[COMCTL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / comctl32 / listview.c
1 /*
2 * ListView tests
3 *
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009-2014 Nikolay Sivov
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
26
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
30
31 static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
32 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
33 static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
34 static BOOL (WINAPI *p_TrackMouseEvent)(TRACKMOUSEEVENT *);
35
36 enum seq_index {
37 PARENT_SEQ_INDEX,
38 PARENT_FULL_SEQ_INDEX,
39 PARENT_CD_SEQ_INDEX,
40 LISTVIEW_SEQ_INDEX,
41 EDITBOX_SEQ_INDEX,
42 COMBINED_SEQ_INDEX,
43 NUM_MSG_SEQUENCES
44 };
45
46 #define LISTVIEW_ID 0
47 #define HEADER_ID 1
48
49 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
50 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
51 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
52
53 static const WCHAR testparentclassW[] =
54 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
55
56 static HWND hwndparent, hwndparentW;
57 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
58 static BOOL blockEdit;
59 /* return nonzero on NM_HOVER */
60 static BOOL g_block_hover;
61 /* notification data for LVN_ITEMCHANGED */
62 static NMLISTVIEW g_nmlistview;
63 /* notification data for LVN_ITEMCHANGING */
64 static NMLISTVIEW g_nmlistview_changing;
65 /* format reported to control:
66 -1 falls to defproc, anything else returned */
67 static INT notifyFormat;
68 /* indicates we're running < 5.80 version */
69 static BOOL g_is_below_5;
70 /* item data passed to LVN_GETDISPINFOA */
71 static LVITEMA g_itema;
72 /* alter notification code A->W */
73 static BOOL g_disp_A_to_W;
74 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
75 static NMLVDISPINFOA g_editbox_disp_info;
76 /* when this is set focus will be tested on LVN_DELETEITEM */
77 static BOOL g_focus_test_LVN_DELETEITEM;
78 /* Whether to send WM_KILLFOCUS to the edit control during LVN_ENDLABELEDIT */
79 static BOOL g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT;
80
81 static HWND subclass_editbox(HWND hwndListview);
82
83 static void init_functions(void)
84 {
85 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
86
87 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
88 X(ImageList_Create);
89 X(ImageList_Destroy);
90 X(ImageList_Add);
91 X(_TrackMouseEvent);
92 #undef X
93 }
94
95 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
96
97 static const struct message create_ownerdrawfixed_parent_seq[] = {
98 { WM_NOTIFYFORMAT, sent },
99 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
100 { WM_MEASUREITEM, sent },
101 { WM_PARENTNOTIFY, sent },
102 { 0 }
103 };
104
105 static const struct message redraw_listview_seq[] = {
106 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
107 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
108 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
109 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
110 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
111 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
112 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
113 { 0 }
114 };
115
116 static const struct message listview_icon_spacing_seq[] = {
117 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
118 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
119 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
120 { 0 }
121 };
122
123 static const struct message listview_color_seq[] = {
124 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
125 { LVM_GETBKCOLOR, sent },
126 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
127 { LVM_GETTEXTCOLOR, sent },
128 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
129 { LVM_GETTEXTBKCOLOR, sent },
130
131 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
132 { LVM_GETBKCOLOR, sent },
133 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
134 { LVM_GETTEXTCOLOR, sent },
135 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
136 { LVM_GETTEXTBKCOLOR, sent },
137
138 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
139 { LVM_GETBKCOLOR, sent },
140 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
141 { LVM_GETTEXTCOLOR, sent },
142 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
143 { LVM_GETTEXTBKCOLOR, sent },
144
145 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
146 { LVM_GETBKCOLOR, sent },
147 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
148 { LVM_GETTEXTCOLOR, sent },
149 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
150 { LVM_GETTEXTBKCOLOR, sent },
151 { 0 }
152 };
153
154 static const struct message listview_item_count_seq[] = {
155 { LVM_GETITEMCOUNT, sent },
156 { LVM_INSERTITEMA, sent },
157 { LVM_INSERTITEMA, sent },
158 { LVM_INSERTITEMA, sent },
159 { LVM_GETITEMCOUNT, sent },
160 { LVM_DELETEITEM, sent|wparam, 2 },
161 { WM_NCPAINT, sent|optional },
162 { WM_ERASEBKGND, sent|optional },
163 { LVM_GETITEMCOUNT, sent },
164 { LVM_DELETEALLITEMS, sent },
165 { LVM_GETITEMCOUNT, sent },
166 { LVM_INSERTITEMA, sent },
167 { LVM_INSERTITEMA, sent },
168 { LVM_GETITEMCOUNT, sent },
169 { LVM_INSERTITEMA, sent },
170 { LVM_GETITEMCOUNT, sent },
171 { 0 }
172 };
173
174 static const struct message listview_itempos_seq[] = {
175 { LVM_INSERTITEMA, sent },
176 { LVM_INSERTITEMA, sent },
177 { LVM_INSERTITEMA, sent },
178 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
179 { WM_NCPAINT, sent|optional },
180 { WM_ERASEBKGND, sent|optional },
181 { LVM_GETITEMPOSITION, sent|wparam, 1 },
182 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
183 { LVM_GETITEMPOSITION, sent|wparam, 2 },
184 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
185 { LVM_GETITEMPOSITION, sent|wparam, 0 },
186 { 0 }
187 };
188
189 static const struct message listview_ownerdata_switchto_seq[] = {
190 { WM_STYLECHANGING, sent },
191 { WM_STYLECHANGED, sent },
192 { 0 }
193 };
194
195 static const struct message listview_getorderarray_seq[] = {
196 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
197 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
198 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
199 { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
200 { 0 }
201 };
202
203 static const struct message listview_setorderarray_seq[] = {
204 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
205 { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
206 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
207 { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
208 { 0 }
209 };
210
211 static const struct message empty_seq[] = {
212 { 0 }
213 };
214
215 static const struct message parent_focus_change_ownerdata_seq[] = {
216 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
217 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
218 { 0 }
219 };
220
221 static const struct message forward_erasebkgnd_parent_seq[] = {
222 { WM_ERASEBKGND, sent },
223 { 0 }
224 };
225
226 static const struct message ownerdata_select_focus_parent_seq[] = {
227 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
228 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
229 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
230 { 0 }
231 };
232
233 static const struct message ownerdata_setstate_all_parent_seq[] = {
234 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
235 { 0 }
236 };
237
238 static const struct message ownerdata_defocus_all_parent_seq[] = {
239 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
240 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
241 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
242 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
243 { 0 }
244 };
245
246 static const struct message ownerdata_deselect_all_parent_seq[] = {
247 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
248 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
249 { 0 }
250 };
251
252 static const struct message change_all_parent_seq[] = {
253 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
254 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
255
256 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
257 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
258
259 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
260 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
261
262 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
263 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
264
265 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
266 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
267 { 0 }
268 };
269
270 static const struct message changing_all_parent_seq[] = {
271 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
272 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
273 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
274 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
275 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
276 { 0 }
277 };
278
279 static const struct message textcallback_set_again_parent_seq[] = {
280 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
281 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
282 { 0 }
283 };
284
285 static const struct message single_getdispinfo_parent_seq[] = {
286 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
287 { 0 }
288 };
289
290 static const struct message getitemposition_seq1[] = {
291 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
292 { 0 }
293 };
294
295 static const struct message getitemposition_seq2[] = {
296 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
297 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
298 { 0 }
299 };
300
301 static const struct message getsubitemrect_seq[] = {
302 { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
303 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
304 { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
305 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
306 { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
307 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
308 { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
309 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
310 { 0 }
311 };
312
313 static const struct message editbox_create_pos[] = {
314 /* sequence sent after LVN_BEGINLABELEDIT */
315 /* next two are 4.7x specific */
316 { WM_WINDOWPOSCHANGING, sent },
317 { WM_WINDOWPOSCHANGED, sent|optional },
318
319 { WM_WINDOWPOSCHANGING, sent|optional },
320 { WM_NCCALCSIZE, sent },
321 { WM_WINDOWPOSCHANGED, sent },
322 { WM_MOVE, sent|defwinproc },
323 { WM_SIZE, sent|defwinproc },
324 /* the rest is todo, skipped in 4.7x */
325 { WM_WINDOWPOSCHANGING, sent|optional },
326 { WM_WINDOWPOSCHANGED, sent|optional },
327 { 0 }
328 };
329
330 static const struct message scroll_parent_seq[] = {
331 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
332 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
333 { 0 }
334 };
335
336 static const struct message setredraw_seq[] = {
337 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
338 { 0 }
339 };
340
341 static const struct message lvs_ex_transparentbkgnd_seq[] = {
342 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
343 { 0 }
344 };
345
346 static const struct message edit_end_nochange[] = {
347 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
348 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
349 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
350 { 0 }
351 };
352
353 static const struct message hover_parent[] = {
354 { WM_GETDLGCODE, sent }, /* todo_wine */
355 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
356 { 0 }
357 };
358
359 static const struct message listview_destroy[] = {
360 { 0x0090, sent|optional }, /* Vista */
361 { WM_PARENTNOTIFY, sent },
362 { WM_SHOWWINDOW, sent },
363 { WM_WINDOWPOSCHANGING, sent },
364 { WM_WINDOWPOSCHANGED, sent|optional },
365 { WM_DESTROY, sent },
366 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
367 { WM_NCDESTROY, sent },
368 { 0 }
369 };
370
371 static const struct message listview_ownerdata_destroy[] = {
372 { 0x0090, sent|optional }, /* Vista */
373 { WM_PARENTNOTIFY, sent },
374 { WM_SHOWWINDOW, sent },
375 { WM_WINDOWPOSCHANGING, sent },
376 { WM_WINDOWPOSCHANGED, sent|optional },
377 { WM_DESTROY, sent },
378 { WM_NCDESTROY, sent },
379 { 0 }
380 };
381
382 static const struct message listview_ownerdata_deleteall[] = {
383 { LVM_DELETEALLITEMS, sent },
384 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
385 { 0 }
386 };
387
388 static const struct message listview_header_changed_seq[] = {
389 { LVM_SETCOLUMNA, sent },
390 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
391 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
392 { 0 }
393 };
394
395 static const struct message parent_header_click_seq[] = {
396 { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
397 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
398 { 0 }
399 };
400
401 static const struct message parent_header_divider_dclick_seq[] = {
402 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
403 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
404 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
405 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
406 { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
407 { 0 }
408 };
409
410 static const struct message listview_set_imagelist[] = {
411 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
412 { 0 }
413 };
414
415 static const struct message listview_header_set_imagelist[] = {
416 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
417 { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
418 { 0 }
419 };
420
421 static const struct message parent_insert_focused_seq[] = {
422 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
423 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
424 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
425 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
426 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
427 { 0 }
428 };
429
430 static const struct message parent_report_cd_seq[] = {
431 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
432 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
433 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
434 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
435 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
436 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
437 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
438 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
439 { 0 }
440 };
441
442 static const struct message parent_list_cd_seq[] = {
443 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
444 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
445 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
446 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
447 { 0 }
448 };
449
450 static const struct message listview_end_label_edit[] = {
451 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
452 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING},
453 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
454 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
455 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
456 { 0 }
457 };
458
459 static const struct message listview_end_label_edit_kill_focus[] = {
460 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
461 { WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
462 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
463 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
464 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
465 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
466 { 0 }
467 };
468
469 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
470 {
471 static LONG defwndproc_counter = 0;
472 LRESULT ret;
473 struct message msg;
474
475 msg.message = message;
476 msg.flags = sent|wparam|lparam;
477 if (defwndproc_counter) msg.flags |= defwinproc;
478 msg.wParam = wParam;
479 msg.lParam = lParam;
480 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
481 if (message == WM_COMMAND) msg.id = HIWORD(wParam);
482
483 /* log system messages, except for painting */
484 if (message < WM_USER &&
485 message != WM_PAINT &&
486 message != WM_ERASEBKGND &&
487 message != WM_NCPAINT &&
488 message != WM_NCHITTEST &&
489 message != WM_GETTEXT &&
490 message != WM_GETICON &&
491 message != WM_DEVICECHANGE)
492 {
493 add_message(sequences, PARENT_SEQ_INDEX, &msg);
494 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
495 }
496 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
497
498 switch (message)
499 {
500 case WM_NOTIFY:
501 {
502 switch (((NMHDR*)lParam)->code)
503 {
504 case LVN_BEGINLABELEDITA:
505 {
506 HWND edit = NULL;
507
508 /* subclass edit box */
509 if (!blockEdit)
510 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
511
512 if (edit)
513 {
514 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
515 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
516 "text limit %d, expected 259\n", len);
517 }
518
519 return blockEdit;
520 }
521 case LVN_ENDLABELEDITA:
522 {
523 HWND edit;
524
525 /* always accept new item text */
526 NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
527 g_editbox_disp_info = *di;
528
529 /* edit control still available from this notification */
530 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
531 ok(IsWindow(edit), "expected valid edit control handle\n");
532 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
533
534 if (g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT)
535 SendMessageA(edit, WM_KILLFOCUS, 0, 0);
536
537 return TRUE;
538 }
539 case LVN_ITEMCHANGING:
540 {
541 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
542 g_nmlistview_changing = *nmlv;
543 }
544 break;
545 case LVN_ITEMCHANGED:
546 {
547 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
548 g_nmlistview = *nmlv;
549 }
550 break;
551 case LVN_GETDISPINFOA:
552 {
553 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
554 g_itema = dispinfo->item;
555
556 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
557 {
558 static const WCHAR testW[] = {'T','E','S','T',0};
559 dispinfo->hdr.code = LVN_GETDISPINFOW;
560 memcpy(dispinfo->item.pszText, testW, sizeof(testW));
561 }
562
563 /* test control buffer size for text, 10 used to mask cases when control
564 is using caller buffer to process LVM_GETITEM for example */
565 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
566 ok(dispinfo->item.cchTextMax == 260 ||
567 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
568 "buffer size %d\n", dispinfo->item.cchTextMax);
569 }
570 break;
571 case LVN_DELETEITEM:
572 if (g_focus_test_LVN_DELETEITEM)
573 {
574 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
575 UINT state;
576
577 state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
578 ok(state == 0, "got state %x\n", state);
579 }
580 break;
581 case NM_HOVER:
582 if (g_block_hover) return 1;
583 break;
584 }
585 break;
586 }
587 case WM_NOTIFYFORMAT:
588 {
589 /* force to return format */
590 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
591 break;
592 }
593 }
594
595 defwndproc_counter++;
596 if (IsWindowUnicode(hwnd))
597 ret = DefWindowProcW(hwnd, message, wParam, lParam);
598 else
599 ret = DefWindowProcA(hwnd, message, wParam, lParam);
600 defwndproc_counter--;
601
602 return ret;
603 }
604
605 static BOOL register_parent_wnd_class(BOOL Unicode)
606 {
607 WNDCLASSA clsA;
608 WNDCLASSW clsW;
609
610 if (Unicode)
611 {
612 clsW.style = 0;
613 clsW.lpfnWndProc = parent_wnd_proc;
614 clsW.cbClsExtra = 0;
615 clsW.cbWndExtra = 0;
616 clsW.hInstance = GetModuleHandleW(NULL);
617 clsW.hIcon = 0;
618 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
619 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
620 clsW.lpszMenuName = NULL;
621 clsW.lpszClassName = testparentclassW;
622 }
623 else
624 {
625 clsA.style = 0;
626 clsA.lpfnWndProc = parent_wnd_proc;
627 clsA.cbClsExtra = 0;
628 clsA.cbWndExtra = 0;
629 clsA.hInstance = GetModuleHandleA(NULL);
630 clsA.hIcon = 0;
631 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
632 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
633 clsA.lpszMenuName = NULL;
634 clsA.lpszClassName = "Listview test parent class";
635 }
636
637 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
638 }
639
640 static HWND create_parent_window(BOOL Unicode)
641 {
642 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
643 HWND hwnd;
644
645 if (!register_parent_wnd_class(Unicode))
646 return NULL;
647
648 blockEdit = FALSE;
649 notifyFormat = -1;
650
651 if (Unicode)
652 hwnd = CreateWindowExW(0, testparentclassW, nameW,
653 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
654 WS_MAXIMIZEBOX | WS_VISIBLE,
655 0, 0, 100, 100,
656 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
657 else
658 hwnd = CreateWindowExA(0, "Listview test parent class",
659 "Listview test parent window",
660 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
661 WS_MAXIMIZEBOX | WS_VISIBLE,
662 0, 0, 100, 100,
663 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
664 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
665 return hwnd;
666 }
667
668 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
669 {
670 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
671 static LONG defwndproc_counter = 0;
672 LRESULT ret;
673 struct message msg;
674
675 msg.message = message;
676 msg.flags = sent|wparam|lparam;
677 if (defwndproc_counter) msg.flags |= defwinproc;
678 msg.wParam = wParam;
679 msg.lParam = lParam;
680 msg.id = LISTVIEW_ID;
681 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
682 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
683
684 defwndproc_counter++;
685 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
686 defwndproc_counter--;
687 return ret;
688 }
689
690 static HWND create_listview_control(DWORD style)
691 {
692 WNDPROC oldproc;
693 HWND hwnd;
694 RECT rect;
695
696 GetClientRect(hwndparent, &rect);
697 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
698 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
699 0, 0, rect.right, rect.bottom,
700 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
701 ok(hwnd != NULL, "gle=%d\n", GetLastError());
702
703 if (!hwnd) return NULL;
704
705 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
706 (LONG_PTR)listview_subclass_proc);
707 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
708
709 return hwnd;
710 }
711
712 /* unicode listview window with specified parent */
713 static HWND create_listview_controlW(DWORD style, HWND parent)
714 {
715 WNDPROC oldproc;
716 HWND hwnd;
717 RECT rect;
718 static const WCHAR nameW[] = {'f','o','o',0};
719
720 GetClientRect(parent, &rect);
721 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
722 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
723 0, 0, rect.right, rect.bottom,
724 parent, NULL, GetModuleHandleW(NULL), NULL);
725 ok(hwnd != NULL, "gle=%d\n", GetLastError());
726
727 if (!hwnd) return NULL;
728
729 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
730 (LONG_PTR)listview_subclass_proc);
731 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
732
733 return hwnd;
734 }
735
736 static BOOL is_win_xp(void)
737 {
738 HWND hwnd, header;
739 BOOL ret;
740
741 hwnd = create_listview_control(LVS_ICON);
742 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, LVS_EX_HEADERINALLVIEWS);
743 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
744 ret = !IsWindow(header);
745
746 DestroyWindow(hwnd);
747
748 return ret;
749 }
750
751 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
752 {
753 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
754 static LONG defwndproc_counter = 0;
755 struct message msg = { 0 };
756 LRESULT ret;
757
758 msg.message = message;
759 msg.flags = sent|wparam|lparam;
760 if (defwndproc_counter) msg.flags |= defwinproc;
761 msg.wParam = wParam;
762 msg.lParam = lParam;
763 msg.id = HEADER_ID;
764 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
765
766 defwndproc_counter++;
767 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
768 defwndproc_counter--;
769 return ret;
770 }
771
772 static HWND subclass_header(HWND hwndListview)
773 {
774 WNDPROC oldproc;
775 HWND hwnd;
776
777 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
778 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
779 (LONG_PTR)header_subclass_proc);
780 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
781
782 return hwnd;
783 }
784
785 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
786 {
787 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
788 static LONG defwndproc_counter = 0;
789 struct message msg = { 0 };
790 LRESULT ret;
791
792 msg.message = message;
793 msg.flags = sent|wparam|lparam;
794 if (defwndproc_counter) msg.flags |= defwinproc;
795 msg.wParam = wParam;
796 msg.lParam = lParam;
797
798 /* all we need is sizing */
799 if (message == WM_WINDOWPOSCHANGING ||
800 message == WM_NCCALCSIZE ||
801 message == WM_WINDOWPOSCHANGED ||
802 message == WM_MOVE ||
803 message == WM_SIZE)
804 {
805 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
806 }
807
808 defwndproc_counter++;
809 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
810 defwndproc_counter--;
811 return ret;
812 }
813
814 static HWND subclass_editbox(HWND hwndListview)
815 {
816 WNDPROC oldproc;
817 HWND hwnd;
818
819 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
820 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
821 (LONG_PTR)editbox_subclass_proc);
822 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
823
824 return hwnd;
825 }
826
827 /* Performs a single LVM_HITTEST test */
828 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
829 BOOL todo_item, BOOL todo_flags, int line)
830 {
831 LVHITTESTINFO lpht;
832 INT ret;
833
834 lpht.pt.x = x;
835 lpht.pt.y = y;
836 lpht.iSubItem = 10;
837
838 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
839
840 todo_wine_if(todo_item)
841 {
842 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
843 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
844 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
845 }
846
847 if (todo_flags)
848 {
849 todo_wine
850 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
851 }
852 else if (broken_flags)
853 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
854 "Expected flags %x, got %x\n", flags, lpht.flags);
855 else
856 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
857 }
858
859 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
860
861 /* Performs a single LVM_SUBITEMHITTEST test */
862 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
863 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
864 {
865 LVHITTESTINFO lpht;
866 INT ret;
867
868 lpht.pt.x = x;
869 lpht.pt.y = y;
870
871 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
872
873 todo_wine_if(todo_item)
874 {
875 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
876 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
877 }
878
879 todo_wine_if(todo_subitem)
880 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
881
882 todo_wine_if(todo_flags)
883 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
884 }
885
886 #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__)
887
888 static void test_images(void)
889 {
890 HWND hwnd;
891 INT r;
892 LVITEMA item;
893 HIMAGELIST himl;
894 HBITMAP hbmp;
895 RECT r1, r2;
896 static CHAR hello[] = "hello";
897
898 himl = pImageList_Create(40, 40, 0, 4, 4);
899 ok(himl != NULL, "failed to create imagelist\n");
900
901 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
902 ok(hbmp != NULL, "failed to create bitmap\n");
903
904 r = pImageList_Add(himl, hbmp, 0);
905 ok(r == 0, "should be zero\n");
906
907 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_OWNERDRAWFIXED,
908 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
909 ok(hwnd != NULL, "failed to create listview window\n");
910
911 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
912 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
913
914 ok(r == 0, "should return zero\n");
915
916 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
917 ok(r == 0, "should return zero\n");
918
919 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
920 ok(r != 0, "got 0\n");
921
922 /* returns dimensions */
923
924 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
925 ok(r == 0, "should be zero items\n");
926
927 item.mask = LVIF_IMAGE | LVIF_TEXT;
928 item.iItem = 0;
929 item.iSubItem = 1;
930 item.iImage = 0;
931 item.pszText = 0;
932 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
933 ok(r == -1, "should fail\n");
934
935 item.iSubItem = 0;
936 item.pszText = hello;
937 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
938 ok(r == 0, "should not fail\n");
939
940 SetRect(&r1, LVIR_ICON, 0, 0, 0);
941 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
942 expect(1, r);
943
944 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
945 ok(r == TRUE, "should not fail\n");
946
947 item.iSubItem = 0;
948 item.pszText = hello;
949 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
950 ok(r == 0, "should not fail\n");
951
952 SetRect(&r2, LVIR_ICON, 0, 0, 0);
953 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
954 expect(1, r);
955
956 ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
957
958 DestroyWindow(hwnd);
959 }
960
961 static void test_checkboxes(void)
962 {
963 HWND hwnd;
964 LVITEMA item;
965 DWORD r;
966 static CHAR text[] = "Text",
967 text2[] = "Text2",
968 text3[] = "Text3";
969
970 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
971 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
972 ok(hwnd != NULL, "failed to create listview window\n");
973
974 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
975 item.mask = LVIF_TEXT | LVIF_STATE;
976 item.stateMask = 0xffff;
977 item.state = 0xfccc;
978 item.iItem = 0;
979 item.iSubItem = 0;
980 item.pszText = text;
981 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
982 expect(0, r);
983
984 item.iItem = 0;
985 item.mask = LVIF_STATE;
986 item.stateMask = 0xffff;
987 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
988 expect(1, r);
989 ok(item.state == 0xfccc, "state %x\n", item.state);
990
991 /* Don't set LVIF_STATE */
992 item.mask = LVIF_TEXT;
993 item.stateMask = 0xffff;
994 item.state = 0xfccc;
995 item.iItem = 1;
996 item.iSubItem = 0;
997 item.pszText = text;
998 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
999 expect(1, r);
1000
1001 item.iItem = 1;
1002 item.mask = LVIF_STATE;
1003 item.stateMask = 0xffff;
1004 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1005 expect(1, r);
1006 ok(item.state == 0, "state %x\n", item.state);
1007
1008 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1009 expect(0, r);
1010
1011 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
1012 item.iItem = 0;
1013 item.mask = LVIF_STATE;
1014 item.stateMask = 0xffff;
1015 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1016 expect(1, r);
1017 if (item.state != 0x1ccc)
1018 {
1019 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
1020 DestroyWindow(hwnd);
1021 return;
1022 }
1023
1024 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1025 item.iItem = 2;
1026 item.mask = LVIF_TEXT;
1027 item.state = 0;
1028 item.pszText = text2;
1029 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1030 expect(2, r);
1031
1032 item.iItem = 2;
1033 item.mask = LVIF_STATE;
1034 item.stateMask = 0xffff;
1035 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1036 expect(1, r);
1037 ok(item.state == 0x1000, "state %x\n", item.state);
1038
1039 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1040 item.iItem = 3;
1041 item.mask = LVIF_TEXT | LVIF_STATE;
1042 item.stateMask = 0xffff;
1043 item.state = 0x2aaa;
1044 item.pszText = text3;
1045 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1046 expect(3, r);
1047
1048 item.iItem = 3;
1049 item.mask = LVIF_STATE;
1050 item.stateMask = 0xffff;
1051 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1052 expect(1, r);
1053 ok(item.state == 0x1aaa, "state %x\n", item.state);
1054
1055 /* Set an item's state to checked */
1056 item.iItem = 3;
1057 item.mask = LVIF_STATE;
1058 item.stateMask = 0xf000;
1059 item.state = 0x2000;
1060 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1061 expect(1, r);
1062
1063 item.iItem = 3;
1064 item.mask = LVIF_STATE;
1065 item.stateMask = 0xffff;
1066 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1067 expect(1, r);
1068 ok(item.state == 0x2aaa, "state %x\n", item.state);
1069
1070 /* Check that only the bits we asked for are returned,
1071 * and that all the others are set to zero
1072 */
1073 item.iItem = 3;
1074 item.mask = LVIF_STATE;
1075 item.stateMask = 0xf000;
1076 item.state = 0xffff;
1077 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1078 expect(1, r);
1079 ok(item.state == 0x2000, "state %x\n", item.state);
1080
1081 /* Set the style again and check that doesn't change an item's state */
1082 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1083 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1084
1085 item.iItem = 3;
1086 item.mask = LVIF_STATE;
1087 item.stateMask = 0xffff;
1088 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1089 expect(1, r);
1090 ok(item.state == 0x2aaa, "state %x\n", item.state);
1091
1092 /* Unsetting the checkbox extended style doesn't change an item's state */
1093 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1094 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1095
1096 item.iItem = 3;
1097 item.mask = LVIF_STATE;
1098 item.stateMask = 0xffff;
1099 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1100 expect(1, r);
1101 ok(item.state == 0x2aaa, "state %x\n", item.state);
1102
1103 /* Now setting the style again will change an item's state */
1104 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1105 expect(0, r);
1106
1107 item.iItem = 3;
1108 item.mask = LVIF_STATE;
1109 item.stateMask = 0xffff;
1110 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1111 expect(1, r);
1112 ok(item.state == 0x1aaa, "state %x\n", item.state);
1113
1114 /* Toggle checkbox tests (bug 9934) */
1115 memset (&item, 0xcc, sizeof(item));
1116 item.mask = LVIF_STATE;
1117 item.iItem = 3;
1118 item.iSubItem = 0;
1119 item.state = LVIS_FOCUSED;
1120 item.stateMask = LVIS_FOCUSED;
1121 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1122 expect(1, r);
1123
1124 item.iItem = 3;
1125 item.mask = LVIF_STATE;
1126 item.stateMask = 0xffff;
1127 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1128 expect(1, r);
1129 ok(item.state == 0x1aab, "state %x\n", item.state);
1130
1131 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1132 expect(0, r);
1133 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1134 expect(0, r);
1135
1136 item.iItem = 3;
1137 item.mask = LVIF_STATE;
1138 item.stateMask = 0xffff;
1139 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1140 expect(1, r);
1141 ok(item.state == 0x2aab, "state %x\n", item.state);
1142
1143 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1144 expect(0, r);
1145 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1146 expect(0, r);
1147
1148 item.iItem = 3;
1149 item.mask = LVIF_STATE;
1150 item.stateMask = 0xffff;
1151 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1152 expect(1, r);
1153 ok(item.state == 0x1aab, "state %x\n", item.state);
1154
1155 DestroyWindow(hwnd);
1156 }
1157
1158 static void insert_column(HWND hwnd, int idx)
1159 {
1160 LVCOLUMNA column;
1161 INT rc;
1162
1163 memset(&column, 0xcc, sizeof(column));
1164 column.mask = LVCF_SUBITEM;
1165 column.iSubItem = idx;
1166
1167 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1168 expect(idx, rc);
1169 }
1170
1171 static void insert_item(HWND hwnd, int idx)
1172 {
1173 static CHAR text[] = "foo";
1174
1175 LVITEMA item;
1176 INT rc;
1177
1178 memset(&item, 0xcc, sizeof (item));
1179 item.mask = LVIF_TEXT;
1180 item.iItem = idx;
1181 item.iSubItem = 0;
1182 item.pszText = text;
1183
1184 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1185 expect(idx, rc);
1186 }
1187
1188 static void test_items(void)
1189 {
1190 const LPARAM lparamTest = 0x42;
1191 static CHAR text[] = "Text";
1192 char buffA[5];
1193 HWND hwnd;
1194 LVITEMA item;
1195 DWORD r;
1196
1197 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1198 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1199 ok(hwnd != NULL, "failed to create listview window\n");
1200
1201 /*
1202 * Test setting/getting item params
1203 */
1204
1205 /* Set up two columns */
1206 insert_column(hwnd, 0);
1207 insert_column(hwnd, 1);
1208
1209 /* LVIS_SELECTED with zero stateMask */
1210 /* set */
1211 memset (&item, 0, sizeof (item));
1212 item.mask = LVIF_STATE;
1213 item.state = LVIS_SELECTED;
1214 item.stateMask = 0;
1215 item.iItem = 0;
1216 item.iSubItem = 0;
1217 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1218 expect(0, r);
1219 /* get */
1220 memset (&item, 0xcc, sizeof (item));
1221 item.mask = LVIF_STATE;
1222 item.stateMask = LVIS_SELECTED;
1223 item.state = 0;
1224 item.iItem = 0;
1225 item.iSubItem = 0;
1226 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1227 expect(1, r);
1228 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1229 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1230 ok(r, "got %d\n", r);
1231
1232 /* LVIS_SELECTED with zero stateMask */
1233 /* set */
1234 memset (&item, 0, sizeof (item));
1235 item.mask = LVIF_STATE;
1236 item.state = LVIS_FOCUSED;
1237 item.stateMask = 0;
1238 item.iItem = 0;
1239 item.iSubItem = 0;
1240 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1241 expect(0, r);
1242 /* get */
1243 memset (&item, 0xcc, sizeof (item));
1244 item.mask = LVIF_STATE;
1245 item.stateMask = LVIS_FOCUSED;
1246 item.state = 0;
1247 item.iItem = 0;
1248 item.iSubItem = 0;
1249 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1250 expect(1, r);
1251 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1252 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1253 ok(r, "got %d\n", r);
1254
1255 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1256 /* set */
1257 memset (&item, 0, sizeof (item));
1258 item.mask = LVIF_STATE;
1259 item.state = LVIS_CUT;
1260 item.stateMask = LVIS_FOCUSED;
1261 item.iItem = 0;
1262 item.iSubItem = 0;
1263 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1264 expect(0, r);
1265 /* get */
1266 memset (&item, 0xcc, sizeof (item));
1267 item.mask = LVIF_STATE;
1268 item.stateMask = LVIS_CUT;
1269 item.state = 0;
1270 item.iItem = 0;
1271 item.iSubItem = 0;
1272 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1273 expect(1, r);
1274 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1275 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1276 ok(r, "got %d\n", r);
1277
1278 /* Insert an item with just a param */
1279 memset (&item, 0xcc, sizeof (item));
1280 item.mask = LVIF_PARAM;
1281 item.iItem = 0;
1282 item.iSubItem = 0;
1283 item.lParam = lparamTest;
1284 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1285 expect(0, r);
1286
1287 /* Test getting of the param */
1288 memset (&item, 0xcc, sizeof (item));
1289 item.mask = LVIF_PARAM;
1290 item.iItem = 0;
1291 item.iSubItem = 0;
1292 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1293 expect(1, r);
1294 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1295
1296 /* Set up a subitem */
1297 memset (&item, 0xcc, sizeof (item));
1298 item.mask = LVIF_TEXT;
1299 item.iItem = 0;
1300 item.iSubItem = 1;
1301 item.pszText = text;
1302 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1303 expect(1, r);
1304
1305 item.mask = LVIF_TEXT;
1306 item.iItem = 0;
1307 item.iSubItem = 1;
1308 item.pszText = buffA;
1309 item.cchTextMax = sizeof(buffA);
1310 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1311 expect(1, r);
1312 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1313
1314 /* set up with extra flag */
1315 /* 1. reset subitem text */
1316 item.mask = LVIF_TEXT;
1317 item.iItem = 0;
1318 item.iSubItem = 1;
1319 item.pszText = NULL;
1320 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1321 expect(1, r);
1322
1323 item.mask = LVIF_TEXT;
1324 item.iItem = 0;
1325 item.iSubItem = 1;
1326 item.pszText = buffA;
1327 buffA[0] = 'a';
1328 item.cchTextMax = sizeof(buffA);
1329 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1330 expect(1, r);
1331 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1332
1333 /* 2. set new text with extra flag specified */
1334 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1335 item.iItem = 0;
1336 item.iSubItem = 1;
1337 item.pszText = text;
1338 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1339 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1340
1341 if (r == 1)
1342 {
1343 item.mask = LVIF_TEXT;
1344 item.iItem = 0;
1345 item.iSubItem = 1;
1346 item.pszText = buffA;
1347 buffA[0] = 'a';
1348 item.cchTextMax = sizeof(buffA);
1349 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1350 expect(1, r);
1351 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1352 }
1353
1354 /* Query param from subitem: returns main item param */
1355 memset (&item, 0xcc, sizeof (item));
1356 item.mask = LVIF_PARAM;
1357 item.iItem = 0;
1358 item.iSubItem = 1;
1359 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1360 expect(1, r);
1361 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1362
1363 /* Set up param on first subitem: no effect */
1364 memset (&item, 0xcc, sizeof (item));
1365 item.mask = LVIF_PARAM;
1366 item.iItem = 0;
1367 item.iSubItem = 1;
1368 item.lParam = lparamTest+1;
1369 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1370 expect(0, r);
1371
1372 /* Query param from subitem again: should still return main item param */
1373 memset (&item, 0xcc, sizeof (item));
1374 item.mask = LVIF_PARAM;
1375 item.iItem = 0;
1376 item.iSubItem = 1;
1377 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1378 expect(1, r);
1379 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1380
1381 /**** Some tests of state highlighting ****/
1382 memset (&item, 0xcc, sizeof (item));
1383 item.mask = LVIF_STATE;
1384 item.iItem = 0;
1385 item.iSubItem = 0;
1386 item.state = LVIS_SELECTED;
1387 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1388 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1389 expect(1, r);
1390 item.iSubItem = 1;
1391 item.state = LVIS_DROPHILITED;
1392 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1393 expect(1, r);
1394
1395 memset (&item, 0xcc, sizeof (item));
1396 item.mask = LVIF_STATE;
1397 item.iItem = 0;
1398 item.iSubItem = 0;
1399 item.stateMask = -1;
1400 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1401 expect(1, r);
1402 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1403 item.iSubItem = 1;
1404 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1405 expect(1, r);
1406 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1407
1408 /* some notnull but meaningless masks */
1409 memset (&item, 0, sizeof(item));
1410 item.mask = LVIF_NORECOMPUTE;
1411 item.iItem = 0;
1412 item.iSubItem = 0;
1413 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1414 expect(1, r);
1415 memset (&item, 0, sizeof(item));
1416 item.mask = LVIF_DI_SETITEM;
1417 item.iItem = 0;
1418 item.iSubItem = 0;
1419 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1420 expect(1, r);
1421
1422 /* set text to callback value already having it */
1423 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1424 expect(TRUE, r);
1425 memset (&item, 0, sizeof (item));
1426 item.mask = LVIF_TEXT;
1427 item.pszText = LPSTR_TEXTCALLBACKA;
1428 item.iItem = 0;
1429 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1430 expect(0, r);
1431 memset (&item, 0, sizeof (item));
1432
1433 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1434
1435 item.pszText = LPSTR_TEXTCALLBACKA;
1436 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1437 expect(TRUE, r);
1438
1439 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1440 "check callback text comparison rule", FALSE);
1441
1442 DestroyWindow(hwnd);
1443 }
1444
1445 static void test_columns(void)
1446 {
1447 HWND hwnd, header;
1448 LVCOLUMNA column;
1449 LVITEMA item;
1450 INT order[2];
1451 CHAR buff[5];
1452 DWORD rc;
1453
1454 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_LIST,
1455 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1456 ok(hwnd != NULL, "failed to create listview window\n");
1457
1458 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1459 ok(header == NULL, "got %p\n", header);
1460
1461 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1462 ok(rc == 0, "got %d\n", rc);
1463
1464 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1465 ok(header == NULL, "got %p\n", header);
1466
1467 DestroyWindow(hwnd);
1468
1469 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1470 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1471 ok(hwnd != NULL, "failed to create listview window\n");
1472
1473 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1474 ok(!rc, "got %d\n", rc);
1475
1476 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1477 ok(!rc, "got %d\n", rc);
1478
1479 /* Add a column with no mask */
1480 memset(&column, 0xcc, sizeof(column));
1481 column.mask = 0;
1482 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1483 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1484
1485 /* Check its width */
1486 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1487 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1488
1489 DestroyWindow(hwnd);
1490
1491 /* LVM_GETCOLUMNORDERARRAY */
1492 hwnd = create_listview_control(LVS_REPORT);
1493 subclass_header(hwnd);
1494
1495 memset(&column, 0, sizeof(column));
1496 column.mask = LVCF_WIDTH;
1497 column.cx = 100;
1498 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1499 expect(0, rc);
1500
1501 column.cx = 200;
1502 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1503 expect(1, rc);
1504
1505 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1506
1507 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1508 expect(1, rc);
1509 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1510 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1511
1512 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1513 expect(0, rc);
1514
1515 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1516
1517 /* LVM_SETCOLUMNORDERARRAY */
1518 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1519
1520 order[0] = 0;
1521 order[1] = 1;
1522 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1523 expect(1, rc);
1524
1525 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1526 expect(0, rc);
1527
1528 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1529
1530 /* after column added subitem is considered as present */
1531 insert_item(hwnd, 0);
1532
1533 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1534
1535 item.pszText = buff;
1536 item.cchTextMax = sizeof(buff);
1537 item.iItem = 0;
1538 item.iSubItem = 1;
1539 item.mask = LVIF_TEXT;
1540 memset(&g_itema, 0, sizeof(g_itema));
1541 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1542 expect(1, rc);
1543 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1544
1545 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1546 "get subitem text after column added", FALSE);
1547
1548 DestroyWindow(hwnd);
1549 }
1550
1551 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1552 static WNDPROC listviewWndProc;
1553 static HIMAGELIST test_create_imagelist;
1554
1555 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1556 {
1557 LRESULT ret;
1558
1559 if (uMsg == WM_CREATE)
1560 {
1561 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1562 lpcs->style |= LVS_REPORT;
1563 }
1564 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1565 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1566 return ret;
1567 }
1568
1569 /* Header creation is delayed in classic implementation. */
1570 #define TEST_NO_HEADER(a) test_header_presence_(a, FALSE, __LINE__)
1571 #define TEST_HEADER_EXPECTED(a) test_header_presence_(a, TRUE, __LINE__)
1572 #define TEST_NO_HEADER2(a, b) test_header_presence_(a, b, __LINE__)
1573 static void test_header_presence_(HWND hwnd, BOOL present, int line)
1574 {
1575 HWND header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1576
1577 if (present)
1578 {
1579 ok_(__FILE__, line)(IsWindow(header), "Header should have been created.\n");
1580 if (header) /* FIXME: remove when todo's are fixed */
1581 ok_(__FILE__, line)(header == GetDlgItem(hwnd, 0), "Dialog item expected.\n");
1582 }
1583 else
1584 {
1585 ok_(__FILE__, line)(!IsWindow(header), "Header shouldn't be created.\n");
1586 ok_(__FILE__, line)(NULL == GetDlgItem(hwnd, 0), "NULL dialog item expected.\n");
1587 }
1588 }
1589
1590 static void test_create(BOOL is_version_6)
1591 {
1592 static const WCHAR testtextW[] = {'t','e','s','t',' ','t','e','x','t',0};
1593 char buff[16];
1594 HWND hList;
1595 HWND hHeader;
1596 LONG_PTR ret;
1597 LONG r;
1598 LVCOLUMNA col;
1599 RECT rect;
1600 WNDCLASSEXA cls;
1601 DWORD style;
1602 ATOM class;
1603
1604 if (is_win_xp() && is_version_6)
1605 {
1606 win_skip("Skipping some tests on XP.\n");
1607 return;
1608 }
1609
1610 cls.cbSize = sizeof(WNDCLASSEXA);
1611 r = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
1612 ok(r, "Failed to get class info.\n");
1613 listviewWndProc = cls.lpfnWndProc;
1614 cls.lpfnWndProc = create_test_wndproc;
1615 cls.lpszClassName = "MyListView32";
1616 class = RegisterClassExA(&cls);
1617 ok(class, "Failed to register class.\n");
1618
1619 test_create_imagelist = pImageList_Create(16, 16, 0, 5, 10);
1620 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1621 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1622 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1623 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1624 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1625 DestroyWindow(hList);
1626
1627 /* header isn't created on LVS_ICON and LVS_LIST styles */
1628 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1629 TEST_NO_HEADER(hList);
1630
1631 /* insert column */
1632 memset(&col, 0, sizeof(LVCOLUMNA));
1633 col.mask = LVCF_WIDTH;
1634 col.cx = 100;
1635 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1636 expect(0, r);
1637 TEST_HEADER_EXPECTED(hList);
1638 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1639 style = GetWindowLongA(hHeader, GWL_STYLE);
1640 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1641 DestroyWindow(hList);
1642
1643 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1644 GetModuleHandleA(NULL), 0);
1645 TEST_NO_HEADER(hList);
1646 /* insert column */
1647 memset(&col, 0, sizeof(LVCOLUMNA));
1648 col.mask = LVCF_WIDTH;
1649 col.cx = 100;
1650 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1651 expect(0, r);
1652 TEST_HEADER_EXPECTED(hList);
1653 DestroyWindow(hList);
1654
1655 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1656 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1657 GetModuleHandleA(NULL), 0);
1658 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1659 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1660 TEST_HEADER_EXPECTED(hList);
1661 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1662 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1663 TEST_HEADER_EXPECTED(hList);
1664 DestroyWindow(hList);
1665
1666 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1667 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1668 GetModuleHandleA(NULL), 0);
1669 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1670 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1671 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1672 TEST_HEADER_EXPECTED(hList);
1673 ret = SetWindowLongPtrA(hList, GWL_STYLE, (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1674 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1675 TEST_HEADER_EXPECTED(hList);
1676 DestroyWindow(hList);
1677
1678 /* LVS_REPORT without WS_VISIBLE */
1679 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1680 GetModuleHandleA(NULL), 0);
1681 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1682 todo_wine_if(is_version_6)
1683 TEST_NO_HEADER2(hList, is_version_6);
1684
1685 /* insert column */
1686 memset(&col, 0, sizeof(LVCOLUMNA));
1687 col.mask = LVCF_WIDTH;
1688 col.cx = 100;
1689 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1690 expect(0, r);
1691 TEST_HEADER_EXPECTED(hList);
1692 DestroyWindow(hList);
1693
1694 /* LVS_REPORT without WS_VISIBLE, try to show it */
1695 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1696 GetModuleHandleA(NULL), 0);
1697 todo_wine_if(is_version_6)
1698 TEST_NO_HEADER2(hList, is_version_6);
1699
1700 ShowWindow(hList, SW_SHOW);
1701 TEST_HEADER_EXPECTED(hList);
1702 DestroyWindow(hList);
1703
1704 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1705 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1706 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1707 TEST_HEADER_EXPECTED(hList);
1708 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1709 /* HDS_DRAGDROP set by default */
1710 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1711 DestroyWindow(hList);
1712
1713 /* setting LVS_EX_HEADERDRAGDROP creates header */
1714 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1715 GetModuleHandleA(NULL), 0);
1716 todo_wine_if(is_version_6)
1717 TEST_NO_HEADER2(hList, is_version_6);
1718
1719 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1720 TEST_HEADER_EXPECTED(hList);
1721 DestroyWindow(hList);
1722
1723 /* setting LVS_EX_GRIDLINES creates header */
1724 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1725 GetModuleHandleA(NULL), 0);
1726 todo_wine_if(is_version_6)
1727 TEST_NO_HEADER2(hList, is_version_6);
1728
1729 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1730 TEST_HEADER_EXPECTED(hList);
1731 DestroyWindow(hList);
1732
1733 /* setting LVS_EX_FULLROWSELECT creates header */
1734 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1735 GetModuleHandleA(NULL), 0);
1736 todo_wine_if(is_version_6)
1737 TEST_NO_HEADER2(hList, is_version_6);
1738 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1739 TEST_HEADER_EXPECTED(hList);
1740 DestroyWindow(hList);
1741
1742 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1743 hList = create_listview_control(LVS_ICON);
1744 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1745 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1746 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1747 DestroyWindow(hList);
1748
1749 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1750 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1751 GetModuleHandleA(NULL), 0);
1752 todo_wine_if(is_version_6)
1753 TEST_NO_HEADER2(hList, is_version_6);
1754
1755 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1756 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1757 ok(r == 1, "Unexpected ret value %d.\n", r);
1758 /* right value contains garbage, probably because header columns are not set up */
1759 ok(rect.bottom >= 0, "Unexpected rectangle.\n");
1760
1761 todo_wine_if(is_version_6)
1762 TEST_NO_HEADER2(hList, is_version_6);
1763 DestroyWindow(hList);
1764
1765 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1766 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1767 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1768 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1769 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1770 DestroyWindow(hList);
1771
1772 /* Test that window text is preserved. */
1773 hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1774 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1775 ok(hList != NULL, "Failed to create ListView window.\n");
1776 *buff = 0;
1777 GetWindowTextA(hList, buff, sizeof(buff));
1778 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1779 DestroyWindow(hList);
1780
1781 hList = CreateWindowExW(0, WC_LISTVIEWW, testtextW, WS_CHILD | WS_BORDER | WS_VISIBLE,
1782 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1783 ok(hList != NULL, "Failed to create ListView window.\n");
1784 *buff = 0;
1785 GetWindowTextA(hList, buff, sizeof(buff));
1786 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1787 DestroyWindow(hList);
1788
1789 r = UnregisterClassA("MyListView32", NULL);
1790 ok(r, "Failed to unregister test class.\n");
1791 }
1792
1793 static void test_redraw(void)
1794 {
1795 HWND hwnd;
1796 HDC hdc;
1797 BOOL res;
1798 DWORD r;
1799 RECT rect;
1800
1801 hwnd = create_listview_control(LVS_REPORT);
1802 subclass_header(hwnd);
1803
1804 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1805
1806 InvalidateRect(hwnd, NULL, TRUE);
1807 UpdateWindow(hwnd);
1808 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1809
1810 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1811
1812 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1813 /* 1. Without backbuffer */
1814 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1815 expect(TRUE, res);
1816
1817 hdc = GetWindowDC(hwndparent);
1818
1819 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1820 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1821 ok(r == 1, "Expected not zero result\n");
1822 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1823 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1824
1825 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1826 expect(TRUE, res);
1827
1828 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1829 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1830 expect(1, r);
1831 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1832 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1833
1834 /* 2. With backbuffer */
1835 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1836 LVS_EX_DOUBLEBUFFER);
1837 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1838 expect(TRUE, res);
1839
1840 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1841 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1842 expect(1, r);
1843 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1844 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1845
1846 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1847 expect(TRUE, res);
1848
1849 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1850 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1851 todo_wine expect(1, r);
1852 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1853 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1854
1855 ReleaseDC(hwndparent, hdc);
1856
1857 /* test setting the window style to what it already was */
1858 UpdateWindow(hwnd);
1859 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE));
1860 GetUpdateRect(hwnd, &rect, FALSE);
1861 ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
1862 "Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));
1863
1864 DestroyWindow(hwnd);
1865 }
1866
1867 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1868 {
1869 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1870
1871 if(message == WM_NOTIFY) {
1872 NMHDR *nmhdr = (NMHDR*)lParam;
1873 if(nmhdr->code == NM_CUSTOMDRAW) {
1874 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1875 struct message msg;
1876
1877 msg.message = message;
1878 msg.flags = sent|wparam|lparam|custdraw;
1879 msg.wParam = wParam;
1880 msg.lParam = lParam;
1881 msg.id = nmhdr->code;
1882 msg.stage = nmlvcd->nmcd.dwDrawStage;
1883 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1884
1885 switch(nmlvcd->nmcd.dwDrawStage) {
1886 case CDDS_PREPAINT:
1887 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1888 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1889 case CDDS_ITEMPREPAINT:
1890 nmlvcd->clrTextBk = CLR_DEFAULT;
1891 nmlvcd->clrText = RGB(0, 255, 0);
1892 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1893 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1894 clr = GetBkColor(nmlvcd->nmcd.hdc);
1895 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1896 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1897 if (!(GetWindowLongW(nmhdr->hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS))
1898 {
1899 todo_wine_if(nmlvcd->iSubItem)
1900 ok(clr == c0ffee, "clr=%.8x\n", clr);
1901 }
1902 return CDRF_NOTIFYPOSTPAINT;
1903 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1904 clr = GetBkColor(nmlvcd->nmcd.hdc);
1905 if (!(GetWindowLongW(nmhdr->hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS))
1906 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1907 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1908 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1909 return CDRF_DODEFAULT;
1910 }
1911 return CDRF_DODEFAULT;
1912 }
1913 }
1914
1915 return DefWindowProcA(hwnd, message, wParam, lParam);
1916 }
1917
1918 static void test_customdraw(void)
1919 {
1920 HWND hwnd;
1921 WNDPROC oldwndproc;
1922 LVITEMA item;
1923
1924 hwnd = create_listview_control(LVS_REPORT);
1925
1926 insert_column(hwnd, 0);
1927 insert_column(hwnd, 1);
1928 insert_item(hwnd, 0);
1929
1930 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1931 (LONG_PTR)cd_wndproc);
1932
1933 InvalidateRect(hwnd, NULL, TRUE);
1934 UpdateWindow(hwnd);
1935
1936 /* message tests */
1937 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1938 InvalidateRect(hwnd, NULL, TRUE);
1939 UpdateWindow(hwnd);
1940 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1941
1942 /* check colors when item is selected */
1943 SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) | LVS_SHOWSELALWAYS);
1944 item.mask = LVIF_STATE;
1945 item.stateMask = LVIS_SELECTED;
1946 item.state = LVIS_SELECTED;
1947 SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
1948
1949 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1950 InvalidateRect(hwnd, NULL, TRUE);
1951 UpdateWindow(hwnd);
1952 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT, selection", FALSE);
1953
1954 DestroyWindow(hwnd);
1955
1956 hwnd = create_listview_control(LVS_LIST);
1957
1958 insert_column(hwnd, 0);
1959 insert_column(hwnd, 1);
1960 insert_item(hwnd, 0);
1961
1962 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1963 InvalidateRect(hwnd, NULL, TRUE);
1964 UpdateWindow(hwnd);
1965 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1966
1967 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1968 DestroyWindow(hwnd);
1969 }
1970
1971 static void test_icon_spacing(void)
1972 {
1973 /* LVM_SETICONSPACING */
1974 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1975
1976 HWND hwnd;
1977 WORD w, h;
1978 INT r;
1979
1980 hwnd = create_listview_control(LVS_ICON);
1981 ok(hwnd != NULL, "failed to create a listview window\n");
1982
1983 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1984 expect(NFR_ANSI, r);
1985
1986 /* reset the icon spacing to defaults */
1987 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1988
1989 /* now we can request what the defaults are */
1990 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1991 w = LOWORD(r);
1992 h = HIWORD(r);
1993
1994 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1995
1996 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1997 ok(r == MAKELONG(w, h) ||
1998 broken(r == MAKELONG(w, w)), /* win98 */
1999 "Expected %d, got %d\n", MAKELONG(w, h), r);
2000
2001 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
2002 expect(MAKELONG(20,30), r);
2003
2004 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
2005 expect(MAKELONG(25,35), r);
2006
2007 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
2008
2009 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2010 DestroyWindow(hwnd);
2011 }
2012
2013 static void test_color(void)
2014 {
2015 RECT rect;
2016 HWND hwnd;
2017 DWORD r;
2018 int i;
2019
2020 COLORREF color;
2021 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
2022
2023 hwnd = create_listview_control(LVS_REPORT);
2024 ok(hwnd != NULL, "failed to create a listview window\n");
2025
2026 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2027
2028 for (i = 0; i < 4; i++)
2029 {
2030 color = colors[i];
2031
2032 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
2033 expect(TRUE, r);
2034 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
2035 expect(color, r);
2036
2037 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
2038 expect (TRUE, r);
2039 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
2040 expect(color, r);
2041
2042 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
2043 expect(TRUE, r);
2044 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
2045 expect(color, r);
2046 }
2047
2048 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
2049 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2050
2051 /* invalidation test done separately to avoid a message chain mess */
2052 r = ValidateRect(hwnd, NULL);
2053 expect(TRUE, r);
2054 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2055 expect(TRUE, r);
2056
2057 rect.right = rect.bottom = 1;
2058 r = GetUpdateRect(hwnd, &rect, TRUE);
2059 todo_wine expect(FALSE, r);
2060 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2061
2062 r = ValidateRect(hwnd, NULL);
2063 expect(TRUE, r);
2064 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2065 expect(TRUE, r);
2066
2067 rect.right = rect.bottom = 1;
2068 r = GetUpdateRect(hwnd, &rect, TRUE);
2069 todo_wine expect(FALSE, r);
2070 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2071
2072 r = ValidateRect(hwnd, NULL);
2073 expect(TRUE, r);
2074 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2075 expect(TRUE, r);
2076
2077 rect.right = rect.bottom = 1;
2078 r = GetUpdateRect(hwnd, &rect, TRUE);
2079 todo_wine expect(FALSE, r);
2080 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2081
2082 DestroyWindow(hwnd);
2083 }
2084
2085 static void test_item_count(void)
2086 {
2087 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2088
2089 HWND hwnd;
2090 DWORD r;
2091 HDC hdc;
2092 HFONT hOldFont;
2093 TEXTMETRICA tm;
2094 RECT rect;
2095 INT height;
2096
2097 LVITEMA item0;
2098 LVITEMA item1;
2099 LVITEMA item2;
2100 static CHAR item0text[] = "item0";
2101 static CHAR item1text[] = "item1";
2102 static CHAR item2text[] = "item2";
2103
2104 hwnd = create_listview_control(LVS_REPORT);
2105 ok(hwnd != NULL, "failed to create a listview window\n");
2106
2107 /* resize in dpiaware manner to fit all 3 items added */
2108 hdc = GetDC(0);
2109 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2110 GetTextMetricsA(hdc, &tm);
2111 /* 2 extra pixels for bounds and header border */
2112 height = tm.tmHeight + 2;
2113 SelectObject(hdc, hOldFont);
2114 ReleaseDC(0, hdc);
2115
2116 GetWindowRect(hwnd, &rect);
2117 /* 3 items + 1 header + 1 to be sure */
2118 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2119
2120 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2121
2122 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2123 expect(0, r);
2124
2125 /* [item0] */
2126 item0.mask = LVIF_TEXT;
2127 item0.iItem = 0;
2128 item0.iSubItem = 0;
2129 item0.pszText = item0text;
2130 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2131 expect(0, r);
2132
2133 /* [item0, item1] */
2134 item1.mask = LVIF_TEXT;
2135 item1.iItem = 1;
2136 item1.iSubItem = 0;
2137 item1.pszText = item1text;
2138 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2139 expect(1, r);
2140
2141 /* [item0, item1, item2] */
2142 item2.mask = LVIF_TEXT;
2143 item2.iItem = 2;
2144 item2.iSubItem = 0;
2145 item2.pszText = item2text;
2146 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2147 expect(2, r);
2148
2149 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2150 expect(3, r);
2151
2152 /* [item0, item1] */
2153 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2154 expect(TRUE, r);
2155
2156 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2157 expect(2, r);
2158
2159 /* [] */
2160 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2161 expect(TRUE, r);
2162
2163 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2164 expect(0, r);
2165
2166 /* [item0] */
2167 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2168 expect(0, r);
2169
2170 /* [item0, item1] */
2171 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2172 expect(1, r);
2173
2174 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2175 expect(2, r);
2176
2177 /* [item0, item1, item2] */
2178 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2179 expect(2, r);
2180
2181 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2182 expect(3, r);
2183
2184 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2185
2186 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2187 DestroyWindow(hwnd);
2188 }
2189
2190 static void test_item_position(void)
2191 {
2192 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2193
2194 HWND hwnd;
2195 DWORD r;
2196 POINT position;
2197
2198 LVITEMA item0;
2199 LVITEMA item1;
2200 LVITEMA item2;
2201 static CHAR item0text[] = "item0";
2202 static CHAR item1text[] = "item1";
2203 static CHAR item2text[] = "item2";
2204
2205 hwnd = create_listview_control(LVS_ICON);
2206 ok(hwnd != NULL, "failed to create a listview window\n");
2207
2208 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2209
2210 /* [item0] */
2211 item0.mask = LVIF_TEXT;
2212 item0.iItem = 0;
2213 item0.iSubItem = 0;
2214 item0.pszText = item0text;
2215 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2216 expect(0, r);
2217
2218 /* [item0, item1] */
2219 item1.mask = LVIF_TEXT;
2220 item1.iItem = 1;
2221 item1.iSubItem = 0;
2222 item1.pszText = item1text;
2223 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2224 expect(1, r);
2225
2226 /* [item0, item1, item2] */
2227 item2.mask = LVIF_TEXT;
2228 item2.iItem = 2;
2229 item2.iSubItem = 0;
2230 item2.pszText = item2text;
2231 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2232 expect(2, r);
2233
2234 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2235 expect(TRUE, r);
2236 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2237 expect(TRUE, r);
2238 expect2(10, 5, position.x, position.y);
2239
2240 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2241 expect(TRUE, r);
2242 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2243 expect(TRUE, r);
2244 expect2(0, 0, position.x, position.y);
2245
2246 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2247 expect(TRUE, r);
2248 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2249 expect(TRUE, r);
2250 expect2(20, 20, position.x, position.y);
2251
2252 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2253
2254 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2255 DestroyWindow(hwnd);
2256 }
2257
2258 static void test_getorigin(void)
2259 {
2260 /* LVM_GETORIGIN */
2261
2262 HWND hwnd;
2263 DWORD r;
2264 POINT position;
2265
2266 position.x = position.y = 0;
2267
2268 hwnd = create_listview_control(LVS_ICON);
2269 ok(hwnd != NULL, "failed to create a listview window\n");
2270 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2271
2272 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2273 expect(TRUE, r);
2274 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2275 DestroyWindow(hwnd);
2276
2277 hwnd = create_listview_control(LVS_SMALLICON);
2278 ok(hwnd != NULL, "failed to create a listview window\n");
2279 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2280
2281 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2282 expect(TRUE, r);
2283 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2284 DestroyWindow(hwnd);
2285
2286 hwnd = create_listview_control(LVS_LIST);
2287 ok(hwnd != NULL, "failed to create a listview window\n");
2288 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2289
2290 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2291 expect(FALSE, r);
2292 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2293 DestroyWindow(hwnd);
2294
2295 hwnd = create_listview_control(LVS_REPORT);
2296 ok(hwnd != NULL, "failed to create a listview window\n");
2297 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2298
2299 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2300 expect(FALSE, r);
2301 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2302 DestroyWindow(hwnd);
2303 }
2304
2305 static void test_multiselect(void)
2306 {
2307 typedef struct t_select_task
2308 {
2309 const char *descr;
2310 int initPos;
2311 int loopVK;
2312 int count;
2313 int result;
2314 } select_task;
2315
2316 HWND hwnd;
2317 INT r;
2318 int i, j;
2319 static const int items=5;
2320 DWORD item_count;
2321 BYTE kstate[256];
2322 select_task task;
2323 LONG_PTR style;
2324 LVITEMA item;
2325
2326 static struct t_select_task task_list[] = {
2327 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2328 { "using VK_UP", -1, VK_UP, -1, -1 },
2329 { "using VK_END", 0, VK_END, 1, -1 },
2330 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2331 };
2332
2333 hwnd = create_listview_control(LVS_REPORT);
2334
2335 for (i = 0; i < items; i++)
2336 insert_item(hwnd, 0);
2337
2338 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2339 expect(items, item_count);
2340
2341 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2342 ok(r == -1, "got %d\n", r);
2343
2344 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2345 ok(r == -1, "got %d\n", r);
2346
2347 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2348 ok(r == 0, "got %d\n", r);
2349
2350 /* out of range index */
2351 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
2352 ok(r == 0, "got %d\n", r);
2353
2354 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2355 ok(r == 0, "got %d\n", r);
2356
2357 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
2358 ok(r == 0, "got %d\n", r);
2359
2360 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2361 ok(r == 0, "got %d\n", r);
2362
2363 for (i = 0; i < ARRAY_SIZE(task_list); i++) {
2364 DWORD selected_count;
2365 LVITEMA item;
2366
2367 task = task_list[i];
2368
2369 /* deselect all items */
2370 item.state = 0;
2371 item.stateMask = LVIS_SELECTED;
2372 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2373 ok(r, "got %d\n", r);
2374 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2375
2376 /* set initial position */
2377 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2378 ok(r, "got %d\n", r);
2379
2380 item.state = LVIS_SELECTED;
2381 item.stateMask = LVIS_SELECTED;
2382 r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2383 ok(r, "got %d\n", r);
2384
2385 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2386 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2387
2388 /* Set SHIFT key pressed */
2389 GetKeyboardState(kstate);
2390 kstate[VK_SHIFT]=0x80;
2391 SetKeyboardState(kstate);
2392
2393 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2394 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2395 expect(0,r);
2396 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2397 expect(0,r);
2398 }
2399
2400 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2401
2402 ok((task.result == -1 ? item_count : task.result) == selected_count,
2403 "Failed multiple selection %s. There should be %d selected items (is %d)\n",
2404 task.descr, item_count, selected_count);
2405
2406 /* Set SHIFT key released */
2407 GetKeyboardState(kstate);
2408 kstate[VK_SHIFT]=0x00;
2409 SetKeyboardState(kstate);
2410 }
2411 DestroyWindow(hwnd);
2412
2413 /* make multiple selection, then switch to LVS_SINGLESEL */
2414 hwnd = create_listview_control(LVS_REPORT);
2415 for (i=0;i<items;i++) {
2416 insert_item(hwnd, 0);
2417 }
2418 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2419 expect(items,item_count);
2420
2421 /* try with NULL pointer */
2422 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2423 expect(FALSE, r);
2424
2425 /* select all, check notifications */
2426 item.state = 0;
2427 item.stateMask = LVIS_SELECTED;
2428 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2429 ok(r, "got %d\n", r);
2430
2431 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2432
2433 item.stateMask = LVIS_SELECTED;
2434 item.state = LVIS_SELECTED;
2435 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2436 expect(TRUE, r);
2437
2438 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2439 "select all notification", FALSE);
2440
2441 /* select all again (all selected already) */
2442 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2443
2444 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2445
2446 item.stateMask = LVIS_SELECTED;
2447 item.state = LVIS_SELECTED;
2448 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2449 expect(TRUE, r);
2450
2451 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2452 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2453 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2454
2455 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2456 "select all notification 2", FALSE);
2457
2458 /* deselect all items */
2459 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2460
2461 item.state = 0;
2462 item.stateMask = LVIS_SELECTED;
2463 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2464 ok(r, "got %d\n", r);
2465
2466 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2467 "deselect all notification", FALSE);
2468
2469 /* deselect all items again */
2470 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2471 item.state = 0;
2472 item.stateMask = LVIS_SELECTED;
2473 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2474 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2475
2476 /* any non-zero state value does the same */
2477 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2478
2479 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2480
2481 item.stateMask = LVIS_SELECTED;
2482 item.state = LVIS_CUT;
2483 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2484 expect(TRUE, r);
2485
2486 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2487 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2488 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2489
2490 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2491 "set state all notification 3", FALSE);
2492
2493 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2494 ok(r, "got %d\n", r);
2495 for (i = 0; i < 3; i++) {
2496 item.state = LVIS_SELECTED;
2497 item.stateMask = LVIS_SELECTED;
2498 r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2499 ok(r, "got %d\n", r);
2500 }
2501
2502 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2503 expect(3, r);
2504 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2505 expect(-1, r);
2506
2507 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2508 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2509 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2510 /* check that style is accepted */
2511 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2512 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2513
2514 for (i=0;i<3;i++) {
2515 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2516 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2517 }
2518 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2519 expect(3, r);
2520 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2521 ok(r == -1, "got %d\n", r);
2522
2523 /* select one more */
2524 item.state = LVIS_SELECTED;
2525 item.stateMask = LVIS_SELECTED;
2526 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2527 ok(r, "got %d\n", r);
2528
2529 for (i=0;i<3;i++) {
2530 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2531 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2532 }
2533
2534 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2535 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2536
2537 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2538 expect(1, r);
2539 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2540 expect(-1, r);
2541
2542 /* try to select all on LVS_SINGLESEL */
2543 memset(&item, 0, sizeof(item));
2544 item.stateMask = LVIS_SELECTED;
2545 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2546 expect(TRUE, r);
2547 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2548 ok(r == -1, "got %d\n", r);
2549
2550 item.stateMask = LVIS_SELECTED;
2551 item.state = LVIS_SELECTED;
2552 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2553 expect(FALSE, r);
2554
2555 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2556 expect(0, r);
2557 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2558 expect(-1, r);
2559
2560 /* try to deselect all on LVS_SINGLESEL */
2561 item.stateMask = LVIS_SELECTED;
2562 item.state = LVIS_SELECTED;
2563 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2564 expect(TRUE, r);
2565
2566 item.stateMask = LVIS_SELECTED;
2567 item.state = 0;
2568 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2569 expect(TRUE, r);
2570 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2571 expect(0, r);
2572
2573 /* 1. selection mark is update when new focused item is set */
2574 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2575 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2576
2577 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2578 expect(-1, r);
2579
2580 item.stateMask = LVIS_FOCUSED;
2581 item.state = LVIS_FOCUSED;
2582 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2583 expect(TRUE, r);
2584
2585 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2586 expect(0, r);
2587
2588 /* it's not updated if already set */
2589 item.stateMask = LVIS_FOCUSED;
2590 item.state = LVIS_FOCUSED;
2591 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2592 expect(TRUE, r);
2593
2594 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2595 expect(0, r);
2596
2597 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2598 expect(0, r);
2599
2600 item.stateMask = LVIS_FOCUSED;
2601 item.state = LVIS_FOCUSED;
2602 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2603 expect(TRUE, r);
2604
2605 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2606 expect(-1, r);
2607
2608 /* need to reset focused item first */
2609 item.stateMask = LVIS_FOCUSED;
2610 item.state = 0;
2611 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2612 expect(TRUE, r);
2613
2614 item.stateMask = LVIS_FOCUSED;
2615 item.state = LVIS_FOCUSED;
2616 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2617 expect(TRUE, r);
2618
2619 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2620 expect(2, r);
2621
2622 item.stateMask = LVIS_FOCUSED;
2623 item.state = 0;
2624 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2625 expect(TRUE, r);
2626
2627 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2628 expect(2, r);
2629
2630 /* 2. same tests, with LVM_SETITEM */
2631 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2632 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2633
2634 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2635 expect(2, r);
2636
2637 item.stateMask = LVIS_FOCUSED;
2638 item.state = LVIS_FOCUSED;
2639 item.mask = LVIF_STATE;
2640 item.iItem = item.iSubItem = 0;
2641 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2642 expect(TRUE, r);
2643
2644 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2645 expect(0, r);
2646
2647 /* it's not updated if already set */
2648 item.stateMask = LVIS_FOCUSED;
2649 item.state = LVIS_FOCUSED;
2650 item.mask = LVIF_STATE;
2651 item.iItem = 1;
2652 item.iSubItem = 0;
2653 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2654 expect(TRUE, r);
2655
2656 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2657 expect(0, r);
2658
2659 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2660 expect(0, r);
2661
2662 item.stateMask = LVIS_FOCUSED;
2663 item.state = LVIS_FOCUSED;
2664 item.mask = LVIF_STATE;
2665 item.iItem = 1;
2666 item.iSubItem = 0;
2667 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2668 expect(TRUE, r);
2669
2670 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2671 expect(-1, r);
2672
2673 /* need to reset focused item first */
2674 item.stateMask = LVIS_FOCUSED;
2675 item.state = 0;
2676 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2677 expect(TRUE, r);
2678
2679 item.stateMask = LVIS_FOCUSED;
2680 item.state = LVIS_FOCUSED;
2681 item.mask = LVIF_STATE;
2682 item.iItem = 2;
2683 item.iSubItem = 0;
2684 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2685 expect(TRUE, r);
2686
2687 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2688 expect(2, r);
2689
2690 item.stateMask = LVIS_FOCUSED;
2691 item.state = 0;
2692 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2693 expect(TRUE, r);
2694
2695 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2696 expect(2, r);
2697
2698 DestroyWindow(hwnd);
2699 }
2700
2701 static void test_subitem_rect(void)
2702 {
2703 HWND hwnd;
2704 DWORD r;
2705 LVCOLUMNA col;
2706 RECT rect, rect2;
2707 INT arr[3];
2708
2709 /* test LVM_GETSUBITEMRECT for header */
2710 hwnd = create_listview_control(LVS_REPORT);
2711 ok(hwnd != NULL, "failed to create a listview window\n");
2712 /* add some columns */
2713 memset(&col, 0, sizeof(LVCOLUMNA));
2714 col.mask = LVCF_WIDTH;
2715 col.cx = 100;
2716 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2717 expect(0, r);
2718 col.cx = 150;
2719 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2720 expect(1, r);
2721 col.cx = 200;
2722 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2723 expect(2, r);
2724 /* item = -1 means header, subitem index is 1 based */
2725 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2726 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2727 expect(0, r);
2728
2729 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2730 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2731 expect(1, r);
2732
2733 expect(100, rect.left);
2734 expect(250, rect.right);
2735 expect(3, rect.top);
2736
2737 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2738 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2739 expect(1, r);
2740
2741 expect(250, rect.left);
2742 expect(450, rect.right);
2743 expect(3, rect.top);
2744
2745 /* item LVS_REPORT padding isn't applied to subitems */
2746 insert_item(hwnd, 0);
2747
2748 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2749 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2750 expect(1, r);
2751 expect(100, rect.left);
2752 expect(250, rect.right);
2753
2754 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2755 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2756 expect(1, r);
2757 /* no icon attached - zero width rectangle, with no left padding */
2758 expect(100, rect.left);
2759 expect(100, rect.right);
2760
2761 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2762 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2763 expect(1, r);
2764 /* same as full LVIR_BOUNDS */
2765 expect(100, rect.left);
2766 expect(250, rect.right);
2767
2768 r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2769 ok(r, "got %d\n", r);
2770
2771 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2772 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2773 expect(1, r);
2774 expect(90, rect.left);
2775 expect(240, rect.right);
2776
2777 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2778
2779 /* test header interaction */
2780 subclass_header(hwnd);
2781 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2782
2783 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2784 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2785 expect(1, r);
2786
2787 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2788 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2789 expect(1, r);
2790
2791 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2792 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2793 expect(1, r);
2794
2795 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2796 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2797 expect(1, r);
2798
2799 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2800
2801 DestroyWindow(hwnd);
2802
2803 /* test subitem rects after re-arranging columns */
2804 hwnd = create_listview_control(LVS_REPORT);
2805 ok(hwnd != NULL, "failed to create a listview window\n");
2806 memset(&col, 0, sizeof(LVCOLUMNA));
2807 col.mask = LVCF_WIDTH;
2808
2809 col.cx = 100;
2810 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2811 expect(0, r);
2812
2813 col.cx = 200;
2814 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2815 expect(1, r);
2816
2817 col.cx = 300;
2818 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2819 expect(2, r);
2820
2821 insert_item(hwnd, 0);
2822 insert_item(hwnd, 1);
2823
2824 /* wrong item is refused for main item */
2825 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2826 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2827 expect(FALSE, r);
2828
2829 /* for subitems rectangle is calculated even if there's no item added */
2830 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2831 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2832 expect(TRUE, r);
2833
2834 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2835 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2836 expect(TRUE, r);
2837 expect(rect.right, rect2.right);
2838 expect(rect.left, rect2.left);
2839 expect(rect.bottom, rect2.top);
2840 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2841
2842 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2843 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2844 expect(TRUE, r);
2845
2846 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2847 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2848 expect(TRUE, r);
2849 expect(0, rect.left);
2850 expect(600, rect.right);
2851
2852 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2853 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2854 expect(TRUE, r);
2855 expect(0, rect.left);
2856 expect(200, rect.right);
2857
2858 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2859 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2860 expect(TRUE, r);
2861 expect(0, rect2.left);
2862 expect(200, rect2.right);
2863 /* items are of the same height */
2864 ok(rect2.top > 0, "expected positive item height\n");
2865 expect(rect.bottom, rect2.top);
2866 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2867
2868 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
2869 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2870 expect(TRUE, r);
2871 expect(300, rect.left);
2872 expect(600, rect.right);
2873
2874 DestroyWindow(hwnd);
2875
2876 /* try it for non LVS_REPORT style */
2877 hwnd = CreateWindowA(WC_LISTVIEWA, "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2878 GetModuleHandleA(NULL), 0);
2879 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
2880 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2881 expect(0, r);
2882 /* rect is unchanged */
2883 expect(0, rect.left);
2884 expect(-10, rect.right);
2885 expect(1, rect.top);
2886 expect(-10, rect.bottom);
2887 DestroyWindow(hwnd);
2888 }
2889
2890 /* comparison callback for test_sorting */
2891 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2892 {
2893 if (first == second) return 0;
2894 return (first > second ? 1 : -1);
2895 }
2896
2897 static void test_sorting(void)
2898 {
2899 HWND hwnd;
2900 LVITEMA item = {0};
2901 INT r;
2902 LONG_PTR style;
2903 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2904 CHAR buff[10];
2905
2906 hwnd = create_listview_control(LVS_REPORT);
2907 ok(hwnd != NULL, "failed to create a listview window\n");
2908
2909 /* insert some items */
2910 item.mask = LVIF_PARAM | LVIF_STATE;
2911 item.state = LVIS_SELECTED;
2912 item.iItem = 0;
2913 item.iSubItem = 0;
2914 item.lParam = 3;
2915 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2916 expect(0, r);
2917
2918 item.mask = LVIF_PARAM;
2919 item.iItem = 1;
2920 item.iSubItem = 0;
2921 item.lParam = 2;
2922 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2923 expect(1, r);
2924
2925 item.mask = LVIF_STATE | LVIF_PARAM;
2926 item.state = LVIS_SELECTED;
2927 item.iItem = 2;
2928 item.iSubItem = 0;
2929 item.lParam = 4;
2930 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2931 expect(2, r);
2932
2933 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2934 expect(-1, r);
2935
2936 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2937 expect(2, r);
2938
2939 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2940 expect(TRUE, r);
2941
2942 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2943 expect(2, r);
2944 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2945 expect(-1, r);
2946 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2947 expect(0, r);
2948 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2949 expect(LVIS_SELECTED, r);
2950 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2951 expect(LVIS_SELECTED, r);
2952
2953 DestroyWindow(hwnd);
2954
2955 /* switch to LVS_SORTASCENDING when some items added */
2956 hwnd = create_listview_control(LVS_REPORT);
2957 ok(hwnd != NULL, "failed to create a listview window\n");
2958
2959 item.mask = LVIF_TEXT;
2960 item.iItem = 0;
2961 item.iSubItem = 0;
2962 item.pszText = names[1];
2963 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2964 expect(0, r);
2965
2966 item.mask = LVIF_TEXT;
2967 item.iItem = 1;
2968 item.iSubItem = 0;
2969 item.pszText = names[2];
2970 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2971 expect(1, r);
2972
2973 item.mask = LVIF_TEXT;
2974 item.iItem = 2;
2975 item.iSubItem = 0;
2976 item.pszText = names[0];
2977 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2978 expect(2, r);
2979
2980 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2981 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2982 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2983 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2984
2985 /* no sorting performed when switched to LVS_SORTASCENDING */
2986 item.mask = LVIF_TEXT;
2987 item.iItem = 0;
2988 item.pszText = buff;
2989 item.cchTextMax = sizeof(buff);
2990 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2991 expect(TRUE, r);
2992 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2993
2994 item.iItem = 1;
2995 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2996 expect(TRUE, r);
2997 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2998
2999 item.iItem = 2;
3000 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3001 expect(TRUE, r);
3002 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3003
3004 /* adding new item doesn't resort list */
3005 item.mask = LVIF_TEXT;
3006 item.iItem = 3;
3007 item.iSubItem = 0;
3008 item.pszText = names[3];
3009 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3010 expect(3, r);
3011
3012 item.mask = LVIF_TEXT;
3013 item.iItem = 0;
3014 item.pszText = buff;
3015 item.cchTextMax = sizeof(buff);
3016 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3017 expect(TRUE, r);
3018 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3019
3020 item.iItem = 1;
3021 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3022 expect(TRUE, r);
3023 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3024
3025 item.iItem = 2;
3026 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3027 expect(TRUE, r);
3028 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3029
3030 item.iItem = 3;
3031 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3032 expect(TRUE, r);
3033 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3034
3035 /* corner case - item should be placed at first position */
3036 item.mask = LVIF_TEXT;
3037 item.iItem = 4;
3038 item.iSubItem = 0;
3039 item.pszText = names[4];
3040 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3041 expect(0, r);
3042
3043 item.iItem = 0;
3044 item.pszText = buff;
3045 item.cchTextMax = sizeof(buff);
3046 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3047 expect(TRUE, r);
3048 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
3049
3050 item.iItem = 1;
3051 item.pszText = buff;
3052 item.cchTextMax = sizeof(buff);
3053 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3054 expect(TRUE, r);
3055 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3056
3057 item.iItem = 2;
3058 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3059 expect(TRUE, r);
3060 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3061
3062 item.iItem = 3;
3063 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3064 expect(TRUE, r);
3065 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3066
3067 item.iItem = 4;
3068 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3069 expect(TRUE, r);
3070 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3071
3072 DestroyWindow(hwnd);
3073 }
3074
3075 static void test_ownerdata(void)
3076 {
3077 static char test_str[] = "test";
3078
3079 HWND hwnd;
3080 LONG_PTR style, ret;
3081 DWORD res;
3082 LVITEMA item;
3083
3084 /* it isn't possible to set LVS_OWNERDATA after creation */
3085 if (g_is_below_5)
3086 {
3087 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3088 }
3089 else
3090 {
3091 hwnd = create_listview_control(LVS_REPORT);
3092 ok(hwnd != NULL, "failed to create a listview window\n");
3093 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3094 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3095
3096 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3097
3098 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3099 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3100 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3101 "try to switch to LVS_OWNERDATA seq", FALSE);
3102
3103 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3104 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3105 DestroyWindow(hwnd);
3106 }
3107
3108 /* try to set LVS_OWNERDATA after creation just having it */
3109 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3110 ok(hwnd != NULL, "failed to create a listview window\n");
3111 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3112 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3113
3114 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3115
3116 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3117 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3118 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3119 "try to switch to LVS_OWNERDATA seq", FALSE);
3120 DestroyWindow(hwnd);
3121
3122 /* try to remove LVS_OWNERDATA after creation just having it */
3123 if (g_is_below_5)
3124 {
3125 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3126 }
3127 else
3128 {
3129 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3130 ok(hwnd != NULL, "failed to create a listview window\n");
3131 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3132 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3133
3134 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3135
3136 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3137 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3138 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3139 "try to switch to LVS_OWNERDATA seq", FALSE);
3140 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3141 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3142 DestroyWindow(hwnd);
3143 }
3144
3145 /* try select an item */
3146 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3147 ok(hwnd != NULL, "failed to create a listview window\n");
3148 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3149 expect(1, res);
3150 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3151 expect(0, res);
3152 memset(&item, 0, sizeof(item));
3153 item.stateMask = LVIS_SELECTED;
3154 item.state = LVIS_SELECTED;
3155 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3156 expect(TRUE, res);
3157 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3158 expect(1, res);
3159 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3160 expect(1, res);
3161 DestroyWindow(hwnd);
3162
3163 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3164 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3165 ok(hwnd != NULL, "failed to create a listview window\n");
3166 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3167 expect(1, res);
3168 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3169 expect(1, res);
3170 memset(&item, 0, sizeof(item));
3171 item.mask = LVIF_STATE;
3172 item.iItem = 0;
3173 item.stateMask = LVIS_SELECTED;
3174 item.state = LVIS_SELECTED;
3175 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3176 expect(FALSE, res);
3177 memset(&item, 0, sizeof(item));
3178 item.pszText = test_str;
3179 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3180 expect(FALSE, res);
3181 DestroyWindow(hwnd);
3182
3183 /* check notifications after focused/selected changed */
3184 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3185 ok(hwnd != NULL, "failed to create a listview window\n");
3186 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3187 expect(1, res);
3188
3189 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3190
3191 memset(&item, 0, sizeof(item));
3192 item.stateMask = LVIS_SELECTED;
3193 item.state = LVIS_SELECTED;
3194 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3195 expect(TRUE, res);
3196
3197 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3198 "ownerdata select notification", TRUE);
3199
3200 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3201
3202 memset(&item, 0, sizeof(item));
3203 item.stateMask = LVIS_FOCUSED;
3204 item.state = LVIS_FOCUSED;
3205 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3206 expect(TRUE, res);
3207
3208 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3209 "ownerdata focus notification", TRUE);
3210
3211 /* select all, check notifications */
3212 item.stateMask = LVIS_SELECTED;
3213 item.state = 0;
3214 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3215 expect(TRUE, res);
3216
3217 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3218
3219 item.stateMask = LVIS_SELECTED;
3220 item.state = LVIS_SELECTED;
3221
3222 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3223 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3224 expect(TRUE, res);
3225 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3226 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3227 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3228 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3229 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3230 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3231 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3232
3233 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3234 "ownerdata select all notification", FALSE);
3235
3236 /* select all again, note that all items are selected already */
3237 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3238 item.stateMask = LVIS_SELECTED;
3239 item.state = LVIS_SELECTED;
3240
3241 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3242 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3243 expect(TRUE, res);
3244 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3245 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3246 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3247 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3248 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3249 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3250 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3251
3252 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3253 "ownerdata select all notification", FALSE);
3254
3255 /* deselect all */
3256 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3257 item.stateMask = LVIS_SELECTED;
3258 item.state = 0;
3259
3260 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3261 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3262 expect(TRUE, res);
3263 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3264 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3265 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3266 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3267 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3268 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3269 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3270
3271 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3272 "ownerdata deselect all notification", TRUE);
3273
3274 /* nothing selected, deselect all again */
3275 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3276 item.stateMask = LVIS_SELECTED;
3277 item.state = 0;
3278
3279 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3280 expect(TRUE, res);
3281
3282 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3283
3284 /* select one, then deselect all */
3285 item.stateMask = LVIS_SELECTED;
3286 item.state = LVIS_SELECTED;
3287 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3288 expect(TRUE, res);
3289 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3290 item.stateMask = LVIS_SELECTED;
3291 item.state = 0;
3292
3293 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3294 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3295 expect(TRUE, res);
3296 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3297 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3298 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3299 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3300 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3301 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3302 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3303
3304 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3305 "ownerdata select all notification", TRUE);
3306
3307 /* remove focused, try to focus all */
3308 item.stateMask = LVIS_FOCUSED;
3309 item.state = LVIS_FOCUSED;
3310 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3311 expect(TRUE, res);
3312 item.stateMask = LVIS_FOCUSED;
3313 item.state = 0;
3314 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3315 expect(TRUE, res);
3316 item.stateMask = LVIS_FOCUSED;
3317 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3318 expect(0, res);
3319
3320 /* setting all to focused returns failure value */
3321 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3322 item.stateMask = LVIS_FOCUSED;
3323 item.state = LVIS_FOCUSED;
3324
3325 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3326 expect(FALSE, res);
3327
3328 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3329 "ownerdata focus all notification", FALSE);
3330
3331 /* focus single item, remove all */
3332 item.stateMask = LVIS_FOCUSED;
3333 item.state = LVIS_FOCUSED;
3334 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3335 expect(TRUE, res);
3336 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3337 item.stateMask = LVIS_FOCUSED;
3338 item.state = 0;
3339
3340 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3341 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3342 expect(TRUE, res);
3343 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3344 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3345 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3346 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3347 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3348 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3349 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3350
3351 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3352 "ownerdata remove focus all notification", TRUE);
3353
3354 /* set all cut */
3355 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3356 item.stateMask = LVIS_CUT;
3357 item.state = LVIS_CUT;
3358
3359 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3360 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3361 expect(TRUE, res);
3362 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3363 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3364 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3365 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3366 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3367 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3368 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3369
3370 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3371 "ownerdata cut all notification", FALSE);
3372
3373 /* all marked cut, try again */
3374 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3375 item.stateMask = LVIS_CUT;
3376 item.state = LVIS_CUT;
3377
3378 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3379 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3380 expect(TRUE, res);
3381 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3382 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3383 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3384 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3385 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3386 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3387 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3388
3389 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3390 "ownerdata cut all notification #2", FALSE);
3391
3392 DestroyWindow(hwnd);
3393
3394 /* check notifications on LVM_GETITEM */
3395 /* zero callback mask */
3396 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3397 ok(hwnd != NULL, "failed to create a listview window\n");
3398 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3399 expect(1, res);
3400
3401 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3402
3403 memset(&item, 0, sizeof(item));
3404 item.stateMask = LVIS_SELECTED;
3405 item.mask = LVIF_STATE;
3406 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3407 expect(TRUE, res);
3408
3409 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3410 "ownerdata getitem selected state 1", FALSE);
3411
3412 /* non zero callback mask but not we asking for */
3413 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3414 expect(TRUE, res);
3415
3416 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3417
3418 memset(&item, 0, sizeof(item));
3419 item.stateMask = LVIS_SELECTED;
3420 item.mask = LVIF_STATE;
3421 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3422 expect(TRUE, res);
3423
3424 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3425 "ownerdata getitem selected state 2", FALSE);
3426
3427 /* LVIS_OVERLAYMASK callback mask, asking for index */
3428 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3429
3430 memset(&item, 0, sizeof(item));
3431 item.stateMask = LVIS_OVERLAYMASK;
3432 item.mask = LVIF_STATE;
3433 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3434 expect(TRUE, res);
3435
3436 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3437 "ownerdata getitem selected state 2", FALSE);
3438
3439 DestroyWindow(hwnd);
3440
3441 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3442 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3443 ok(hwnd != NULL, "failed to create a listview window\n");
3444 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3445 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3446 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3447 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3448 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3449 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3450 DestroyWindow(hwnd);
3451 /* apparently it's allowed to switch these style on after creation */
3452 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3453 ok(hwnd != NULL, "failed to create a listview window\n");
3454 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3455 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3456 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3457 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3458 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3459 DestroyWindow(hwnd);
3460
3461 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3462 ok(hwnd != NULL, "failed to create a listview window\n");
3463 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3464 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3465 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3466 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3467 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3468 DestroyWindow(hwnd);
3469
3470 /* The focused item is updated after the invalidation */
3471 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3472 ok(hwnd != NULL, "failed to create a listview window\n");
3473 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3474 expect(TRUE, res);
3475
3476 memset(&item, 0, sizeof(item));
3477 item.stateMask = LVIS_FOCUSED;
3478 item.state = LVIS_FOCUSED;
3479 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3480 expect(TRUE, res);
3481
3482 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3483 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3484 expect(TRUE, res);
3485 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3486 "ownerdata setitemcount", FALSE);
3487
3488 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3489 expect(-1, res);
3490 DestroyWindow(hwnd);
3491 }
3492
3493 static void test_norecompute(void)
3494 {
3495 static CHAR testA[] = "test";
3496 CHAR buff[10];
3497 LVITEMA item;
3498 HWND hwnd;
3499 DWORD res;
3500
3501 /* self containing control */
3502 hwnd = create_listview_control(LVS_REPORT);
3503 ok(hwnd != NULL, "failed to create a listview window\n");
3504 memset(&item, 0, sizeof(item));
3505 item.mask = LVIF_TEXT | LVIF_STATE;
3506 item.iItem = 0;
3507 item.stateMask = LVIS_SELECTED;
3508 item.state = LVIS_SELECTED;
3509 item.pszText = testA;
3510 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3511 expect(0, res);
3512 /* retrieve with LVIF_NORECOMPUTE */
3513 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3514 item.iItem = 0;
3515 item.pszText = buff;
3516 item.cchTextMax = ARRAY_SIZE(buff);
3517 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3518 expect(TRUE, res);
3519 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3520
3521 item.mask = LVIF_TEXT;
3522 item.iItem = 1;
3523 item.pszText = LPSTR_TEXTCALLBACKA;
3524 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3525 expect(1, res);
3526
3527 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3528 item.iItem = 1;
3529 item.pszText = buff;
3530 item.cchTextMax = ARRAY_SIZE(buff);
3531
3532 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3533 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3534 expect(TRUE, res);
3535 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3536 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3537 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3538
3539 DestroyWindow(hwnd);
3540
3541 /* LVS_OWNERDATA */
3542 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3543 ok(hwnd != NULL, "failed to create a listview window\n");
3544
3545 item.mask = LVIF_STATE;
3546 item.stateMask = LVIS_SELECTED;
3547 item.state = LVIS_SELECTED;
3548 item.iItem = 0;
3549 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3550 expect(0, res);
3551
3552 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3553 item.iItem = 0;
3554 item.pszText = buff;
3555 item.cchTextMax = ARRAY_SIZE(buff);
3556 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3557 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3558 expect(TRUE, res);
3559 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3560 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3561 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3562
3563 DestroyWindow(hwnd);
3564 }
3565
3566 static void test_nosortheader(void)
3567 {
3568 HWND hwnd, header;
3569 LONG_PTR style;
3570
3571 hwnd = create_listview_control(LVS_REPORT);
3572 ok(hwnd != NULL, "failed to create a listview window\n");
3573
3574 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3575 ok(IsWindow(header), "header expected\n");
3576
3577 style = GetWindowLongPtrA(header, GWL_STYLE);
3578 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3579
3580 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3581 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3582 /* HDS_BUTTONS retained */
3583 style = GetWindowLongPtrA(header, GWL_STYLE);
3584 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3585
3586 DestroyWindow(hwnd);
3587
3588 /* create with LVS_NOSORTHEADER */
3589 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3590 ok(hwnd != NULL, "failed to create a listview window\n");
3591
3592 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3593 ok(IsWindow(header), "header expected\n");
3594
3595 style = GetWindowLongPtrA(header, GWL_STYLE);
3596 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3597
3598 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3599 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3600 /* not changed here */
3601 style = GetWindowLongPtrA(header, GWL_STYLE);
3602 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3603
3604 DestroyWindow(hwnd);
3605 }
3606
3607 static void test_setredraw(void)
3608 {
3609 HWND hwnd;
3610 DWORD_PTR style;
3611 DWORD ret;
3612 HDC hdc;
3613 RECT rect;
3614
3615 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3616 ok(hwnd != NULL, "failed to create a listview window\n");
3617
3618 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3619 ListView seems to handle it internally without DefWinProc */
3620
3621 /* default value first */
3622 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3623 expect(0, ret);
3624 /* disable */
3625 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3626 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3627 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3628 expect(0, ret);
3629 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3630 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3631 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3632 expect(0, ret);
3633
3634 /* check update rect after redrawing */
3635 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3636 expect(0, ret);
3637 InvalidateRect(hwnd, NULL, FALSE);
3638 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3639 rect.right = rect.bottom = 1;
3640 GetUpdateRect(hwnd, &rect, FALSE);
3641 expect(0, rect.right);
3642 expect(0, rect.bottom);
3643
3644 /* WM_ERASEBKGND */
3645 hdc = GetWindowDC(hwndparent);
3646 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3647 expect(TRUE, ret);
3648 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3649 expect(0, ret);
3650 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3651 expect(TRUE, ret);
3652 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3653 expect(0, ret);
3654 ReleaseDC(hwndparent, hdc);
3655
3656 /* check notification messages to show that repainting is disabled */
3657 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3658 expect(TRUE, ret);
3659 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3660 expect(0, ret);
3661 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3662
3663 InvalidateRect(hwnd, NULL, TRUE);
3664 UpdateWindow(hwnd);
3665 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3666 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3667
3668 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3669 expect(TRUE, ret);
3670 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3671 InvalidateRect(hwnd, NULL, TRUE);
3672 UpdateWindow(hwnd);
3673 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3674 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3675
3676 /* message isn't forwarded to header */
3677 subclass_header(hwnd);
3678 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3679 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3680 expect(0, ret);
3681 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3682 "WM_SETREDRAW: not forwarded to header", FALSE);
3683
3684 DestroyWindow(hwnd);
3685 }
3686
3687 static void test_hittest(void)
3688 {
3689 HWND hwnd;
3690 DWORD r;
3691 RECT bounds;
3692 LVITEMA item;
3693 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3694 POINT pos;
3695 INT x, y, i;
3696 WORD vert;
3697 HIMAGELIST himl, himl2;
3698 HBITMAP hbmp;
3699
3700 hwnd = create_listview_control(LVS_REPORT);
3701 ok(hwnd != NULL, "failed to create a listview window\n");
3702
3703 /* LVS_REPORT with a single subitem (2 columns) */
3704 insert_column(hwnd, 0);
3705 insert_column(hwnd, 1);
3706 insert_item(hwnd, 0);
3707
3708 item.iSubItem = 0;
3709 /* the only purpose of that line is to be as long as a half item rect */
3710 item.pszText = text;
3711 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3712 expect(TRUE, r);
3713
3714 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3715 expect(TRUE, r);
3716 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3717 expect(TRUE, r);
3718
3719 SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3720 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3721 expect(1, r);
3722 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3723 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3724 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3725 vert = HIWORD(r);
3726 ok(bounds.bottom - bounds.top == vert,
3727 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3728 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3729 expect(TRUE, r);
3730
3731 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3732
3733 /* outside columns by x position - valid is [0, 199] */
3734 x = -1;
3735 y = pos.y + (bounds.bottom - bounds.top) / 2;
3736 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3737 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3738
3739 x = pos.x + 50; /* column half width */
3740 y = pos.y + (bounds.bottom - bounds.top) / 2;
3741 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3742 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3743 x = pos.x + 150; /* outside column */
3744 y = pos.y + (bounds.bottom - bounds.top) / 2;
3745 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3746 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3747 y = (bounds.bottom - bounds.top) / 2;
3748 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3749 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3750 /* outside possible client rectangle (to right) */
3751 x = pos.x + 500;
3752 y = pos.y + (bounds.bottom - bounds.top) / 2;
3753 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3754 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3755 y = (bounds.bottom - bounds.top) / 2;
3756 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3757 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3758 /* subitem returned with -1 item too */
3759 x = pos.x + 150;
3760 y = bounds.top - vert;
3761 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3762 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3763 /* return values appear to underflow with negative indices */
3764 i = -2;
3765 y = y - vert;
3766 while (i > -10) {
3767 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3768 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3769 y = y - vert;
3770 i--;
3771 }
3772 /* parent client area is 100x100 by default */
3773 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3774 x = pos.x + 150; /* outside column */
3775 y = pos.y + (bounds.bottom - bounds.top) / 2;
3776 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3777 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3778 y = (bounds.bottom - bounds.top) / 2;
3779 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3780 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3781 /* the same with LVS_EX_FULLROWSELECT */
3782 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3783 x = pos.x + 150; /* outside column */
3784 y = pos.y + (bounds.bottom - bounds.top) / 2;
3785 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3786 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3787 y = (bounds.bottom - bounds.top) / 2;
3788 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3789 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3790 x = pos.x + 150; /* outside column */
3791 y = pos.y + (bounds.bottom - bounds.top) / 2;
3792 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3793 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3794 y = (bounds.bottom - bounds.top) / 2;
3795 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3796 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3797 /* outside possible client rectangle (to right) */
3798 x = pos.x + 500;
3799 y = pos.y + (bounds.bottom - bounds.top) / 2;
3800 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3801 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3802 y = (bounds.bottom - bounds.top) / 2;
3803 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3804 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3805 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3806 himl = pImageList_Create(16, 16, 0, 4, 4);
3807 ok(himl != NULL, "failed to create imagelist\n");
3808 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3809 ok(hbmp != NULL, "failed to create bitmap\n");
3810 r = pImageList_Add(himl, hbmp, 0);
3811 ok(r == 0, "should be zero\n");
3812 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3813 ok(hbmp != NULL, "failed to create bitmap\n");
3814 r = pImageList_Add(himl, hbmp, 0);
3815 ok(r == 1, "should be one\n");
3816
3817 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3818 expect(0, r);
3819
3820 item.mask = LVIF_IMAGE;
3821 item.iImage = 0;
3822 item.iItem = 0;
3823 item.iSubItem = 0;
3824 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3825 expect(TRUE, r);
3826 /* on state icon */
3827 x = pos.x + 8;
3828 y = pos.y + (bounds.bottom - bounds.top) / 2;
3829 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3830 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3831 y = (bounds.bottom - bounds.top) / 2;
3832 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3833
3834 /* state icons indices are 1 based, check with valid index */
3835 item.mask = LVIF_STATE;
3836 item.state = INDEXTOSTATEIMAGEMASK(1);
3837 item.stateMask = LVIS_STATEIMAGEMASK;
3838 item.iItem = 0;
3839 item.iSubItem = 0;
3840 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3841 expect(TRUE, r);
3842 /* on state icon */
3843 x = pos.x + 8;
3844 y = pos.y + (bounds.bottom - bounds.top) / 2;
3845 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3846 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3847 y = (bounds.bottom - bounds.top) / 2;
3848 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3849
3850 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3851 ok(himl2 == himl, "should return handle\n");
3852
3853 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3854 expect(0, r);
3855 /* on item icon */
3856 x = pos.x + 8;
3857 y = pos.y + (bounds.bottom - bounds.top) / 2;
3858 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3859 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3860 y = (bounds.bottom - bounds.top) / 2;
3861 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3862
3863 DestroyWindow(hwnd);
3864 }
3865
3866 static void test_getviewrect(void)
3867 {
3868 HWND hwnd;
3869 DWORD r;
3870 RECT rect;
3871 LVITEMA item;
3872
3873 hwnd = create_listview_control(LVS_REPORT);
3874 ok(hwnd != NULL, "failed to create a listview window\n");
3875
3876 /* empty */
3877 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3878 expect(TRUE, r);
3879
3880 insert_column(hwnd, 0);
3881 insert_column(hwnd, 1);
3882
3883 memset(&item, 0, sizeof(item));
3884 item.iItem = 0;
3885 item.iSubItem = 0;
3886 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3887 ok(!r, "got %d\n", r);
3888
3889 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3890 expect(TRUE, r);
3891 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3892 expect(TRUE, r);
3893
3894 SetRect(&rect, -1, -1, -1, -1);
3895 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3896 expect(TRUE, r);
3897 /* left is set to (2e31-1) - XP SP2 */
3898 expect(0, rect.right);
3899 expect(0, rect.top);
3900 expect(0, rect.bottom);
3901
3902 /* switch to LVS_ICON */
3903 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
3904
3905 SetRect(&rect, -1, -1, -1, -1);
3906 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3907 expect(TRUE, r);
3908 expect(0, rect.left);
3909 expect(0, rect.top);
3910 /* precise value differs for 2k, XP and Vista */
3911 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3912 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3913
3914 DestroyWindow(hwnd);
3915 }
3916
3917 static void test_getitemposition(void)
3918 {
3919 HWND hwnd, header;
3920 DWORD r;
3921 POINT pt;
3922 RECT rect;
3923
3924 hwnd = create_listview_control(LVS_REPORT);
3925 ok(hwnd != NULL, "failed to create a listview window\n");
3926 header = subclass_header(hwnd);
3927
3928 /* LVS_REPORT, single item, no columns added */
3929 insert_item(hwnd, 0);
3930
3931 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3932
3933 pt.x = pt.y = -1;
3934 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3935 expect(TRUE, r);
3936 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3937
3938 /* LVS_REPORT, single item, single column */
3939 insert_column(hwnd, 0);
3940
3941 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3942
3943 pt.x = pt.y = -1;
3944 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3945 expect(TRUE, r);
3946 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3947
3948 SetRectEmpty(&rect);
3949 r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3950 ok(r, "got %d\n", r);
3951 /* some padding? */
3952 expect(2, pt.x);
3953 /* offset by header height */
3954 expect(rect.bottom - rect.top, pt.y);
3955
3956 DestroyWindow(hwnd);
3957 }
3958
3959 static void test_columnscreation(void)
3960 {
3961 HWND hwnd, header;
3962 DWORD r;
3963
3964 hwnd = create_listview_control(LVS_REPORT);
3965 ok(hwnd != NULL, "failed to create a listview window\n");
3966
3967 insert_item(hwnd, 0);
3968
3969 /* headers columns aren't created automatically */
3970 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3971 ok(IsWindow(header), "Expected header handle\n");
3972 r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
3973 expect(0, r);
3974
3975 DestroyWindow(hwnd);
3976 }
3977
3978 static void test_getitemrect(void)
3979 {
3980 HWND hwnd;
3981 HIMAGELIST himl, himl_ret;
3982 HBITMAP hbm;
3983 RECT rect;
3984 DWORD r;
3985 LVITEMA item;
3986 LVCOLUMNA col;
3987 INT order[2];
3988 POINT pt;
3989
3990 /* rectangle isn't empty for empty text items */
3991 hwnd = create_listview_control(LVS_LIST);
3992 memset(&item, 0, sizeof(item));
3993 item.mask = 0;
3994 item.iItem = 0;
3995 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3996 expect(0, r);
3997 rect.left = LVIR_LABEL;
3998 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3999 expect(TRUE, r);
4000 expect(0, rect.left);
4001 expect(0, rect.top);
4002 /* estimate it as width / height ratio */
4003 todo_wine
4004 ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom);
4005 DestroyWindow(hwnd);
4006
4007 hwnd = create_listview_control(LVS_REPORT);
4008 ok(hwnd != NULL, "failed to create a listview window\n");
4009
4010 /* empty item */
4011 memset(&item, 0, sizeof(item));
4012 item.iItem = 0;
4013 item.iSubItem = 0;
4014 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4015 expect(0, r);
4016
4017 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4018 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4019 expect(TRUE, r);
4020
4021 /* zero width rectangle with no padding */
4022 expect(0, rect.left);
4023 expect(0, rect.right);
4024
4025 insert_column(hwnd, 0);
4026 insert_column(hwnd, 1);
4027
4028 col.mask = LVCF_WIDTH;
4029 col.cx = 50;
4030 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
4031 expect(TRUE, r);
4032
4033 col.mask = LVCF_WIDTH;
4034 col.cx = 100;
4035 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
4036 expect(TRUE, r);
4037
4038 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4039 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4040 expect(TRUE, r);
4041
4042 /* still no left padding */
4043 expect(0, rect.left);
4044 expect(150, rect.right);
4045
4046 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4047 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4048 expect(TRUE, r);
4049 /* padding */
4050 expect(2, rect.left);
4051
4052 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4053 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4054 expect(TRUE, r);
4055 /* padding, column width */
4056 expect(2, rect.left);
4057 expect(50, rect.right);
4058
4059 /* no icons attached */
4060 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4061 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4062 expect(TRUE, r);
4063 /* padding */
4064 expect(2, rect.left);
4065 expect(2, rect.right);
4066
4067 /* change order */
4068 order[0] = 1; order[1] = 0;
4069 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4070 expect(TRUE, r);
4071 pt.x = -1;
4072 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4073 expect(TRUE, r);
4074 /* 1 indexed column width + padding */
4075 expect(102, pt.x);
4076 /* rect is at zero too */
4077 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4078 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4079 expect(TRUE, r);
4080 expect(0, rect.left);
4081 /* just width sum */
4082 expect(150, rect.right);
4083
4084 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4085 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4086 expect(TRUE, r);
4087 /* column width + padding */
4088 expect(102, rect.left);
4089
4090 /* back to initial order */
4091 order[0] = 0; order[1] = 1;
4092 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4093 expect(TRUE, r);
4094
4095 /* state icons */
4096 himl = pImageList_Create(16, 16, 0, 2, 2);
4097 ok(himl != NULL, "failed to create imagelist\n");
4098 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4099 ok(hbm != NULL, "failed to create bitmap\n");
4100 r = pImageList_Add(himl, hbm, 0);
4101 expect(0, r);
4102 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4103 ok(hbm != NULL, "failed to create bitmap\n");
4104 r = pImageList_Add(himl, hbm, 0);
4105 expect(1, r);
4106
4107 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4108 expect(0, r);
4109
4110 item.mask = LVIF_STATE;
4111 item.state = INDEXTOSTATEIMAGEMASK(1);
4112 item.stateMask = LVIS_STATEIMAGEMASK;
4113 item.iItem = 0;
4114 item.iSubItem = 0;
4115 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4116 expect(TRUE, r);
4117
4118 /* icon bounds */
4119 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4120 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4121 expect(TRUE, r);
4122 /* padding + stateicon width */
4123 expect(18, rect.left);
4124 expect(18, rect.right);
4125 /* label bounds */
4126 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4127 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4128 expect(TRUE, r);
4129 /* padding + stateicon width -> column width */
4130 expect(18, rect.left);
4131 expect(50, rect.right);
4132
4133 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4134 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4135
4136 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4137 expect(0, r);
4138
4139 item.mask = LVIF_STATE | LVIF_IMAGE;
4140 item.iImage = 1;
4141 item.state = 0;
4142 item.stateMask = ~0;
4143 item.iItem = 0;
4144 item.iSubItem = 0;
4145 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4146 expect(TRUE, r);
4147
4148 /* icon bounds */
4149 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4150 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4151 expect(TRUE, r);
4152 /* padding, icon width */
4153 expect(2, rect.left);
4154 expect(18, rect.right);
4155 /* label bounds */
4156 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4157 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4158 expect(TRUE, r);
4159 /* padding + icon width -> column width */
4160 expect(18, rect.left);
4161 expect(50, rect.right);
4162
4163 /* select bounds */
4164 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4165 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4166 expect(TRUE, r);
4167 /* padding, column width */
4168 expect(2, rect.left);
4169 expect(50, rect.right);
4170
4171 /* try with indentation */
4172 item.mask = LVIF_INDENT;
4173 item.iIndent = 1;
4174 item.iItem = 0;
4175 item.iSubItem = 0;
4176 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4177 expect(TRUE, r);
4178
4179 /* bounds */
4180 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4181 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4182 expect(TRUE, r);
4183 /* padding + 1 icon width, column width */
4184 expect(0, rect.left);
4185 expect(150, rect.right);
4186
4187 /* select bounds */
4188 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4189 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4190 expect(TRUE, r);
4191 /* padding + 1 icon width, column width */
4192 expect(2 + 16, rect.left);
4193 expect(50, rect.right);
4194
4195 /* label bounds */
4196 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4197 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4198 expect(TRUE, r);
4199 /* padding + 2 icon widths, column width */
4200 expect(2 + 16*2, rect.left);
4201 expect(50, rect.right);
4202
4203 /* icon bounds */
4204 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4205 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4206 expect(TRUE, r);
4207 /* padding + 1 icon width indentation, icon width */
4208 expect(2 + 16, rect.left);
4209 expect(34, rect.right);
4210
4211 DestroyWindow(hwnd);
4212 }
4213
4214 static void test_editbox(void)
4215 {
4216 static CHAR testitemA[] = "testitem";
4217 static CHAR testitem1A[] = "testitem_quitelongname";
4218 static CHAR testitem2A[] = "testITEM_quitelongname";
4219 static CHAR buffer[25];
4220 HWND hwnd, hwndedit, hwndedit2, header;
4221 LVITEMA item;
4222 INT r;
4223
4224 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4225 ok(hwnd != NULL, "failed to create a listview window\n");
4226
4227 insert_column(hwnd, 0);
4228
4229 memset(&item, 0, sizeof(item));
4230 item.mask = LVIF_TEXT;
4231 item.pszText = testitemA;
4232 item.iItem = 0;
4233 item.iSubItem = 0;
4234 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4235 expect(0, r);
4236
4237 /* test notifications without edit created */
4238 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4239 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4240 expect(0, r);
4241 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4242 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4243 /* same thing but with valid window */
4244 hwndedit = CreateWindowA(WC_EDITA, "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4245 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4246 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4247 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4248 expect(0, r);
4249 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4250 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4251 DestroyWindow(hwndedit);
4252
4253 /* setting focus is necessary */
4254 SetFocus(hwnd);
4255 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4256 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4257
4258 /* test children Z-order after Edit box created */
4259 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4260 ok(IsWindow(header), "Expected header to be created\n");
4261 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4262 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4263
4264 /* modify initial string */
4265 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4266 expect(TRUE, r);
4267
4268 /* edit window is resized and repositioned,
4269 check again for Z-order - it should be preserved */
4270 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4271 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4272
4273 /* return focus to listview */
4274 SetFocus(hwnd);
4275
4276 memset(&item, 0, sizeof(item));
4277 item.mask = LVIF_TEXT;
4278 item.pszText = buffer;
4279 item.cchTextMax = sizeof(buffer);
4280 item.iItem = 0;
4281 item.iSubItem = 0;
4282 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4283 expect(TRUE, r);
4284
4285 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4286
4287 /* send LVM_EDITLABEL on already created edit */
4288 SetFocus(hwnd);
4289 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4290 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4291 /* focus will be set to edit */
4292 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4293 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4294 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4295
4296 /* creating label disabled when control isn't focused */
4297 SetFocus(0);
4298 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4299 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4300
4301 /* check EN_KILLFOCUS handling */
4302 memset(&item, 0, sizeof(item));
4303 item.pszText = testitemA;
4304 item.iItem = 0;
4305 item.iSubItem = 0;
4306 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4307 expect(TRUE, r);
4308
4309 SetFocus(hwnd);
4310 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4311 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4312 /* modify edit and notify control that it lost focus */
4313 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4314 expect(TRUE, r);
4315 g_editbox_disp_info.item.pszText = NULL;
4316 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4317 expect(0, r);
4318 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4319
4320 memset(&item, 0, sizeof(item));
4321 item.pszText = buffer;
4322 item.cchTextMax = sizeof(buffer);
4323 item.iItem = 0;
4324 item.iSubItem = 0;
4325 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4326 expect(lstrlenA(item.pszText), r);
4327 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4328 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4329
4330 /* change item name to differ in casing only */
4331 SetFocus(hwnd);
4332 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4333 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4334 /* modify edit and notify control that it lost focus */
4335 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4336 expect(TRUE, r);
4337 g_editbox_disp_info.item.pszText = NULL;
4338 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4339 expect(0, r);
4340 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4341
4342 memset(&item, 0, sizeof(item));
4343 item.pszText = buffer;
4344 item.cchTextMax = sizeof(buffer);
4345 item.iItem = 0;
4346 item.iSubItem = 0;
4347 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4348 expect(lstrlenA(item.pszText), r);
4349 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4350 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4351
4352 /* end edit without saving */
4353 SetFocus(hwnd);
4354 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4355 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4356 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4357 expect(0, r);
4358 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4359 "edit box - end edit, no change, escape", TRUE);
4360 /* end edit with saving */
4361 SetFocus(hwnd);
4362 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4363 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4364 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4365 expect(0, r);
4366 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4367 "edit box - end edit, no change, return", TRUE);
4368
4369 memset(&item, 0, sizeof(item));
4370 item.pszText = buffer;
4371 item.cchTextMax = sizeof(buffer);
4372 item.iItem = 0;
4373 item.iSubItem = 0;
4374 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4375 expect(lstrlenA(item.pszText), r);
4376 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4377
4378 /* LVM_EDITLABEL with -1 destroys current edit */
4379 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4380 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4381 /* no edit present */
4382 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4383 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4384 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4385 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4386 /* edit present */
4387 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4388 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4389 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4390 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4391 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4392 /* check another negative value */
4393 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4394 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4395 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4396 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4397 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4398 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4399 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4400 /* and value greater than max item index */
4401 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4402 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4403 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4404 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4405 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4406 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4407 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4408 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4409
4410 /* messaging tests */
4411 SetFocus(hwnd);
4412 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4413 blockEdit = FALSE;
4414 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4415 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4416 /* testing only sizing messages */
4417 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4418 "edit box create - sizing", FALSE);
4419
4420 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4421 SetFocus(hwnd);
4422 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4423 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4424 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4425 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4426 expect(0, r);
4427 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4428 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4429
4430 DestroyWindow(hwnd);
4431 }
4432
4433 static void test_notifyformat(void)
4434 {
4435 HWND hwnd, header;
4436 DWORD r;
4437
4438 hwnd = create_listview_control(LVS_REPORT);
4439 ok(hwnd != NULL, "failed to create a listview window\n");
4440
4441 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4442 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4443 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4444 expect(0, r);
4445 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4446 /* set */
4447 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4448 expect(0, r);
4449 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4450 ok(r == 1, "Unexpected return value %d.\n", r);
4451 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4452 expect(1, r);
4453 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4454 expect(0, r);
4455
4456 DestroyWindow(hwnd);
4457
4458 /* test failure in parent WM_NOTIFYFORMAT */
4459 notifyFormat = 0;
4460 hwnd = create_listview_control(LVS_REPORT);
4461 ok(hwnd != NULL, "failed to create a listview window\n");
4462 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4463 ok(IsWindow(header), "expected header to be created\n");
4464 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4465 expect(0, r);
4466 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4467 ok( r == 1, "Expected 1, got %d\n", r );
4468 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4469 ok(r != 0, "Expected valid format\n");
4470
4471 notifyFormat = NFR_UNICODE;
4472 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4473 expect(NFR_UNICODE, r);
4474 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4475 expect(1, r);
4476 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4477 ok( r == 1, "Expected 1, got %d\n", r );
4478
4479 notifyFormat = NFR_ANSI;
4480 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4481 expect(NFR_ANSI, r);
4482 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4483 expect(0, r);
4484 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4485 ok( r == 1, "Expected 1, got %d\n", r );
4486
4487 DestroyWindow(hwnd);
4488
4489 hwndparentW = create_parent_window(TRUE);
4490 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4491 if (!IsWindow(hwndparentW)) return;
4492
4493 notifyFormat = -1;
4494 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4495 ok(hwnd != NULL, "failed to create a listview window\n");
4496 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4497 ok(IsWindow(header), "expected header to be created\n");
4498 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4499 expect(1, r);
4500 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4501 expect(1, r);
4502 DestroyWindow(hwnd);
4503 /* receiving error code defaulting to ansi */
4504 notifyFormat = 0;
4505 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4506 ok(hwnd != NULL, "failed to create a listview window\n");
4507 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4508 ok(IsWindow(header), "expected header to be created\n");
4509 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4510 expect(0, r);
4511 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4512 expect(1, r);
4513 DestroyWindow(hwnd);
4514 /* receiving ansi code from unicode window, use it */
4515 notifyFormat = NFR_ANSI;
4516 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4517 ok(hwnd != NULL, "failed to create a listview window\n");
4518 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4519 ok(IsWindow(header), "expected header to be created\n");
4520 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4521 expect(0, r);
4522 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4523 expect(1, r);
4524 DestroyWindow(hwnd);
4525 /* unicode listview with ansi parent window */
4526 notifyFormat = -1;
4527 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4528 ok(hwnd != NULL, "failed to create a listview window\n");
4529 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4530 ok(IsWindow(header), "expected header to be created\n");
4531 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4532 expect(0, r);
4533 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4534 expect(1, r);
4535 DestroyWindow(hwnd);
4536 /* unicode listview with ansi parent window, return error code */
4537 notifyFormat = 0;
4538 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4539 ok(hwnd != NULL, "failed to create a listview window\n");
4540 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4541 ok(IsWindow(header), "expected header to be created\n");
4542 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4543 expect(0, r);
4544 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4545 expect(1, r);
4546 DestroyWindow(hwnd);
4547
4548 DestroyWindow(hwndparentW);
4549 }
4550
4551 static void test_indentation(void)
4552 {
4553 HWND hwnd;
4554 LVITEMA item;
4555 DWORD r;
4556
4557 hwnd = create_listview_control(LVS_REPORT);
4558 ok(hwnd != NULL, "failed to create a listview window\n");
4559
4560 memset(&item, 0, sizeof(item));
4561 item.mask = LVIF_INDENT;
4562 item.iItem = 0;
4563 item.iIndent = I_INDENTCALLBACK;
4564 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4565 expect(0, r);
4566
4567 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4568
4569 item.iItem = 0;
4570 item.mask = LVIF_INDENT;
4571 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4572 expect(TRUE, r);
4573
4574 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4575 "get indent dispinfo", FALSE);
4576
4577 DestroyWindow(hwnd);
4578 }
4579
4580 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4581 {
4582 return 0;
4583 }
4584
4585 static BOOL is_below_comctl_5(void)
4586 {
4587 HWND hwnd;
4588 BOOL ret;
4589
4590 hwnd = create_listview_control(LVS_REPORT);
4591 ok(hwnd != NULL, "failed to create a listview window\n");
4592 insert_item(hwnd, 0);
4593
4594 ret = SendMessageA(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4595
4596 DestroyWindow(hwnd);
4597
4598 return !ret;
4599 }
4600
4601 static void test_get_set_view(void)
4602 {
4603 HWND hwnd;
4604 DWORD ret;
4605 DWORD_PTR style;
4606
4607 /* test style->view mapping */
4608 hwnd = create_listview_control(LVS_REPORT);
4609 ok(hwnd != NULL, "failed to create a listview window\n");
4610
4611 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4612 expect(LV_VIEW_DETAILS, ret);
4613
4614 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4615 /* LVS_ICON == 0 */
4616 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4617 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4618 expect(LV_VIEW_ICON, ret);
4619
4620 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4621 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4622 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4623 expect(LV_VIEW_SMALLICON, ret);
4624
4625 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4626 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4627 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4628 expect(LV_VIEW_LIST, ret);
4629
4630 /* switching view doesn't touch window style */
4631 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4632 expect(1, ret);
4633 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4634 ok(style & LVS_LIST, "Expected style to be preserved\n");
4635 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4636 expect(1, ret);
4637 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4638 ok(style & LVS_LIST, "Expected style to be preserved\n");
4639 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4640 expect(1, ret);
4641 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4642 ok(style & LVS_LIST, "Expected style to be preserved\n");
4643
4644 /* now change window style to see if view is remapped */
4645 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4646 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4647 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4648 expect(LV_VIEW_SMALLICON, ret);
4649
4650 DestroyWindow(hwnd);
4651 }
4652
4653 static void test_canceleditlabel(void)
4654 {
4655 HWND hwnd, hwndedit;
4656 DWORD ret;
4657 CHAR buff[10];
4658 LVITEMA itema;
4659 static CHAR test[] = "test";
4660 static const CHAR test1[] = "test1";
4661
4662 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4663 ok(hwnd != NULL, "failed to create a listview window\n");
4664
4665 insert_item(hwnd, 0);
4666
4667 /* try without edit created */
4668 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4669 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4670 expect(TRUE, ret);
4671 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4672 "cancel edit label without edit", FALSE);
4673
4674 /* cancel without data change */
4675 SetFocus(hwnd);
4676 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4677 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4678 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4679 expect(TRUE, ret);
4680 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4681
4682 /* cancel after data change */
4683 memset(&itema, 0, sizeof(itema));
4684 itema.pszText = test;
4685 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4686 expect(TRUE, ret);
4687 SetFocus(hwnd);
4688 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4689 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4690 ret = SetWindowTextA(hwndedit, test1);
4691 expect(1, ret);
4692 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4693 expect(TRUE, ret);
4694 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4695 memset(&itema, 0, sizeof(itema));
4696 itema.pszText = buff;
4697 itema.cchTextMax = ARRAY_SIZE(buff);
4698 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4699 expect(5, ret);
4700 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4701
4702 DestroyWindow(hwnd);
4703 }
4704
4705 static void test_mapidindex(void)
4706 {
4707 HWND hwnd;
4708 INT ret;
4709
4710 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4711 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4712 ok(hwnd != NULL, "failed to create a listview window\n");
4713 insert_item(hwnd, 0);
4714 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4715 expect(-1, ret);
4716 DestroyWindow(hwnd);
4717
4718 hwnd = create_listview_control(LVS_REPORT);
4719 ok(hwnd != NULL, "failed to create a listview window\n");
4720
4721 /* LVM_MAPINDEXTOID with invalid index */
4722 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4723 expect(-1, ret);
4724
4725 insert_item(hwnd, 0);
4726 insert_item(hwnd, 1);
4727
4728 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4729 expect(-1, ret);
4730 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4731 expect(-1, ret);
4732
4733 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4734 expect(0, ret);
4735 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4736 expect(1, ret);
4737 /* remove 0 indexed item, id retained */
4738 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4739 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4740 expect(1, ret);
4741 /* new id starts from previous value */
4742 insert_item(hwnd, 1);
4743 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4744 expect(2, ret);
4745
4746 /* get index by id */
4747 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4748 expect(-1, ret);
4749 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4750 expect(-1, ret);
4751 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4752 expect(0, ret);
4753 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4754 expect(1, ret);
4755
4756 DestroyWindow(hwnd);
4757 }
4758
4759 static void test_getitemspacing(void)
4760 {
4761 HWND hwnd;
4762 DWORD ret;
4763 INT cx, cy;
4764 HIMAGELIST himl40, himl80;
4765
4766 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4767 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4768
4769 /* LVS_ICON */
4770 hwnd = create_listview_control(LVS_ICON);
4771 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4772 expect(cx, LOWORD(ret));
4773 expect(cy, HIWORD(ret));
4774
4775 /* now try with icons */
4776 himl40 = pImageList_Create(40, 40, 0, 4, 4);
4777 ok(himl40 != NULL, "failed to create imagelist\n");
4778 himl80 = pImageList_Create(80, 80, 0, 4, 4);
4779 ok(himl80 != NULL, "failed to create imagelist\n");
4780 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4781 expect(0, ret);
4782
4783 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4784 /* spacing + icon size returned */
4785 expect(cx + 40, LOWORD(ret));
4786 expect(cy + 40, HIWORD(ret));
4787 /* try changing icon size */
4788 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4789
4790 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4791 /* spacing + icon size returned */
4792 expect(cx + 80, LOWORD(ret));
4793 expect(cy + 80, HIWORD(ret));
4794
4795 /* set own icon spacing */
4796 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4797 expect(cx + 80, LOWORD(ret));
4798 expect(cy + 80, HIWORD(ret));
4799
4800 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4801 /* set size returned */
4802 expect(100, LOWORD(ret));
4803 expect(100, HIWORD(ret));
4804
4805 /* now change image list - icon spacing should be unaffected */
4806 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4807
4808 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4809 /* set size returned */
4810 expect(100, LOWORD(ret));
4811 expect(100, HIWORD(ret));
4812
4813 /* spacing = 0 - keep previous value */
4814 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4815 expect(100, LOWORD(ret));
4816 expect(100, HIWORD(ret));
4817
4818 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4819 expect(100, LOWORD(ret));
4820
4821 expect(0xFFFF, HIWORD(ret));
4822
4823 if (sizeof(void*) == 8)
4824 {
4825 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4826 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4827 expect(100, LOWORD(ret));
4828 expect(0xFFFF, HIWORD(ret));
4829
4830 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4831 expect(0xFFFF, LOWORD(ret));
4832 expect(0xFFFF, HIWORD(ret));
4833 }
4834 else
4835 {
4836 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4837 expect(100, LOWORD(ret));
4838 expect(0xFFFF, HIWORD(ret));
4839 }
4840 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4841 /* spacing + icon size returned */
4842 expect(cx + 40, LOWORD(ret));
4843 expect(cy + 40, HIWORD(ret));
4844
4845 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4846 pImageList_Destroy(himl80);
4847 DestroyWindow(hwnd);
4848 /* LVS_SMALLICON */
4849 hwnd = create_listview_control(LVS_SMALLICON);
4850 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4851 expect(cx, LOWORD(ret));
4852 expect(cy, HIWORD(ret));
4853
4854 /* spacing does not depend on selected view type */
4855 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4856 expect(0, ret);
4857
4858 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4859 /* spacing + icon size returned */
4860 expect(cx + 40, LOWORD(ret));
4861 expect(cy + 40, HIWORD(ret));
4862
4863 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4864 pImageList_Destroy(himl40);
4865 DestroyWindow(hwnd);
4866 /* LVS_REPORT */
4867 hwnd = create_listview_control(LVS_REPORT);
4868 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4869 expect(cx, LOWORD(ret));
4870 expect(cy, HIWORD(ret));
4871
4872 DestroyWindow(hwnd);
4873 /* LVS_LIST */
4874 hwnd = create_listview_control(LVS_LIST);
4875 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4876 expect(cx, LOWORD(ret));
4877 expect(cy, HIWORD(ret));
4878
4879 DestroyWindow(hwnd);
4880 }
4881
4882 static INT get_current_font_height(HWND listview)
4883 {
4884 TEXTMETRICA tm;
4885 HFONT hfont;
4886 HWND hwnd;
4887 HDC hdc;
4888
4889 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
4890 if (!hwnd)
4891 hwnd = listview;
4892
4893 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
4894 if (!hfont) {
4895 hdc = GetDC(hwnd);
4896 GetTextMetricsA(hdc, &tm);
4897 ReleaseDC(hwnd, hdc);
4898 }
4899 else {
4900 HFONT oldfont;
4901
4902 hdc = GetDC(0);
4903 oldfont = SelectObject(hdc, hfont);
4904 GetTextMetricsA(hdc, &tm);
4905 SelectObject(hdc, oldfont);
4906 ReleaseDC(0, hdc);
4907 }
4908
4909 return tm.tmHeight;
4910 }
4911
4912 static void test_getcolumnwidth(void)
4913 {
4914 HWND hwnd;
4915 INT ret;
4916 DWORD_PTR style;
4917 LVCOLUMNA col;
4918 LVITEMA itema;
4919 INT height;
4920
4921 /* default column width */
4922 hwnd = create_listview_control(LVS_ICON);
4923 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4924 expect(0, ret);
4925 style = GetWindowLongA(hwnd, GWL_STYLE);
4926 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
4927 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4928 todo_wine expect(8, ret);
4929 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
4930 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
4931 col.mask = 0;
4932 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4933 expect(0, ret);
4934 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4935 expect(10, ret);
4936 DestroyWindow(hwnd);
4937
4938 /* default column width with item added */
4939 hwnd = create_listview_control(LVS_LIST);
4940 memset(&itema, 0, sizeof(itema));
4941 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4942 ok(!ret, "got %d\n", ret);
4943 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4944 height = get_current_font_height(hwnd);
4945 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
4946 DestroyWindow(hwnd);
4947 }
4948
4949 static void test_scrollnotify(void)
4950 {
4951 HWND hwnd;
4952 DWORD ret;
4953
4954 hwnd = create_listview_control(LVS_REPORT);
4955
4956 insert_column(hwnd, 0);
4957 insert_column(hwnd, 1);
4958 insert_item(hwnd, 0);
4959
4960 /* make it scrollable - resize */
4961 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4962 expect(TRUE, ret);
4963 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4964 expect(TRUE, ret);
4965
4966 /* try with dummy call */
4967 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4968 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
4969 expect(TRUE, ret);
4970 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4971 "scroll notify 1", TRUE);
4972
4973 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4974 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
4975 expect(TRUE, ret);
4976 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4977 "scroll notify 2", TRUE);
4978
4979 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4980 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
4981 expect(TRUE, ret);
4982 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4983 "scroll notify 3", TRUE);
4984
4985 DestroyWindow(hwnd);
4986 }
4987
4988 static void test_LVS_EX_TRANSPARENTBKGND(void)
4989 {
4990 HWND hwnd;
4991 DWORD ret;
4992 HDC hdc;
4993
4994 hwnd = create_listview_control(LVS_REPORT);
4995
4996 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4997 expect(TRUE, ret);
4998
4999 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5000 LVS_EX_TRANSPARENTBKGND);
5001
5002 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
5003 if (ret != CLR_NONE)
5004 {
5005 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
5006 DestroyWindow(hwnd);
5007 return;
5008 }
5009
5010 /* try to set some back color and check this style bit */
5011 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5012 expect(TRUE, ret);
5013 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
5014 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
5015
5016 /* now test what this style actually does */
5017 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5018 LVS_EX_TRANSPARENTBKGND);
5019
5020 hdc = GetWindowDC(hwndparent);
5021
5022 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5023 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
5024 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
5025 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
5026
5027 ReleaseDC(hwndparent, hdc);
5028
5029 DestroyWindow(hwnd);
5030 }
5031
5032 static void test_approximate_viewrect(void)
5033 {
5034 static CHAR test[] = "abracadabra, a very long item label";
5035 DWORD item_width, item_height, header_height;
5036 static CHAR column_header[] = "Header";
5037 unsigned const column_width = 100;
5038 DWORD ret, item_count;
5039 HIMAGELIST himl;
5040 LVITEMA itema;
5041 LVCOLUMNA col;
5042 HBITMAP hbmp;
5043 HWND hwnd;
5044
5045 /* LVS_ICON */
5046 hwnd = create_listview_control(LVS_ICON);
5047 himl = pImageList_Create(40, 40, 0, 4, 4);
5048 ok(himl != NULL, "failed to create imagelist\n");
5049 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
5050 ok(hbmp != NULL, "failed to create bitmap\n");
5051 ret = pImageList_Add(himl, hbmp, 0);
5052 expect(0, ret);
5053 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
5054 expect(0, ret);
5055
5056 itema.mask = LVIF_IMAGE;
5057 itema.iImage = 0;
5058 itema.iItem = 0;
5059 itema.iSubItem = 0;
5060 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5061 expect(0, ret);
5062
5063 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
5064 ok(ret != 0, "Unexpected return value %#x.\n", ret);
5065
5066 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5067 expect(MAKELONG(77,827), ret);
5068
5069 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5070 ok(ret != 0, "got 0\n");
5071
5072 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5073 expect(MAKELONG(102,302), ret);
5074
5075 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5076 expect(MAKELONG(52,52), ret);
5077
5078 itema.pszText = test;
5079 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5080 expect(TRUE, ret);
5081 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5082 expect(MAKELONG(52,52), ret);
5083
5084 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5085 expect(MAKELONG(52,2), ret);
5086 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5087 expect(MAKELONG(52,52), ret);
5088 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5089 expect(MAKELONG(102,52), ret);
5090 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5091 expect(MAKELONG(102,102), ret);
5092 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5093 expect(MAKELONG(102,102), ret);
5094 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5095 expect(MAKELONG(102,152), ret);
5096 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5097 expect(MAKELONG(102,152), ret);
5098 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5099 expect(MAKELONG(152,152), ret);
5100
5101 DestroyWindow(hwnd);
5102
5103 /* LVS_REPORT */
5104 hwnd = create_listview_control(LVS_REPORT);
5105
5106 /* Empty control without columns */
5107 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
5108 todo_wine
5109 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5110 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5111
5112 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5113 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5114 todo_wine
5115 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5116
5117 header_height = HIWORD(ret);
5118
5119 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5120 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5121 todo_wine
5122 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5123
5124 item_height = HIWORD(ret) - header_height;
5125
5126 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5127 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5128 ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;
5129
5130 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5131 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5132 ok(HIWORD(ret) == header_height, "Unexpected height.\n");
5133 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5134 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5135 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5136
5137 /* Insert column */
5138 col.mask = LVCF_TEXT | LVCF_WIDTH;
5139 col.pszText = column_header;
5140 col.cx = column_width;
5141 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5142 ok(ret == 0, "Unexpected return value %d.\n", ret);
5143
5144 /* Empty control with column */
5145 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5146 todo_wine {
5147 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5148 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5149 }
5150 header_height = HIWORD(ret);
5151 item_width = LOWORD(ret);
5152
5153 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5154 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5155 todo_wine
5156 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5157
5158 item_height = HIWORD(ret) - header_height;
5159
5160 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5161 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5162 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5163
5164 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5165 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5166 ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));
5167
5168 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5169 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5170 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5171
5172 for (item_count = 1; item_count <= 2; ++item_count)
5173 {
5174 itema.mask = LVIF_TEXT;
5175 itema.iItem = 0;
5176 itema.iSubItem = 0;
5177 itema.pszText = test;
5178 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5179 ok(ret == 0, "Unexpected return value %d.\n", ret);
5180
5181 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5182 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5183 todo_wine
5184 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5185
5186 header_height = HIWORD(ret);
5187 item_width = LOWORD(ret);
5188
5189 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5190 ok(LOWORD(ret) == item_width, "Unexpected width %d, item %d\n", LOWORD(ret), item_count - 1);
5191 ok(HIWORD(ret) > header_height, "Unexpected height %d. item %d.\n", HIWORD(ret), item_count - 1);
5192
5193 item_height = HIWORD(ret) - header_height;
5194
5195 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5196 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5197 todo_wine
5198 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5199
5200 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5201 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5202 ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));
5203
5204 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5205 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5206 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5207
5208 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
5209 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5210 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5211
5212 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
5213 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5214 todo_wine
5215 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5216
5217 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
5218 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5219 todo_wine
5220 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5221 }
5222
5223 DestroyWindow(hwnd);
5224
5225 }
5226
5227 static void test_finditem(void)
5228 {
5229 LVFINDINFOA fi;
5230 static char f[5];
5231 HWND hwnd;
5232 INT r;
5233
5234 hwnd = create_listview_control(LVS_REPORT);
5235 insert_item(hwnd, 0);
5236
5237 memset(&fi, 0, sizeof(fi));
5238
5239 /* full string search, inserted text was "foo" */
5240 strcpy(f, "foo");
5241 fi.flags = LVFI_STRING;
5242 fi.psz = f;
5243 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5244 expect(0, r);
5245
5246 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5247 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5248 expect(0, r);
5249
5250 fi.flags = LVFI_PARTIAL;
5251 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5252 expect(0, r);
5253
5254 /* partial string search, inserted text was "foo" */
5255 strcpy(f, "fo");
5256 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5257 fi.psz = f;
5258 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5259 expect(0, r);
5260
5261 fi.flags = LVFI_STRING;
5262 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5263 expect(-1, r);
5264
5265 fi.flags = LVFI_PARTIAL;
5266 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5267 expect(0, r);
5268
5269 /* partial string search, part after start char */
5270 strcpy(f, "oo");
5271 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5272 fi.psz = f;
5273 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5274 expect(-1, r);
5275
5276 /* try with LVFI_SUBSTRING */
5277 strcpy(f, "fo");
5278 fi.flags = LVFI_SUBSTRING;
5279 fi.psz = f;
5280 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5281 expect(0, r);
5282 strcpy(f, "f");
5283 fi.flags = LVFI_SUBSTRING;
5284 fi.psz = f;
5285 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5286 expect(0, r);
5287 strcpy(f, "o");
5288 fi.flags = LVFI_SUBSTRING;
5289 fi.psz = f;
5290 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5291 expect(-1, r);
5292
5293 strcpy(f, "o");
5294 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5295 fi.psz = f;
5296 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5297 expect(-1, r);
5298
5299 strcpy(f, "f");
5300 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5301 fi.psz = f;
5302 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5303 expect(0, r);
5304
5305 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5306 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5307 expect(0, r);
5308
5309 DestroyWindow(hwnd);
5310 }
5311
5312 static void test_LVS_EX_HEADERINALLVIEWS(void)
5313 {
5314 HWND hwnd, header;
5315 DWORD style;
5316
5317 hwnd = create_listview_control(LVS_ICON);
5318
5319 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5320 LVS_EX_HEADERINALLVIEWS);
5321
5322 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5323 if (!IsWindow(header))
5324 {
5325 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5326 DestroyWindow(hwnd);
5327 return;
5328 }
5329
5330 /* LVS_NOCOLUMNHEADER works as before */
5331 style = GetWindowLongA(hwnd, GWL_STYLE);
5332 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5333 style = GetWindowLongA(header, GWL_STYLE);
5334 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5335 style = GetWindowLongA(hwnd, GWL_STYLE);
5336 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5337 style = GetWindowLongA(header, GWL_STYLE);
5338 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5339
5340 /* try to remove style */
5341 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5342 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5343 ok(IsWindow(header), "Expected header to be created\n");
5344 style = GetWindowLongA(header, GWL_STYLE);
5345 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5346
5347 DestroyWindow(hwnd);
5348
5349 /* check other styles */
5350 hwnd = create_listview_control(LVS_LIST);
5351 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5352 LVS_EX_HEADERINALLVIEWS);
5353 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5354 ok(IsWindow(header), "Expected header to be created\n");
5355 DestroyWindow(hwnd);
5356
5357 hwnd = create_listview_control(LVS_SMALLICON);
5358 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5359 LVS_EX_HEADERINALLVIEWS);
5360 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5361 ok(IsWindow(header), "Expected header to be created\n");
5362 DestroyWindow(hwnd);
5363
5364 hwnd = create_listview_control(LVS_REPORT);
5365 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5366 LVS_EX_HEADERINALLVIEWS);
5367 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5368 ok(IsWindow(header), "Expected header to be created\n");
5369 DestroyWindow(hwnd);
5370 }
5371
5372 static void test_hover(void)
5373 {
5374 HWND hwnd, fg;
5375 DWORD r;
5376
5377 hwnd = create_listview_control(LVS_ICON);
5378 SetForegroundWindow(hwndparent);
5379 fg = GetForegroundWindow();
5380 if (fg != hwndparent)
5381 {
5382 skip("Window is not in the foreground. Skipping hover tests.\n");
5383 DestroyWindow(hwnd);
5384 return;
5385 }
5386
5387 /* test WM_MOUSEHOVER forwarding */
5388 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5389 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5390 expect(0, r);
5391 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5392 g_block_hover = TRUE;
5393 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5394 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5395 expect(0, r);
5396 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5397 g_block_hover = FALSE;
5398
5399 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5400 expect(HOVER_DEFAULT, r);
5401 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5402 expect(500, r);
5403
5404 DestroyWindow(hwnd);
5405 }
5406
5407 static void test_destroynotify(void)
5408 {
5409 HWND hwnd;
5410 BOOL ret;
5411
5412 hwnd = create_listview_control(LVS_REPORT);
5413 ok(hwnd != NULL, "failed to create listview window\n");
5414
5415 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5416 DestroyWindow(hwnd);
5417 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5418
5419 /* same for ownerdata list */
5420 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5421 ok(hwnd != NULL, "failed to create listview window\n");
5422
5423 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5424 DestroyWindow(hwnd);
5425 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5426
5427 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5428 ok(hwnd != NULL, "failed to create listview window\n");
5429
5430 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5431 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5432 ok(ret == TRUE, "got %d\n", ret);
5433 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5434 DestroyWindow(hwnd);
5435 }
5436
5437 static void test_header_notification(void)
5438 {
5439 static char textA[] = "newtext";
5440 HWND list, header;
5441 HDITEMA item;
5442 NMHEADERA nmh;
5443 LVCOLUMNA col;
5444 DWORD ret;
5445 BOOL r;
5446
5447 list = create_listview_control(LVS_REPORT);
5448 ok(list != NULL, "failed to create listview window\n");
5449
5450 memset(&col, 0, sizeof(col));
5451 col.mask = LVCF_WIDTH;
5452 col.cx = 100;
5453 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5454 expect(0, ret);
5455
5456 /* check list parent notification after header item changed,
5457 this test should be placed before header subclassing to avoid
5458 Listview -> Header messages to be logged */
5459 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5460
5461 col.mask = LVCF_TEXT;
5462 col.pszText = textA;
5463 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5464 expect(TRUE, r);
5465
5466 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5467 "header notify, listview", FALSE);
5468 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5469 "header notify, parent", FALSE);
5470
5471 header = subclass_header(list);
5472
5473 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5474 expect(1, ret);
5475
5476 memset(&item, 0, sizeof(item));
5477 item.mask = HDI_WIDTH;
5478 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5479 expect(1, ret);
5480 expect(100, item.cxy);
5481
5482 nmh.hdr.hwndFrom = header;
5483 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5484 nmh.hdr.code = HDN_ITEMCHANGEDA;
5485 nmh.iItem = 0;
5486 nmh.iButton = 0;
5487 item.mask = HDI_WIDTH;
5488 item.cxy = 50;
5489 nmh.pitem = &item;
5490 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5491 expect(0, ret);
5492
5493 DestroyWindow(list);
5494 }
5495
5496 static void test_header_notification2(void)
5497 {
5498 static char textA[] = "newtext";
5499 HWND list, header;
5500 HDITEMW itemW;
5501 NMHEADERW nmhdr;
5502 LVCOLUMNA col;
5503 DWORD ret;
5504 WCHAR buffer[100];
5505 struct message parent_header_notify_seq[] = {
5506 { WM_NOTIFY, sent|id, 0, 0, 0 },
5507 { 0 }
5508 };
5509
5510 list = create_listview_control(LVS_REPORT);
5511 ok(list != NULL, "failed to create listview window\n");
5512
5513 memset(&col, 0, sizeof(col));
5514 col.mask = LVCF_WIDTH | LVCF_TEXT;
5515 col.cx = 100;
5516 col.pszText = textA;
5517 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5518 expect(0, ret);
5519
5520 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5521 ok(header != 0, "No header\n");
5522 memset(&itemW, 0, sizeof(itemW));
5523 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5524 itemW.pszText = buffer;
5525 itemW.cchTextMax = ARRAY_SIZE(buffer);
5526 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5527 expect(1, ret);
5528
5529 nmhdr.hdr.hwndFrom = header;
5530 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5531 nmhdr.iItem = 0;
5532 nmhdr.iButton = 0;
5533 nmhdr.pitem = &itemW;
5534
5535 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5536 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5537 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5538 ok(ret == 0, "got %d\n", ret);
5539 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5540 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5541 "header notify, parent", TRUE);
5542 todo_wine
5543 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5544 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5545 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5546 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5547 ok(ret == 0, "got %d\n", ret);
5548 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5549 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5550 "header notify, parent", TRUE);
5551 todo_wine
5552 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5553 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5554 SetFocus(list);
5555 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5556 nmhdr.hdr.code = HDN_ITEMCLICKW;
5557 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5558 ok(ret == 0, "got %d\n", ret);
5559 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5560 "header notify, parent", FALSE);
5561 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5562 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5563 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5564 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5565 ok(ret == 0, "got %d\n", ret);
5566 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5567 "header notify, parent", FALSE);
5568 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5569 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5570 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5571 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5572 ok(ret == 0, "got %d\n", ret);
5573 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5574 "header notify, parent", TRUE);
5575 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5576 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5577 nmhdr.hdr.code = HDN_BEGINTRACKW;
5578 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5579 ok(ret == 0, "got %d\n", ret);
5580 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5581 "header notify, parent", FALSE);
5582 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5583 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5584 nmhdr.hdr.code = HDN_ENDTRACKW;
5585 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5586 ok(ret == 0, "got %d\n", ret);
5587 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5588 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5589 "header notify, parent", FALSE);
5590 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5591 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5592 nmhdr.hdr.code = HDN_TRACKW;
5593 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5594 ok(ret == 0, "got %d\n", ret);
5595 parent_header_notify_seq[0].id = HDN_TRACKA;
5596 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5597 "header notify, parent", FALSE);
5598 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5599 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5600 nmhdr.hdr.code = HDN_BEGINDRAG;
5601 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5602 ok(ret == 1, "got %d\n", ret);
5603 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5604 "header notify, parent", FALSE);
5605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5606 nmhdr.hdr.code = HDN_ENDDRAG;
5607 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5608 ok(ret == 0, "got %d\n", ret);
5609 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5610 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5611 "header notify, parent", FALSE);
5612 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5613 nmhdr.hdr.code = HDN_FILTERCHANGE;
5614 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5615 ok(ret == 0, "got %d\n", ret);
5616 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5617 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5618 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5619 "header notify, parent", FALSE);
5620 parent_header_notify_seq[0].flags &= ~optional;
5621 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5622 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5623 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5624 ok(ret == 0, "got %d\n", ret);
5625 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5626 "header notify, parent", FALSE);
5627 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5628 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5629 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5630 ok(ret == 0, "got %d\n", ret);
5631 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5632 "header notify, parent", FALSE);
5633 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5634 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5635 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5636 ok(ret == 0, "got %d\n", ret);
5637 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5638 "header notify, parent", FALSE);
5639 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5640 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5641 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5642 ok(ret == 0, "got %d\n", ret);
5643 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5644 "header notify, parent", FALSE);
5645
5646 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5647
5648 DestroyWindow(list);
5649 }
5650
5651 static void test_createdragimage(void)
5652 {
5653 HIMAGELIST himl;
5654 POINT pt;
5655 HWND list;
5656
5657 list = create_listview_control(LVS_ICON);
5658 ok(list != NULL, "failed to create listview window\n");
5659
5660 insert_item(list, 0);
5661
5662 /* NULL point */
5663 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5664 ok(himl == NULL, "got %p\n", himl);
5665
5666 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5667 ok(himl != NULL, "got %p\n", himl);
5668 pImageList_Destroy(himl);
5669
5670 DestroyWindow(list);
5671 }
5672
5673 static void test_dispinfo(void)
5674 {
5675 static const char testA[] = "TEST";
5676 WCHAR buff[10];
5677 LVITEMA item;
5678 HWND hwnd;
5679 DWORD ret;
5680
5681 hwnd = create_listview_control(LVS_ICON);
5682 ok(hwnd != NULL, "failed to create listview window\n");
5683
5684 insert_item(hwnd, 0);
5685
5686 memset(&item, 0, sizeof(item));
5687 item.pszText = LPSTR_TEXTCALLBACKA;
5688 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5689 expect(1, ret);
5690
5691 g_disp_A_to_W = TRUE;
5692 item.pszText = (char*)buff;
5693 item.cchTextMax = ARRAY_SIZE(buff);
5694 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5695 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5696 g_disp_A_to_W = FALSE;
5697
5698 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5699 "got %s, expected %s\n", item.pszText, testA);
5700
5701 DestroyWindow(hwnd);
5702 }
5703
5704 static void test_LVM_SETITEMTEXT(void)
5705 {
5706 static char testA[] = "TEST";
5707 LVITEMA item;
5708 HWND hwnd;
5709 DWORD ret;
5710
5711 hwnd = create_listview_control(LVS_ICON);
5712 ok(hwnd != NULL, "failed to create listview window\n");
5713
5714 insert_item(hwnd, 0);
5715
5716 /* null item pointer */
5717 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5718 expect(FALSE, ret);
5719
5720 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5721 expect(FALSE, ret);
5722
5723 /* index out of bounds */
5724 item.pszText = testA;
5725 item.cchTextMax = 0; /* ignored */
5726 item.iSubItem = 0;
5727
5728 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5729 expect(FALSE, ret);
5730
5731 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5732 expect(FALSE, ret);
5733
5734 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5735 expect(TRUE, ret);
5736
5737 DestroyWindow(hwnd);
5738 }
5739
5740 static void test_LVM_REDRAWITEMS(void)
5741 {
5742 HWND list;
5743 DWORD ret;
5744
5745 list = create_listview_control(LVS_ICON);
5746 ok(list != NULL, "failed to create listview window\n");
5747
5748 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5749 expect(TRUE, ret);
5750
5751 insert_item(list, 0);
5752
5753 ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
5754 expect(TRUE, ret);
5755
5756 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
5757 expect(TRUE, ret);
5758
5759 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5760 expect(TRUE, ret);
5761
5762 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
5763 expect(TRUE, ret);
5764
5765 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
5766 expect(TRUE, ret);
5767
5768 ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
5769 expect(TRUE, ret);
5770
5771 ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
5772 expect(TRUE, ret);
5773
5774 DestroyWindow(list);
5775 }
5776
5777 static void test_imagelists(void)
5778 {
5779 HWND hwnd, header;
5780 HIMAGELIST himl1, himl2, himl3;
5781 LRESULT ret;
5782
5783 himl1 = pImageList_Create(40, 40, 0, 4, 4);
5784 himl2 = pImageList_Create(40, 40, 0, 4, 4);
5785 himl3 = pImageList_Create(40, 40, 0, 4, 4);
5786 ok(himl1 != NULL, "Failed to create imagelist\n");
5787 ok(himl2 != NULL, "Failed to create imagelist\n");
5788 ok(himl3 != NULL, "Failed to create imagelist\n");
5789
5790 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5791 header = subclass_header(hwnd);
5792
5793 ok(header != NULL, "Expected header\n");
5794 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5795 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5796
5797 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5798
5799 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5800 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5801 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5802 "set normal image list", FALSE);
5803
5804 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5805
5806 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5807 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5808 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5809 "set state image list", TRUE);
5810
5811 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5812 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5813
5814 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5815
5816 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5817 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5818 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5819 "set small image list", FALSE);
5820
5821 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5822 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5823 DestroyWindow(hwnd);
5824
5825 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5826
5827 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5828
5829 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5830 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5831 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5832 "set normal image list", FALSE);
5833
5834 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5835
5836 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5837 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5838 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5839 "set state image list", FALSE);
5840
5841 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5842
5843 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5844 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5845 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5846 "set small image list", FALSE);
5847
5848 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5849 ok(header == NULL, "Expected no header, got %p\n", header);
5850
5851 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
5852
5853 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5854 ok(header != NULL, "Expected header, got NULL\n");
5855
5856 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5857 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5858
5859 DestroyWindow(hwnd);
5860 }
5861
5862 static void test_deleteitem(void)
5863 {
5864 LVITEMA item;
5865 UINT state;
5866 HWND hwnd;
5867 BOOL ret;
5868
5869 hwnd = create_listview_control(LVS_REPORT);
5870
5871 insert_item(hwnd, 0);
5872 insert_item(hwnd, 0);
5873 insert_item(hwnd, 0);
5874 insert_item(hwnd, 0);
5875 insert_item(hwnd, 0);
5876
5877 g_focus_test_LVN_DELETEITEM = TRUE;
5878
5879 /* delete focused item (not the last index) */
5880 item.stateMask = LVIS_FOCUSED;
5881 item.state = LVIS_FOCUSED;
5882 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5883 ok(ret == TRUE, "got %d\n", ret);
5884 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5885 ok(ret == TRUE, "got %d\n", ret);
5886 /* next item gets focus */
5887 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5888 ok(state == LVIS_FOCUSED, "got %x\n", state);
5889
5890 /* focus last item and delete it */
5891 item.stateMask = LVIS_FOCUSED;
5892 item.state = LVIS_FOCUSED;
5893 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5894 ok(ret == TRUE, "got %d\n", ret);
5895 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5896 ok(ret == TRUE, "got %d\n", ret);
5897 /* new last item gets focus */
5898 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5899 ok(state == LVIS_FOCUSED, "got %x\n", state);
5900
5901 /* focus first item and delete it */
5902 item.stateMask = LVIS_FOCUSED;
5903 item.state = LVIS_FOCUSED;
5904 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5905 ok(ret == TRUE, "got %d\n", ret);
5906 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5907 ok(ret == TRUE, "got %d\n", ret);
5908 /* new first item gets focus */
5909 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5910 ok(state == LVIS_FOCUSED, "got %x\n", state);
5911
5912 g_focus_test_LVN_DELETEITEM = FALSE;
5913
5914 DestroyWindow(hwnd);
5915 }
5916
5917 static void test_insertitem(void)
5918 {
5919 LVITEMA item;
5920 UINT state;
5921 HWND hwnd;
5922 INT ret;
5923
5924 hwnd = create_listview_control(LVS_REPORT);
5925
5926 /* insert item 0 focused */
5927 item.mask = LVIF_STATE;
5928 item.state = LVIS_FOCUSED;
5929 item.stateMask = LVIS_FOCUSED;
5930 item.iItem = 0;
5931 item.iSubItem = 0;
5932 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5933 ok(ret == 0, "got %d\n", ret);
5934
5935 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5936 ok(state == LVIS_FOCUSED, "got %x\n", state);
5937
5938 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5939
5940 /* insert item 1, focus shift */
5941 item.mask = LVIF_STATE;
5942 item.state = LVIS_FOCUSED;
5943 item.stateMask = LVIS_FOCUSED;
5944 item.iItem = 1;
5945 item.iSubItem = 0;
5946 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5947 ok(ret == 1, "got %d\n", ret);
5948
5949 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5950
5951 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5952 ok(state == LVIS_FOCUSED, "got %x\n", state);
5953
5954 /* insert item 2, no focus shift */
5955 item.mask = LVIF_STATE;
5956 item.state = 0;
5957 item.stateMask = LVIS_FOCUSED;
5958 item.iItem = 2;
5959 item.iSubItem = 0;
5960 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5961 ok(ret == 2, "got %d\n", ret);
5962
5963 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5964 ok(state == LVIS_FOCUSED, "got %x\n", state);
5965
5966 DestroyWindow(hwnd);
5967 }
5968
5969 static void test_header_proc(void)
5970 {
5971 HWND hwnd, header, hdr;
5972 WNDPROC proc1, proc2;
5973
5974 hwnd = create_listview_control(LVS_REPORT);
5975
5976 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5977 ok(header != NULL, "got %p\n", header);
5978
5979 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
5980 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
5981 0, 0, 0, 0,
5982 NULL, NULL, NULL, NULL);
5983 ok(hdr != NULL, "got %p\n", hdr);
5984
5985 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
5986 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
5987 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
5988
5989 DestroyWindow(hdr);
5990 DestroyWindow(hwnd);
5991 }
5992
5993 static void flush_events(void)
5994 {
5995 MSG msg;
5996 int diff = 200;
5997 int min_timeout = 100;
5998 DWORD time = GetTickCount() + diff;
5999
6000 while (diff > 0)
6001 {
6002 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
6003 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6004 diff = time - GetTickCount();
6005 }
6006 }
6007
6008 static void test_oneclickactivate(void)
6009 {
6010 TRACKMOUSEEVENT track;
6011 char item1[] = "item1";
6012 LVITEMA item;
6013 HWND hwnd, fg;
6014 RECT rect;
6015 INT r;
6016 POINT orig_pos;
6017
6018 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
6019 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
6020 ok(hwnd != NULL, "failed to create listview window\n");
6021 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
6022 ok(r == 0, "should return zero\n");
6023
6024 SetForegroundWindow(hwndparent);
6025 flush_events();
6026 fg = GetForegroundWindow();
6027 if (fg != hwndparent)
6028 {
6029 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
6030 DestroyWindow(hwnd);
6031 return;
6032 }
6033
6034 item.mask = LVIF_TEXT;
6035 item.iItem = 0;
6036 item.iSubItem = 0;
6037 item.iImage = 0;
6038 item.pszText = item1;
6039 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
6040 ok(r == 0, "should not fail\n");
6041
6042 GetWindowRect(hwnd, &rect);
6043 GetCursorPos(&orig_pos);
6044 SetCursorPos(rect.left+5, rect.top+5);
6045 flush_events();
6046 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
6047 expect(0, r);
6048
6049 track.cbSize = sizeof(track);
6050 track.dwFlags = TME_QUERY;
6051 p_TrackMouseEvent(&track);
6052 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
6053 ok(track.dwFlags == TME_LEAVE, "dwFlags = %x\n", track.dwFlags);
6054
6055 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6056 expect(0, r);
6057 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
6058 expect(0, r);
6059 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6060 expect(1, r);
6061
6062 DestroyWindow(hwnd);
6063 SetCursorPos(orig_pos.x, orig_pos.y);
6064 }
6065
6066 static void test_callback_mask(void)
6067 {
6068 LVITEMA item;
6069 DWORD mask;
6070 HWND hwnd;
6071 BOOL ret;
6072
6073 hwnd = create_listview_control(LVS_REPORT);
6074
6075 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
6076 ok(ret, "got %d\n", ret);
6077
6078 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
6079 ok(ret, "got %d\n", ret);
6080
6081 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6082 ok(mask == ~0u, "got 0x%08x\n", mask);
6083
6084 DestroyWindow(hwnd);
6085
6086 /* LVS_OWNERDATA, mask LVIS_FOCUSED */
6087 hwnd = create_listview_control(LVS_REPORT | LVS_OWNERDATA);
6088
6089 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6090 ok(mask == 0, "Unexpected callback mask %#x.\n", mask);
6091
6092 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
6093 ok(ret, "Failed to set callback mask, %d\n", ret);
6094
6095 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6096 ok(mask == LVIS_FOCUSED, "Unexpected callback mask %#x.\n", mask);
6097
6098 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6099 ok(ret, "Failed to set item count.\n");
6100
6101 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6102 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6103
6104 item.stateMask = LVIS_FOCUSED;
6105 item.state = LVIS_FOCUSED;
6106 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6107 ok(ret, "Failed to set item state.\n");
6108
6109 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6110
6111 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6112 todo_wine
6113 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6114
6115 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6116 todo_wine
6117 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6118
6119 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6120 ok(ret, "Failed to set item count.\n");
6121
6122 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6123 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6124
6125 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6126 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6127
6128 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6129 ok(ret, "Failed to set item count.\n");
6130
6131 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6132 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6133
6134 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 1", FALSE);
6135
6136 /* LVS_OWNDERDATA, empty mask */
6137 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, 0, 0);
6138 ok(ret, "Failed to set callback mask, %d\n", ret);
6139
6140 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6141 ok(ret, "Failed to set item count.\n");
6142
6143 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6144 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6145
6146 item.stateMask = LVIS_FOCUSED;
6147 item.state = LVIS_FOCUSED;
6148 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6149 ok(ret, "Failed to set item state.\n");
6150
6151 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6152 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6153
6154 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6155
6156 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6157 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6158
6159 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6160 ok(ret, "Failed to set item count.\n");
6161
6162 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6163 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6164
6165 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6166 todo_wine
6167 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6168
6169 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6170 ok(ret, "Failed to set item count.\n");
6171
6172 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6173 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6174
6175 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 2", FALSE);
6176
6177 /* 2 items, focus on index 0, reduce to 1 item. */
6178 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6179
6180 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 2, 0);
6181 ok(ret, "Failed to set item count.\n");
6182
6183 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6184 ok(ret, "Failed to set item state.\n");
6185
6186 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6187 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6188
6189 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6190 ok(ret, "Failed to set item count.\n");
6191
6192 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6193 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6194
6195 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_focus_change_ownerdata_seq,
6196 "parent seq, owner data/focus 3", TRUE);
6197
6198 DestroyWindow(hwnd);
6199 }
6200
6201 static void test_state_image(void)
6202 {
6203 static const DWORD styles[] =
6204 {
6205 LVS_ICON,
6206 LVS_REPORT,
6207 LVS_SMALLICON,
6208 LVS_LIST,
6209 };
6210 int i;
6211
6212 for (i = 0; i < ARRAY_SIZE(styles); i++)
6213 {
6214 static char text[] = "Item";
6215 static char subtext[] = "Subitem";
6216 char buff[16];
6217 LVITEMA item;
6218 HWND hwnd;
6219 int r;
6220
6221 hwnd = create_listview_control(styles[i]);
6222
6223 insert_column(hwnd, 0);
6224 insert_column(hwnd, 1);
6225
6226 item.mask = LVIF_TEXT | LVIF_PARAM;
6227 item.iItem = 0;
6228 item.iSubItem = 0;
6229 item.pszText = text;
6230 item.lParam = 123456;
6231 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6232 ok(r == 0, "Failed to insert an item.\n");
6233
6234 item.mask = LVIF_STATE;
6235 item.state = INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED;
6236 item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED | LVIS_FOCUSED;
6237 item.iItem = 0;
6238 item.iSubItem = 0;
6239 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6240 ok(r, "Failed to set item state.\n");
6241
6242 item.mask = LVIF_TEXT;
6243 item.iItem = 0;
6244 item.iSubItem = 1;
6245 item.pszText = subtext;
6246 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6247 ok(r, "Failed to set subitem text.\n");
6248
6249 item.mask = LVIF_STATE | LVIF_PARAM;
6250 item.stateMask = ~0u;
6251 item.state = 0;
6252 item.iItem = 0;
6253 item.iSubItem = 0;
6254 item.lParam = 0;
6255 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6256 ok(r, "Failed to get item state.\n");
6257 ok(item.state == (INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED),
6258 "Unexpected item state %#x.\n", item.state);
6259 ok(item.lParam == 123456, "Unexpected lParam %ld.\n", item.lParam);
6260
6261 item.mask = 0;
6262 item.stateMask = ~0u;
6263 item.state = INDEXTOSTATEIMAGEMASK(2);
6264 item.iItem = 0;
6265 item.iSubItem = 1;
6266 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6267 ok(r, "Failed to get subitem state.\n");
6268 ok(item.state == INDEXTOSTATEIMAGEMASK(2), "Unexpected state %#x.\n", item.state);
6269
6270 item.mask = LVIF_STATE | LVIF_PARAM;
6271 item.stateMask = ~0u;
6272 item.state = INDEXTOSTATEIMAGEMASK(2);
6273 item.iItem = 0;
6274 item.iSubItem = 1;
6275 item.lParam = 0;
6276 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6277 ok(r, "Failed to get subitem state.\n");
6278 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6279 ok(item.lParam == 123456, "Unexpected lParam %ld.\n", item.lParam);
6280
6281 item.mask = LVIF_STATE;
6282 item.stateMask = LVIS_FOCUSED;
6283 item.state = 0;
6284 item.iItem = 0;
6285 item.iSubItem = 1;
6286 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6287 ok(r, "Failed to get subitem state.\n");
6288 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6289
6290 item.mask = LVIF_STATE;
6291 item.stateMask = ~0u;
6292 item.state = INDEXTOSTATEIMAGEMASK(2);
6293 item.iItem = 0;
6294 item.iSubItem = 2;
6295 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6296 ok(r, "Failed to get subitem state.\n");
6297 todo_wine
6298 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6299
6300 item.mask = LVIF_TEXT;
6301 item.iItem = 0;
6302 item.iSubItem = 1;
6303 item.pszText = buff;
6304 item.cchTextMax = sizeof(buff);
6305 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6306 ok(r, "Failed to get subitem text %d.\n", r);
6307 ok(!strcmp(buff, subtext), "Unexpected subitem text %s.\n", buff);
6308
6309 DestroyWindow(hwnd);
6310 }
6311 }
6312
6313 static void test_LVSCW_AUTOSIZE(void)
6314 {
6315 int width, width2;
6316 HWND hwnd;
6317 BOOL ret;
6318
6319 hwnd = create_listview_control(LVS_REPORT);
6320 ok(hwnd != NULL, "failed to create a listview window\n");
6321
6322 insert_column(hwnd, 0);
6323 insert_column(hwnd, 1);
6324 insert_item(hwnd, 0);
6325
6326 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6327 ok(ret, "Failed to set column width.\n");
6328
6329 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6330 ok(width > 0, "Unexpected column width %d.\n", width);
6331
6332 /* Turn on checkboxes. */
6333 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
6334 ok(ret == 0, "Unexpected previous extended style.\n");
6335
6336 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6337 ok(ret, "Failed to set column width.\n");
6338
6339 width2 = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6340 ok(width2 > 0, "Unexpected column width %d.\n", width2);
6341 ok(width2 > width, "Expected increased column width.\n");
6342
6343 /* Turn off checkboxes. */
6344 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
6345 ok(ret == LVS_EX_CHECKBOXES, "Unexpected previous extended style.\n");
6346
6347 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6348 ok(ret, "Failed to set column width.\n");
6349
6350 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6351 ok(width > 0, "Unexpected column width %d.\n", width2);
6352 ok(width2 > width, "Expected reduced column width.\n");
6353
6354 DestroyWindow(hwnd);
6355 }
6356
6357 static void test_LVN_ENDLABELEDIT(void)
6358 {
6359 WCHAR text[] = {'l','a','l','a',0};
6360 HWND hwnd, hwndedit;
6361 LVITEMW item = {0};
6362 DWORD ret;
6363
6364 hwnd = create_listview_control(LVS_REPORT | LVS_EDITLABELS);
6365
6366 insert_column(hwnd, 0);
6367
6368 item.mask = LVIF_TEXT;
6369 item.pszText = text;
6370 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
6371
6372 /* Test normal editing */
6373 SetFocus(hwnd);
6374 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6375 ok(hwndedit != NULL, "Failed to get edit control.\n");
6376
6377 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test");
6378 ok(ret, "Failed to set edit text.\n");
6379
6380 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6381
6382 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6383 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit, "Label edit", FALSE);
6384
6385 /* Test editing with kill focus */
6386 SetFocus(hwnd);
6387 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6388 ok(hwndedit != NULL, "Failed to get edit control.\n");
6389
6390 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test2");
6391 ok(ret, "Failed to set edit text.\n");
6392
6393 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6394
6395 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = TRUE;
6396 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6397 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = FALSE;
6398
6399 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit_kill_focus,
6400 "Label edit, kill focus", FALSE);
6401 ok(GetFocus() == hwnd, "Unexpected focused window.\n");
6402
6403 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6404
6405 DestroyWindow(hwnd);
6406 }
6407
6408 static LRESULT CALLBACK create_item_height_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6409 {
6410 if (msg == WM_CREATE)
6411 return 0;
6412
6413 return CallWindowProcA(listviewWndProc, hwnd, msg, wParam, lParam);
6414 }
6415
6416 static void test_LVM_GETCOUNTPERPAGE(void)
6417 {
6418 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6419 unsigned int i, j;
6420 WNDCLASSEXA cls;
6421 ATOM class;
6422 HWND hwnd;
6423 BOOL ret;
6424
6425 cls.cbSize = sizeof(WNDCLASSEXA);
6426 ret = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
6427 ok(ret, "Failed to get class info.\n");
6428 listviewWndProc = cls.lpfnWndProc;
6429 cls.lpfnWndProc = create_item_height_wndproc;
6430 cls.lpszClassName = "CountPerPageClass";
6431 class = RegisterClassExA(&cls);
6432 ok(class, "Failed to register class.\n");
6433
6434 for (i = 0; i < ARRAY_SIZE(styles); i++)
6435 {
6436 static char text[] = "item text";
6437 LVITEMA item = { 0 };
6438 UINT count, count2;
6439
6440 hwnd = create_listview_control(styles[i]);
6441 ok(hwnd != NULL, "Failed to create listview window.\n");
6442
6443 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6444 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6445 ok(count > 0 || broken(styles[i] == LVS_LIST && count == 0), "%u: unexpected count %u.\n", i, count);
6446 else
6447 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6448
6449 for (j = 0; j < 10; j++)
6450 {
6451 item.mask = LVIF_TEXT;
6452 item.pszText = text;
6453 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6454 }
6455
6456 count2 = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6457 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6458 ok(count == count2, "%u: unexpected count %u.\n", i, count2);
6459 else
6460 ok(count2 == 10, "%u: unexpected count %u.\n", i, count2);
6461
6462 DestroyWindow(hwnd);
6463
6464 hwnd = CreateWindowA("CountPerPageClass", "Test", WS_VISIBLE | styles[i], 0, 0, 100, 100, NULL, NULL,
6465 GetModuleHandleA(NULL), 0);
6466 ok(hwnd != NULL, "Failed to create a window.\n");
6467
6468 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6469 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6470
6471 DestroyWindow(hwnd);
6472 }
6473
6474 ret = UnregisterClassA("CountPerPageClass", NULL);
6475 ok(ret, "Failed to unregister test class.\n");
6476 }
6477
6478 START_TEST(listview)
6479 {
6480 ULONG_PTR ctx_cookie;
6481 HANDLE hCtx;
6482
6483 init_functions();
6484
6485 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
6486
6487 hwndparent = create_parent_window(FALSE);
6488 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6489
6490 g_is_below_5 = is_below_comctl_5();
6491
6492 test_header_notification();
6493 test_header_notification2();
6494 test_images();
6495 test_checkboxes();
6496 test_items();
6497 test_create(FALSE);
6498 test_redraw();
6499 test_customdraw();
6500 test_icon_spacing();
6501 test_color();
6502 test_item_count();
6503 test_item_position();
6504 test_columns();
6505 test_getorigin();
6506 test_multiselect();
6507 test_getitemrect();
6508 test_subitem_rect();
6509 test_sorting();
6510 test_ownerdata();
6511 test_norecompute();
6512 test_nosortheader();
6513 test_setredraw();
6514 test_hittest();
6515 test_getviewrect();
6516 test_getitemposition();
6517 test_columnscreation();
6518 test_editbox();
6519 test_notifyformat();
6520 test_indentation();
6521 test_getitemspacing();
6522 test_getcolumnwidth();
6523 test_approximate_viewrect();
6524 test_finditem();
6525 test_hover();
6526 test_destroynotify();
6527 test_createdragimage();
6528 test_dispinfo();
6529 test_LVM_SETITEMTEXT();
6530 test_LVM_REDRAWITEMS();
6531 test_imagelists();
6532 test_deleteitem();
6533 test_insertitem();
6534 test_header_proc();
6535 test_oneclickactivate();
6536 test_callback_mask();
6537 test_state_image();
6538 test_LVSCW_AUTOSIZE();
6539 test_LVN_ENDLABELEDIT();
6540 test_LVM_GETCOUNTPERPAGE();
6541
6542 if (!load_v6_module(&ctx_cookie, &hCtx))
6543 {
6544 DestroyWindow(hwndparent);
6545 return;
6546 }
6547
6548 init_functions();
6549
6550 /* comctl32 version 6 tests start here */
6551 test_get_set_view();
6552 test_canceleditlabel();
6553 test_mapidindex();
6554 test_scrollnotify();
6555 test_LVS_EX_TRANSPARENTBKGND();
6556 test_LVS_EX_HEADERINALLVIEWS();
6557 test_deleteitem();
6558 test_multiselect();
6559 test_insertitem();
6560 test_header_proc();
6561 test_images();
6562 test_checkboxes();
6563 test_items();
6564 test_create(TRUE);
6565 test_color();
6566 test_columns();
6567 test_sorting();
6568 test_ownerdata();
6569 test_norecompute();
6570 test_nosortheader();
6571 test_columnscreation();
6572 test_indentation();
6573 test_finditem();
6574 test_hover();
6575 test_destroynotify();
6576 test_createdragimage();
6577 test_dispinfo();
6578 test_LVM_SETITEMTEXT();
6579 test_LVM_REDRAWITEMS();
6580 test_oneclickactivate();
6581 test_state_image();
6582 test_LVSCW_AUTOSIZE();
6583 test_LVN_ENDLABELEDIT();
6584 test_LVM_GETCOUNTPERPAGE();
6585
6586 unload_v6_module(ctx_cookie, hCtx);
6587
6588 DestroyWindow(hwndparent);
6589 }