[COMCTL32_WINETEST] Sync with Wine Staging 1.7.47. CORE-9924
[reactos.git] / rostests / winetests / comctl32 / listview.c
1 /*
2 * ListView tests
3 *
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * 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 <wine/test.h>
24
25 //#include <stdio.h>
26 //#include <windows.h>
27 #include <wingdi.h>
28 #include <winuser.h>
29 #include <commctrl.h>
30
31 #include "v6util.h"
32 #include "msg.h"
33
34 enum seq_index {
35 PARENT_SEQ_INDEX,
36 PARENT_FULL_SEQ_INDEX,
37 PARENT_CD_SEQ_INDEX,
38 LISTVIEW_SEQ_INDEX,
39 EDITBOX_SEQ_INDEX,
40 COMBINED_SEQ_INDEX,
41 NUM_MSG_SEQUENCES
42 };
43
44 #define LISTVIEW_ID 0
45 #define HEADER_ID 1
46
47 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
48 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
49 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
50
51 static const WCHAR testparentclassW[] =
52 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
53
54 static HWND hwndparent, hwndparentW;
55 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
56 static BOOL blockEdit;
57 /* return nonzero on NM_HOVER */
58 static BOOL g_block_hover;
59 /* notification data for LVN_ITEMCHANGED */
60 static NMLISTVIEW g_nmlistview;
61 /* notification data for LVN_ITEMCHANGING */
62 static NMLISTVIEW g_nmlistview_changing;
63 /* format reported to control:
64 -1 falls to defproc, anything else returned */
65 static INT notifyFormat;
66 /* indicates we're running < 5.80 version */
67 static BOOL g_is_below_5;
68 /* item data passed to LVN_GETDISPINFOA */
69 static LVITEMA g_itema;
70 /* alter notification code A->W */
71 static BOOL g_disp_A_to_W;
72 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
73 static NMLVDISPINFOA g_editbox_disp_info;
74 /* when this is set focus will be tested on LVN_DELETEITEM */
75 static BOOL g_focus_test_LVN_DELETEITEM;
76
77 static HWND subclass_editbox(HWND hwndListview);
78
79 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
80
81 static const struct message create_ownerdrawfixed_parent_seq[] = {
82 { WM_NOTIFYFORMAT, sent },
83 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
84 { WM_MEASUREITEM, sent },
85 { WM_PARENTNOTIFY, sent },
86 { 0 }
87 };
88
89 static const struct message redraw_listview_seq[] = {
90 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
91 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
92 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
93 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
94 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
95 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
96 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
97 { 0 }
98 };
99
100 static const struct message listview_icon_spacing_seq[] = {
101 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
102 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
103 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
104 { 0 }
105 };
106
107 static const struct message listview_color_seq[] = {
108 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
109 { LVM_GETBKCOLOR, sent },
110 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
111 { LVM_GETTEXTCOLOR, sent },
112 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
113 { LVM_GETTEXTBKCOLOR, sent },
114
115 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
116 { LVM_GETBKCOLOR, sent },
117 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
118 { LVM_GETTEXTCOLOR, sent },
119 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
120 { LVM_GETTEXTBKCOLOR, sent },
121
122 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
123 { LVM_GETBKCOLOR, sent },
124 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
125 { LVM_GETTEXTCOLOR, sent },
126 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
127 { LVM_GETTEXTBKCOLOR, sent },
128
129 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
130 { LVM_GETBKCOLOR, sent },
131 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
132 { LVM_GETTEXTCOLOR, sent },
133 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
134 { LVM_GETTEXTBKCOLOR, sent },
135 { 0 }
136 };
137
138 static const struct message listview_item_count_seq[] = {
139 { LVM_GETITEMCOUNT, sent },
140 { LVM_INSERTITEMA, sent },
141 { LVM_INSERTITEMA, sent },
142 { LVM_INSERTITEMA, sent },
143 { LVM_GETITEMCOUNT, sent },
144 { LVM_DELETEITEM, sent|wparam, 2 },
145 { WM_NCPAINT, sent|optional },
146 { WM_ERASEBKGND, sent|optional },
147 { LVM_GETITEMCOUNT, sent },
148 { LVM_DELETEALLITEMS, sent },
149 { LVM_GETITEMCOUNT, sent },
150 { LVM_INSERTITEMA, sent },
151 { LVM_INSERTITEMA, sent },
152 { LVM_GETITEMCOUNT, sent },
153 { LVM_INSERTITEMA, sent },
154 { LVM_GETITEMCOUNT, sent },
155 { 0 }
156 };
157
158 static const struct message listview_itempos_seq[] = {
159 { LVM_INSERTITEMA, sent },
160 { LVM_INSERTITEMA, sent },
161 { LVM_INSERTITEMA, sent },
162 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
163 { WM_NCPAINT, sent|optional },
164 { WM_ERASEBKGND, sent|optional },
165 { LVM_GETITEMPOSITION, sent|wparam, 1 },
166 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
167 { LVM_GETITEMPOSITION, sent|wparam, 2 },
168 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
169 { LVM_GETITEMPOSITION, sent|wparam, 0 },
170 { 0 }
171 };
172
173 static const struct message listview_ownerdata_switchto_seq[] = {
174 { WM_STYLECHANGING, sent },
175 { WM_STYLECHANGED, sent },
176 { 0 }
177 };
178
179 static const struct message listview_getorderarray_seq[] = {
180 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
181 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
182 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
183 { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
184 { 0 }
185 };
186
187 static const struct message listview_setorderarray_seq[] = {
188 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
189 { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
190 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
191 { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
192 { 0 }
193 };
194
195 static const struct message empty_seq[] = {
196 { 0 }
197 };
198
199 static const struct message forward_erasebkgnd_parent_seq[] = {
200 { WM_ERASEBKGND, sent },
201 { 0 }
202 };
203
204 static const struct message ownderdata_select_focus_parent_seq[] = {
205 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
206 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
207 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
208 { 0 }
209 };
210
211 static const struct message ownerdata_setstate_all_parent_seq[] = {
212 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
213 { 0 }
214 };
215
216 static const struct message ownerdata_defocus_all_parent_seq[] = {
217 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
218 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
219 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
220 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
221 { 0 }
222 };
223
224 static const struct message ownerdata_deselect_all_parent_seq[] = {
225 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
226 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
227 { 0 }
228 };
229
230 static const struct message change_all_parent_seq[] = {
231 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
232 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
233
234 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
235 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
236
237 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
238 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
239
240 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
241 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
242
243 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
244 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
245 { 0 }
246 };
247
248 static const struct message changing_all_parent_seq[] = {
249 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
250 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
251 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
252 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
253 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
254 { 0 }
255 };
256
257 static const struct message textcallback_set_again_parent_seq[] = {
258 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
259 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
260 { 0 }
261 };
262
263 static const struct message single_getdispinfo_parent_seq[] = {
264 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
265 { 0 }
266 };
267
268 static const struct message getitemposition_seq1[] = {
269 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
270 { 0 }
271 };
272
273 static const struct message getitemposition_seq2[] = {
274 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
275 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
276 { 0 }
277 };
278
279 static const struct message getsubitemrect_seq[] = {
280 { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
281 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
282 { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
283 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
284 { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
285 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
286 { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
287 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
288 { 0 }
289 };
290
291 static const struct message editbox_create_pos[] = {
292 /* sequence sent after LVN_BEGINLABELEDIT */
293 /* next two are 4.7x specific */
294 { WM_WINDOWPOSCHANGING, sent },
295 { WM_WINDOWPOSCHANGED, sent|optional },
296
297 { WM_WINDOWPOSCHANGING, sent|optional },
298 { WM_NCCALCSIZE, sent },
299 { WM_WINDOWPOSCHANGED, sent },
300 { WM_MOVE, sent|defwinproc },
301 { WM_SIZE, sent|defwinproc },
302 /* the rest is todo, skipped in 4.7x */
303 { WM_WINDOWPOSCHANGING, sent|optional },
304 { WM_WINDOWPOSCHANGED, sent|optional },
305 { 0 }
306 };
307
308 static const struct message scroll_parent_seq[] = {
309 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
310 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
311 { 0 }
312 };
313
314 static const struct message setredraw_seq[] = {
315 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
316 { 0 }
317 };
318
319 static const struct message lvs_ex_transparentbkgnd_seq[] = {
320 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
321 { 0 }
322 };
323
324 static const struct message edit_end_nochange[] = {
325 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
326 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
327 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
328 { 0 }
329 };
330
331 static const struct message hover_parent[] = {
332 { WM_GETDLGCODE, sent }, /* todo_wine */
333 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
334 { 0 }
335 };
336
337 static const struct message listview_destroy[] = {
338 { 0x0090, sent|optional }, /* Vista */
339 { WM_PARENTNOTIFY, sent },
340 { WM_SHOWWINDOW, sent },
341 { WM_WINDOWPOSCHANGING, sent },
342 { WM_WINDOWPOSCHANGED, sent|optional },
343 { WM_DESTROY, sent },
344 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
345 { WM_NCDESTROY, sent },
346 { 0 }
347 };
348
349 static const struct message listview_ownerdata_destroy[] = {
350 { 0x0090, sent|optional }, /* Vista */
351 { WM_PARENTNOTIFY, sent },
352 { WM_SHOWWINDOW, sent },
353 { WM_WINDOWPOSCHANGING, sent },
354 { WM_WINDOWPOSCHANGED, sent|optional },
355 { WM_DESTROY, sent },
356 { WM_NCDESTROY, sent },
357 { 0 }
358 };
359
360 static const struct message listview_ownerdata_deleteall[] = {
361 { LVM_DELETEALLITEMS, sent },
362 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
363 { 0 }
364 };
365
366 static const struct message listview_header_changed_seq[] = {
367 { LVM_SETCOLUMNA, sent },
368 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
369 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
370 { 0 }
371 };
372
373 static const struct message parent_header_click_seq[] = {
374 { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
375 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
376 { 0 }
377 };
378
379 static const struct message parent_header_divider_dclick_seq[] = {
380 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
381 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
382 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
383 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
384 { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
385 { 0 }
386 };
387
388 static const struct message listview_set_imagelist[] = {
389 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
390 { 0 }
391 };
392
393 static const struct message listview_header_set_imagelist[] = {
394 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
395 { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
396 { 0 }
397 };
398
399 static const struct message parent_insert_focused_seq[] = {
400 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
401 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
402 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
403 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
404 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
405 { 0 }
406 };
407
408 static const struct message parent_report_cd_seq[] = {
409 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
410 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
411 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
412 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
413 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
414 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
415 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
416 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
417 { 0 }
418 };
419
420 static const struct message parent_list_cd_seq[] = {
421 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
422 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
423 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
424 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
425 { 0 }
426 };
427
428 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
429 {
430 static LONG defwndproc_counter = 0;
431 LRESULT ret;
432 struct message msg;
433
434 msg.message = message;
435 msg.flags = sent|wparam|lparam;
436 if (defwndproc_counter) msg.flags |= defwinproc;
437 msg.wParam = wParam;
438 msg.lParam = lParam;
439 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
440
441 /* log system messages, except for painting */
442 if (message < WM_USER &&
443 message != WM_PAINT &&
444 message != WM_ERASEBKGND &&
445 message != WM_NCPAINT &&
446 message != WM_NCHITTEST &&
447 message != WM_GETTEXT &&
448 message != WM_GETICON &&
449 message != WM_DEVICECHANGE)
450 {
451 add_message(sequences, PARENT_SEQ_INDEX, &msg);
452 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
453 }
454 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
455
456 switch (message)
457 {
458 case WM_NOTIFY:
459 {
460 switch (((NMHDR*)lParam)->code)
461 {
462 case LVN_BEGINLABELEDITA:
463 {
464 HWND edit = NULL;
465
466 /* subclass edit box */
467 if (!blockEdit)
468 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
469
470 if (edit)
471 {
472 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
473 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
474 "text limit %d, expected 259\n", len);
475 }
476
477 return blockEdit;
478 }
479 case LVN_ENDLABELEDITA:
480 {
481 HWND edit;
482
483 /* always accept new item text */
484 NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
485 g_editbox_disp_info = *di;
486 trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText ? di->item.pszText : "(null)");
487
488 /* edit control still available from this notification */
489 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
490 ok(IsWindow(edit), "expected valid edit control handle\n");
491 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
492
493 return TRUE;
494 }
495 case LVN_BEGINSCROLL:
496 case LVN_ENDSCROLL:
497 {
498 NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
499
500 trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
501 "BEGIN" : "END", pScroll->dx, pScroll->dy);
502 }
503 break;
504 case LVN_ITEMCHANGING:
505 {
506 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
507 g_nmlistview_changing = *nmlv;
508 }
509 break;
510 case LVN_ITEMCHANGED:
511 {
512 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
513 g_nmlistview = *nmlv;
514 }
515 break;
516 case LVN_GETDISPINFOA:
517 {
518 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
519 g_itema = dispinfo->item;
520
521 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
522 {
523 static const WCHAR testW[] = {'T','E','S','T',0};
524 dispinfo->hdr.code = LVN_GETDISPINFOW;
525 memcpy(dispinfo->item.pszText, testW, sizeof(testW));
526 }
527
528 /* test control buffer size for text, 10 used to mask cases when control
529 is using caller buffer to process LVM_GETITEM for example */
530 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
531 ok(dispinfo->item.cchTextMax == 260 ||
532 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
533 "buffer size %d\n", dispinfo->item.cchTextMax);
534 }
535 break;
536 case LVN_DELETEITEM:
537 if (g_focus_test_LVN_DELETEITEM)
538 {
539 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
540 UINT state;
541
542 state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
543 ok(state == 0, "got state %x\n", state);
544 }
545 break;
546 case NM_HOVER:
547 if (g_block_hover) return 1;
548 break;
549 }
550 break;
551 }
552 case WM_NOTIFYFORMAT:
553 {
554 /* force to return format */
555 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
556 break;
557 }
558 }
559
560 defwndproc_counter++;
561 ret = DefWindowProcA(hwnd, message, wParam, lParam);
562 defwndproc_counter--;
563
564 return ret;
565 }
566
567 static BOOL register_parent_wnd_class(BOOL Unicode)
568 {
569 WNDCLASSA clsA;
570 WNDCLASSW clsW;
571
572 if (Unicode)
573 {
574 clsW.style = 0;
575 clsW.lpfnWndProc = parent_wnd_proc;
576 clsW.cbClsExtra = 0;
577 clsW.cbWndExtra = 0;
578 clsW.hInstance = GetModuleHandleW(NULL);
579 clsW.hIcon = 0;
580 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
581 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
582 clsW.lpszMenuName = NULL;
583 clsW.lpszClassName = testparentclassW;
584 }
585 else
586 {
587 clsA.style = 0;
588 clsA.lpfnWndProc = parent_wnd_proc;
589 clsA.cbClsExtra = 0;
590 clsA.cbWndExtra = 0;
591 clsA.hInstance = GetModuleHandleA(NULL);
592 clsA.hIcon = 0;
593 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
594 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
595 clsA.lpszMenuName = NULL;
596 clsA.lpszClassName = "Listview test parent class";
597 }
598
599 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
600 }
601
602 static HWND create_parent_window(BOOL Unicode)
603 {
604 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
605 HWND hwnd;
606
607 if (!register_parent_wnd_class(Unicode))
608 return NULL;
609
610 blockEdit = FALSE;
611 notifyFormat = -1;
612
613 if (Unicode)
614 hwnd = CreateWindowExW(0, testparentclassW, nameW,
615 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
616 WS_MAXIMIZEBOX | WS_VISIBLE,
617 0, 0, 100, 100,
618 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
619 else
620 hwnd = CreateWindowExA(0, "Listview test parent class",
621 "Listview test parent window",
622 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
623 WS_MAXIMIZEBOX | WS_VISIBLE,
624 0, 0, 100, 100,
625 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
626 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
627 return hwnd;
628 }
629
630 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
631 {
632 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
633 static LONG defwndproc_counter = 0;
634 LRESULT ret;
635 struct message msg;
636
637 /* some debug output for style changing */
638 if ((message == WM_STYLECHANGING ||
639 message == WM_STYLECHANGED) && lParam)
640 {
641 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
642 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
643 }
644
645 msg.message = message;
646 msg.flags = sent|wparam|lparam;
647 if (defwndproc_counter) msg.flags |= defwinproc;
648 msg.wParam = wParam;
649 msg.lParam = lParam;
650 msg.id = LISTVIEW_ID;
651 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
652 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
653
654 defwndproc_counter++;
655 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
656 defwndproc_counter--;
657 return ret;
658 }
659
660 static HWND create_listview_control(DWORD style)
661 {
662 WNDPROC oldproc;
663 HWND hwnd;
664 RECT rect;
665
666 GetClientRect(hwndparent, &rect);
667 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
668 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
669 0, 0, rect.right, rect.bottom,
670 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
671 ok(hwnd != NULL, "gle=%d\n", GetLastError());
672
673 if (!hwnd) return NULL;
674
675 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
676 (LONG_PTR)listview_subclass_proc);
677 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
678
679 return hwnd;
680 }
681
682 /* unicode listview window with specified parent */
683 static HWND create_listview_controlW(DWORD style, HWND parent)
684 {
685 WNDPROC oldproc;
686 HWND hwnd;
687 RECT rect;
688 static const WCHAR nameW[] = {'f','o','o',0};
689
690 GetClientRect(parent, &rect);
691 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
692 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
693 0, 0, rect.right, rect.bottom,
694 parent, NULL, GetModuleHandleW(NULL), NULL);
695 ok(hwnd != NULL, "gle=%d\n", GetLastError());
696
697 if (!hwnd) return NULL;
698
699 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
700 (LONG_PTR)listview_subclass_proc);
701 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
702
703 return hwnd;
704 }
705
706 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
707 {
708 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
709 static LONG defwndproc_counter = 0;
710 LRESULT ret;
711 struct message msg;
712
713 msg.message = message;
714 msg.flags = sent|wparam|lparam;
715 if (defwndproc_counter) msg.flags |= defwinproc;
716 msg.wParam = wParam;
717 msg.lParam = lParam;
718 msg.id = HEADER_ID;
719 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
720
721 defwndproc_counter++;
722 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
723 defwndproc_counter--;
724 return ret;
725 }
726
727 static HWND subclass_header(HWND hwndListview)
728 {
729 WNDPROC oldproc;
730 HWND hwnd;
731
732 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
733 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
734 (LONG_PTR)header_subclass_proc);
735 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
736
737 return hwnd;
738 }
739
740 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
741 {
742 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
743 static LONG defwndproc_counter = 0;
744 LRESULT ret;
745 struct message msg;
746
747 msg.message = message;
748 msg.flags = sent|wparam|lparam;
749 if (defwndproc_counter) msg.flags |= defwinproc;
750 msg.wParam = wParam;
751 msg.lParam = lParam;
752 msg.id = 0;
753
754 /* all we need is sizing */
755 if (message == WM_WINDOWPOSCHANGING ||
756 message == WM_NCCALCSIZE ||
757 message == WM_WINDOWPOSCHANGED ||
758 message == WM_MOVE ||
759 message == WM_SIZE)
760 {
761 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
762 }
763
764 defwndproc_counter++;
765 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
766 defwndproc_counter--;
767 return ret;
768 }
769
770 static HWND subclass_editbox(HWND hwndListview)
771 {
772 WNDPROC oldproc;
773 HWND hwnd;
774
775 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
776 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
777 (LONG_PTR)editbox_subclass_proc);
778 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
779
780 return hwnd;
781 }
782
783 /* Performs a single LVM_HITTEST test */
784 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
785 BOOL todo_item, BOOL todo_flags, int line)
786 {
787 LVHITTESTINFO lpht;
788 INT ret;
789
790 lpht.pt.x = x;
791 lpht.pt.y = y;
792 lpht.iSubItem = 10;
793
794 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
795
796 if (todo_item)
797 {
798 todo_wine
799 {
800 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
801 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
802 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
803 }
804 }
805 else
806 {
807 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
808 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
809 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
810 }
811
812 if (todo_flags)
813 {
814 todo_wine
815 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
816 }
817 else if (broken_flags)
818 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
819 "Expected flags %x, got %x\n", flags, lpht.flags);
820 else
821 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
822 }
823
824 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
825
826 /* Performs a single LVM_SUBITEMHITTEST test */
827 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
828 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
829 {
830 LVHITTESTINFO lpht;
831 INT ret;
832
833 lpht.pt.x = x;
834 lpht.pt.y = y;
835
836 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
837
838 if (todo_item)
839 {
840 todo_wine
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 }
845 }
846 else
847 {
848 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
849 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
850 }
851
852 if (todo_subitem)
853 {
854 todo_wine
855 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
856 }
857 else
858 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
859
860 if (todo_flags)
861 {
862 todo_wine
863 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
864 }
865 else
866 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
867 }
868
869 #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__)
870
871 static void test_images(void)
872 {
873 HWND hwnd;
874 INT r;
875 LVITEMA item;
876 HIMAGELIST himl;
877 HBITMAP hbmp;
878 RECT r1, r2;
879 static CHAR hello[] = "hello";
880
881 himl = ImageList_Create(40, 40, 0, 4, 4);
882 ok(himl != NULL, "failed to create imagelist\n");
883
884 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
885 ok(hbmp != NULL, "failed to create bitmap\n");
886
887 r = ImageList_Add(himl, hbmp, 0);
888 ok(r == 0, "should be zero\n");
889
890 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
891 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
892 ok(hwnd != NULL, "failed to create listview window\n");
893
894 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
895 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
896
897 ok(r == 0, "should return zero\n");
898
899 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
900 ok(r == 0, "should return zero\n");
901
902 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
903 ok(r != 0, "got 0\n");
904
905 /* returns dimensions */
906
907 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
908 ok(r == 0, "should be zero items\n");
909
910 item.mask = LVIF_IMAGE | LVIF_TEXT;
911 item.iItem = 0;
912 item.iSubItem = 1;
913 item.iImage = 0;
914 item.pszText = 0;
915 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
916 ok(r == -1, "should fail\n");
917
918 item.iSubItem = 0;
919 item.pszText = hello;
920 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
921 ok(r == 0, "should not fail\n");
922
923 memset(&r1, 0, sizeof r1);
924 r1.left = LVIR_ICON;
925 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
926 expect(1, r);
927
928 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
929 ok(r == TRUE, "should not fail\n");
930
931 item.iSubItem = 0;
932 item.pszText = hello;
933 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
934 ok(r == 0, "should not fail\n");
935
936 memset(&r2, 0, sizeof r2);
937 r2.left = LVIR_ICON;
938 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
939 expect(1, r);
940
941 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
942
943 DestroyWindow(hwnd);
944 }
945
946 static void test_checkboxes(void)
947 {
948 HWND hwnd;
949 LVITEMA item;
950 DWORD r;
951 static CHAR text[] = "Text",
952 text2[] = "Text2",
953 text3[] = "Text3";
954
955 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
956 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
957 ok(hwnd != NULL, "failed to create listview window\n");
958
959 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
960 item.mask = LVIF_TEXT | LVIF_STATE;
961 item.stateMask = 0xffff;
962 item.state = 0xfccc;
963 item.iItem = 0;
964 item.iSubItem = 0;
965 item.pszText = text;
966 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
967 expect(0, r);
968
969 item.iItem = 0;
970 item.mask = LVIF_STATE;
971 item.stateMask = 0xffff;
972 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
973 expect(1, r);
974 ok(item.state == 0xfccc, "state %x\n", item.state);
975
976 /* Don't set LVIF_STATE */
977 item.mask = LVIF_TEXT;
978 item.stateMask = 0xffff;
979 item.state = 0xfccc;
980 item.iItem = 1;
981 item.iSubItem = 0;
982 item.pszText = text;
983 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
984 expect(1, r);
985
986 item.iItem = 1;
987 item.mask = LVIF_STATE;
988 item.stateMask = 0xffff;
989 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
990 expect(1, r);
991 ok(item.state == 0, "state %x\n", item.state);
992
993 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
994 expect(0, r);
995
996 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
997 item.iItem = 0;
998 item.mask = LVIF_STATE;
999 item.stateMask = 0xffff;
1000 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1001 expect(1, r);
1002 if (item.state != 0x1ccc)
1003 {
1004 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
1005 DestroyWindow(hwnd);
1006 return;
1007 }
1008
1009 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1010 item.iItem = 2;
1011 item.mask = LVIF_TEXT;
1012 item.state = 0;
1013 item.pszText = text2;
1014 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1015 expect(2, r);
1016
1017 item.iItem = 2;
1018 item.mask = LVIF_STATE;
1019 item.stateMask = 0xffff;
1020 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1021 expect(1, r);
1022 ok(item.state == 0x1000, "state %x\n", item.state);
1023
1024 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1025 item.iItem = 3;
1026 item.mask = LVIF_TEXT | LVIF_STATE;
1027 item.stateMask = 0xffff;
1028 item.state = 0x2aaa;
1029 item.pszText = text3;
1030 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1031 expect(3, r);
1032
1033 item.iItem = 3;
1034 item.mask = LVIF_STATE;
1035 item.stateMask = 0xffff;
1036 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1037 expect(1, r);
1038 ok(item.state == 0x1aaa, "state %x\n", item.state);
1039
1040 /* Set an item's state to checked */
1041 item.iItem = 3;
1042 item.mask = LVIF_STATE;
1043 item.stateMask = 0xf000;
1044 item.state = 0x2000;
1045 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1046 expect(1, 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 == 0x2aaa, "state %x\n", item.state);
1054
1055 /* Check that only the bits we asked for are returned,
1056 * and that all the others are set to zero
1057 */
1058 item.iItem = 3;
1059 item.mask = LVIF_STATE;
1060 item.stateMask = 0xf000;
1061 item.state = 0xffff;
1062 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1063 expect(1, r);
1064 ok(item.state == 0x2000, "state %x\n", item.state);
1065
1066 /* Set the style again and check that doesn't change an item's state */
1067 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1068 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1069
1070 item.iItem = 3;
1071 item.mask = LVIF_STATE;
1072 item.stateMask = 0xffff;
1073 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1074 expect(1, r);
1075 ok(item.state == 0x2aaa, "state %x\n", item.state);
1076
1077 /* Unsetting the checkbox extended style doesn't change an item's state */
1078 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1079 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1080
1081 item.iItem = 3;
1082 item.mask = LVIF_STATE;
1083 item.stateMask = 0xffff;
1084 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1085 expect(1, r);
1086 ok(item.state == 0x2aaa, "state %x\n", item.state);
1087
1088 /* Now setting the style again will change an item's state */
1089 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1090 expect(0, r);
1091
1092 item.iItem = 3;
1093 item.mask = LVIF_STATE;
1094 item.stateMask = 0xffff;
1095 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1096 expect(1, r);
1097 ok(item.state == 0x1aaa, "state %x\n", item.state);
1098
1099 /* Toggle checkbox tests (bug 9934) */
1100 memset (&item, 0xcc, sizeof(item));
1101 item.mask = LVIF_STATE;
1102 item.iItem = 3;
1103 item.iSubItem = 0;
1104 item.state = LVIS_FOCUSED;
1105 item.stateMask = LVIS_FOCUSED;
1106 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1107 expect(1, r);
1108
1109 item.iItem = 3;
1110 item.mask = LVIF_STATE;
1111 item.stateMask = 0xffff;
1112 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1113 expect(1, r);
1114 ok(item.state == 0x1aab, "state %x\n", item.state);
1115
1116 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1117 expect(0, r);
1118 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1119 expect(0, r);
1120
1121 item.iItem = 3;
1122 item.mask = LVIF_STATE;
1123 item.stateMask = 0xffff;
1124 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1125 expect(1, r);
1126 ok(item.state == 0x2aab, "state %x\n", item.state);
1127
1128 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1129 expect(0, r);
1130 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1131 expect(0, r);
1132
1133 item.iItem = 3;
1134 item.mask = LVIF_STATE;
1135 item.stateMask = 0xffff;
1136 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1137 expect(1, r);
1138 ok(item.state == 0x1aab, "state %x\n", item.state);
1139
1140 DestroyWindow(hwnd);
1141 }
1142
1143 static void insert_column(HWND hwnd, int idx)
1144 {
1145 LVCOLUMNA column;
1146 INT rc;
1147
1148 memset(&column, 0xcc, sizeof(column));
1149 column.mask = LVCF_SUBITEM;
1150 column.iSubItem = idx;
1151
1152 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1153 expect(idx, rc);
1154 }
1155
1156 static void insert_item(HWND hwnd, int idx)
1157 {
1158 static CHAR text[] = "foo";
1159
1160 LVITEMA item;
1161 INT rc;
1162
1163 memset(&item, 0xcc, sizeof (item));
1164 item.mask = LVIF_TEXT;
1165 item.iItem = idx;
1166 item.iSubItem = 0;
1167 item.pszText = text;
1168
1169 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1170 expect(idx, rc);
1171 }
1172
1173 static void test_items(void)
1174 {
1175 const LPARAM lparamTest = 0x42;
1176 static CHAR text[] = "Text";
1177 char buffA[5];
1178 HWND hwnd;
1179 LVITEMA item;
1180 DWORD r;
1181
1182 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1183 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1184 ok(hwnd != NULL, "failed to create listview window\n");
1185
1186 /*
1187 * Test setting/getting item params
1188 */
1189
1190 /* Set up two columns */
1191 insert_column(hwnd, 0);
1192 insert_column(hwnd, 1);
1193
1194 /* LVIS_SELECTED with zero stateMask */
1195 /* set */
1196 memset (&item, 0, sizeof (item));
1197 item.mask = LVIF_STATE;
1198 item.state = LVIS_SELECTED;
1199 item.stateMask = 0;
1200 item.iItem = 0;
1201 item.iSubItem = 0;
1202 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1203 expect(0, r);
1204 /* get */
1205 memset (&item, 0xcc, sizeof (item));
1206 item.mask = LVIF_STATE;
1207 item.stateMask = LVIS_SELECTED;
1208 item.state = 0;
1209 item.iItem = 0;
1210 item.iSubItem = 0;
1211 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1212 expect(1, r);
1213 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1214 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1215
1216 /* LVIS_SELECTED with zero stateMask */
1217 /* set */
1218 memset (&item, 0, sizeof (item));
1219 item.mask = LVIF_STATE;
1220 item.state = LVIS_FOCUSED;
1221 item.stateMask = 0;
1222 item.iItem = 0;
1223 item.iSubItem = 0;
1224 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1225 expect(0, r);
1226 /* get */
1227 memset (&item, 0xcc, sizeof (item));
1228 item.mask = LVIF_STATE;
1229 item.stateMask = LVIS_FOCUSED;
1230 item.state = 0;
1231 item.iItem = 0;
1232 item.iSubItem = 0;
1233 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1234 expect(1, r);
1235 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1236 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1237
1238 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1239 /* set */
1240 memset (&item, 0, sizeof (item));
1241 item.mask = LVIF_STATE;
1242 item.state = LVIS_CUT;
1243 item.stateMask = LVIS_FOCUSED;
1244 item.iItem = 0;
1245 item.iSubItem = 0;
1246 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1247 expect(0, r);
1248 /* get */
1249 memset (&item, 0xcc, sizeof (item));
1250 item.mask = LVIF_STATE;
1251 item.stateMask = LVIS_CUT;
1252 item.state = 0;
1253 item.iItem = 0;
1254 item.iSubItem = 0;
1255 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1256 expect(1, r);
1257 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1258 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1259
1260 /* Insert an item with just a param */
1261 memset (&item, 0xcc, sizeof (item));
1262 item.mask = LVIF_PARAM;
1263 item.iItem = 0;
1264 item.iSubItem = 0;
1265 item.lParam = lparamTest;
1266 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1267 expect(0, r);
1268
1269 /* Test getting of the param */
1270 memset (&item, 0xcc, sizeof (item));
1271 item.mask = LVIF_PARAM;
1272 item.iItem = 0;
1273 item.iSubItem = 0;
1274 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1275 expect(1, r);
1276 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1277
1278 /* Set up a subitem */
1279 memset (&item, 0xcc, sizeof (item));
1280 item.mask = LVIF_TEXT;
1281 item.iItem = 0;
1282 item.iSubItem = 1;
1283 item.pszText = text;
1284 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1285 expect(1, r);
1286
1287 item.mask = LVIF_TEXT;
1288 item.iItem = 0;
1289 item.iSubItem = 1;
1290 item.pszText = buffA;
1291 item.cchTextMax = sizeof(buffA);
1292 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1293 expect(1, r);
1294 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1295
1296 /* set up with extra flag */
1297 /* 1. reset subitem text */
1298 item.mask = LVIF_TEXT;
1299 item.iItem = 0;
1300 item.iSubItem = 1;
1301 item.pszText = NULL;
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 buffA[0] = 'a';
1310 item.cchTextMax = sizeof(buffA);
1311 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1312 expect(1, r);
1313 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1314
1315 /* 2. set new text with extra flag specified */
1316 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1317 item.iItem = 0;
1318 item.iSubItem = 1;
1319 item.pszText = text;
1320 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1321 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1322
1323 if (r == 1)
1324 {
1325 item.mask = LVIF_TEXT;
1326 item.iItem = 0;
1327 item.iSubItem = 1;
1328 item.pszText = buffA;
1329 buffA[0] = 'a';
1330 item.cchTextMax = sizeof(buffA);
1331 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1332 expect(1, r);
1333 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1334 }
1335
1336 /* Query param from subitem: returns main item param */
1337 memset (&item, 0xcc, sizeof (item));
1338 item.mask = LVIF_PARAM;
1339 item.iItem = 0;
1340 item.iSubItem = 1;
1341 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1342 expect(1, r);
1343 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1344
1345 /* Set up param on first subitem: no effect */
1346 memset (&item, 0xcc, sizeof (item));
1347 item.mask = LVIF_PARAM;
1348 item.iItem = 0;
1349 item.iSubItem = 1;
1350 item.lParam = lparamTest+1;
1351 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1352 expect(0, r);
1353
1354 /* Query param from subitem again: should still return 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 /**** Some tests of state highlighting ****/
1364 memset (&item, 0xcc, sizeof (item));
1365 item.mask = LVIF_STATE;
1366 item.iItem = 0;
1367 item.iSubItem = 0;
1368 item.state = LVIS_SELECTED;
1369 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1370 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1371 expect(1, r);
1372 item.iSubItem = 1;
1373 item.state = LVIS_DROPHILITED;
1374 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1375 expect(1, r);
1376
1377 memset (&item, 0xcc, sizeof (item));
1378 item.mask = LVIF_STATE;
1379 item.iItem = 0;
1380 item.iSubItem = 0;
1381 item.stateMask = -1;
1382 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1383 expect(1, r);
1384 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1385 item.iSubItem = 1;
1386 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1387 expect(1, r);
1388 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1389
1390 /* some notnull but meaningless masks */
1391 memset (&item, 0, sizeof(item));
1392 item.mask = LVIF_NORECOMPUTE;
1393 item.iItem = 0;
1394 item.iSubItem = 0;
1395 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1396 expect(1, r);
1397 memset (&item, 0, sizeof(item));
1398 item.mask = LVIF_DI_SETITEM;
1399 item.iItem = 0;
1400 item.iSubItem = 0;
1401 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1402 expect(1, r);
1403
1404 /* set text to callback value already having it */
1405 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1406 expect(TRUE, r);
1407 memset (&item, 0, sizeof (item));
1408 item.mask = LVIF_TEXT;
1409 item.pszText = LPSTR_TEXTCALLBACKA;
1410 item.iItem = 0;
1411 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1412 expect(0, r);
1413 memset (&item, 0, sizeof (item));
1414
1415 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1416
1417 item.pszText = LPSTR_TEXTCALLBACKA;
1418 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1419 expect(TRUE, r);
1420
1421 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1422 "check callback text comparison rule", FALSE);
1423
1424 DestroyWindow(hwnd);
1425 }
1426
1427 static void test_columns(void)
1428 {
1429 HWND hwnd, header;
1430 LVCOLUMNA column;
1431 LVITEMA item;
1432 INT order[2];
1433 CHAR buff[5];
1434 DWORD rc;
1435
1436 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_LIST,
1437 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1438 ok(hwnd != NULL, "failed to create listview window\n");
1439
1440 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1441 ok(header == NULL, "got %p\n", header);
1442
1443 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1444 ok(rc == 0, "got %d\n", rc);
1445
1446 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1447 ok(header == NULL, "got %p\n", header);
1448
1449 DestroyWindow(hwnd);
1450
1451 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1452 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1453 ok(hwnd != NULL, "failed to create listview window\n");
1454
1455 /* Add a column with no mask */
1456 memset(&column, 0xcc, sizeof(column));
1457 column.mask = 0;
1458 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1459 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1460
1461 /* Check its width */
1462 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1463 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1464
1465 DestroyWindow(hwnd);
1466
1467 /* LVM_GETCOLUMNORDERARRAY */
1468 hwnd = create_listview_control(LVS_REPORT);
1469 subclass_header(hwnd);
1470
1471 memset(&column, 0, sizeof(column));
1472 column.mask = LVCF_WIDTH;
1473 column.cx = 100;
1474 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1475 expect(0, rc);
1476
1477 column.cx = 200;
1478 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1479 expect(1, rc);
1480
1481 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1482
1483 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1484 expect(1, rc);
1485 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1486 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1487
1488 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1489 expect(0, rc);
1490
1491 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1492
1493 /* LVM_SETCOLUMNORDERARRAY */
1494 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1495
1496 order[0] = 0;
1497 order[1] = 1;
1498 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1499 expect(1, rc);
1500
1501 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1502 expect(0, rc);
1503
1504 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1505
1506 /* after column added subitem is considered as present */
1507 insert_item(hwnd, 0);
1508
1509 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1510
1511 item.pszText = buff;
1512 item.cchTextMax = sizeof(buff);
1513 item.iItem = 0;
1514 item.iSubItem = 1;
1515 item.mask = LVIF_TEXT;
1516 memset(&g_itema, 0, sizeof(g_itema));
1517 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1518 expect(1, rc);
1519 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1520
1521 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1522 "get subitem text after column added", FALSE);
1523
1524 DestroyWindow(hwnd);
1525 }
1526
1527 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1528 static WNDPROC listviewWndProc;
1529 static HIMAGELIST test_create_imagelist;
1530
1531 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1532 {
1533 LRESULT ret;
1534
1535 if (uMsg == WM_CREATE)
1536 {
1537 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1538 lpcs->style |= LVS_REPORT;
1539 }
1540 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1541 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1542 return ret;
1543 }
1544
1545 static void test_create(void)
1546 {
1547 HWND hList;
1548 HWND hHeader;
1549 LONG_PTR ret;
1550 LONG r;
1551 LVCOLUMNA col;
1552 RECT rect;
1553 WNDCLASSEXA cls;
1554 DWORD style;
1555
1556 cls.cbSize = sizeof(WNDCLASSEXA);
1557 ok(GetClassInfoExA(GetModuleHandleA(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1558 listviewWndProc = cls.lpfnWndProc;
1559 cls.lpfnWndProc = create_test_wndproc;
1560 cls.lpszClassName = "MyListView32";
1561 ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
1562
1563 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1564 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1565 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1566 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1567
1568 if (!IsWindow(hHeader))
1569 {
1570 /* version 4.0 */
1571 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1572 DestroyWindow(hList);
1573 return;
1574 }
1575
1576 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1577 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1578 DestroyWindow(hList);
1579
1580 /* header isn't created on LVS_ICON and LVS_LIST styles */
1581 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1582 GetModuleHandleA(NULL), 0);
1583 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1584 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1585 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1586 /* insert column */
1587 memset(&col, 0, sizeof(LVCOLUMNA));
1588 col.mask = LVCF_WIDTH;
1589 col.cx = 100;
1590 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1591 expect(0, r);
1592 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1593 ok(IsWindow(hHeader), "Header should be created\n");
1594 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1595 style = GetWindowLongA(hHeader, GWL_STYLE);
1596 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1597 DestroyWindow(hList);
1598
1599 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1600 GetModuleHandleA(NULL), 0);
1601 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1602 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1603 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1604 /* insert column */
1605 memset(&col, 0, sizeof(LVCOLUMNA));
1606 col.mask = LVCF_WIDTH;
1607 col.cx = 100;
1608 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1609 expect(0, r);
1610 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1611 ok(IsWindow(hHeader), "Header should be created\n");
1612 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1613 DestroyWindow(hList);
1614
1615 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1616 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1617 GetModuleHandleA(NULL), 0);
1618 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1619 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1620 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1621 ok(IsWindow(hHeader), "Header should be created\n");
1622 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1623 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1624 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1625 ok(IsWindow(hHeader), "Header should be created\n");
1626 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1627 DestroyWindow(hList);
1628
1629 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1630 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1631 GetModuleHandleA(NULL), 0);
1632 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1633 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1634 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1635 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1636 ok(IsWindow(hHeader), "Header should be created\n");
1637 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1638 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1639 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1640 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1641 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1642 ok(IsWindow(hHeader), "Header should be created\n");
1643 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1644 DestroyWindow(hList);
1645
1646 /* LVS_REPORT without WS_VISIBLE */
1647 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1648 GetModuleHandleA(NULL), 0);
1649 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1650 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1651 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1652 /* insert column */
1653 memset(&col, 0, sizeof(LVCOLUMNA));
1654 col.mask = LVCF_WIDTH;
1655 col.cx = 100;
1656 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1657 expect(0, r);
1658 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1659 ok(IsWindow(hHeader), "Header should be created\n");
1660 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1661 DestroyWindow(hList);
1662
1663 /* LVS_REPORT without WS_VISIBLE, try to show it */
1664 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1665 GetModuleHandleA(NULL), 0);
1666 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1667 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1668 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1669 ShowWindow(hList, SW_SHOW);
1670 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1671 ok(IsWindow(hHeader), "Header should be created\n");
1672 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1673 DestroyWindow(hList);
1674
1675 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1676 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1677 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1678 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1679 ok(IsWindow(hHeader), "Header should be created\n");
1680 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1681 /* HDS_DRAGDROP set by default */
1682 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1683 DestroyWindow(hList);
1684
1685 /* setting LVS_EX_HEADERDRAGDROP creates header */
1686 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1687 GetModuleHandleA(NULL), 0);
1688 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1689 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1690 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1691 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1692 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1693 ok(IsWindow(hHeader) ||
1694 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1695 "Header should be created\n");
1696 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1697 DestroyWindow(hList);
1698
1699 /* setting LVS_EX_GRIDLINES creates header */
1700 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1701 GetModuleHandleA(NULL), 0);
1702 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1703 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1704 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1705 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1706 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1707 ok(IsWindow(hHeader) ||
1708 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1709 "Header should be created\n");
1710 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1711 DestroyWindow(hList);
1712
1713 /* setting LVS_EX_FULLROWSELECT creates header */
1714 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1715 GetModuleHandleA(NULL), 0);
1716 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1717 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1718 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1719 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1720 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1721 ok(IsWindow(hHeader) ||
1722 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1723 "Header should be created\n");
1724 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1725 DestroyWindow(hList);
1726
1727 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1728 hList = create_listview_control(LVS_ICON);
1729 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1730 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1731 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1732 DestroyWindow(hList);
1733
1734 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1735 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1736 GetModuleHandleA(NULL), 0);
1737 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1738 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1739
1740 rect.left = LVIR_BOUNDS;
1741 rect.top = 1;
1742 rect.right = rect.bottom = -10;
1743 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1744 /* right value contains garbage, probably because header columns are not set up */
1745 expect(0, rect.bottom);
1746 expect(1, r);
1747
1748 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1749 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1750 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1751
1752 DestroyWindow(hList);
1753
1754 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1755 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1756 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1757 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1758 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1759 DestroyWindow(hList);
1760 }
1761
1762 static void test_redraw(void)
1763 {
1764 HWND hwnd;
1765 HDC hdc;
1766 BOOL res;
1767 DWORD r;
1768
1769 hwnd = create_listview_control(LVS_REPORT);
1770 subclass_header(hwnd);
1771
1772 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1773
1774 InvalidateRect(hwnd, NULL, TRUE);
1775 UpdateWindow(hwnd);
1776 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1777
1778 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1779
1780 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1781 /* 1. Without backbuffer */
1782 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1783 expect(TRUE, res);
1784
1785 hdc = GetWindowDC(hwndparent);
1786
1787 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1788 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1789 ok(r == 1, "Expected not zero result\n");
1790 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1791 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1792
1793 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1794 expect(TRUE, res);
1795
1796 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1797 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1798 expect(1, r);
1799 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1800 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1801
1802 /* 2. With backbuffer */
1803 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1804 LVS_EX_DOUBLEBUFFER);
1805 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1806 expect(TRUE, res);
1807
1808 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1809 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1810 expect(1, r);
1811 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1812 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1813
1814 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1815 expect(TRUE, res);
1816
1817 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1818 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1819 todo_wine expect(1, r);
1820 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1821 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1822
1823 ReleaseDC(hwndparent, hdc);
1824
1825 DestroyWindow(hwnd);
1826 }
1827
1828 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1829 {
1830 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1831
1832 if(message == WM_NOTIFY) {
1833 NMHDR *nmhdr = (NMHDR*)lParam;
1834 if(nmhdr->code == NM_CUSTOMDRAW) {
1835 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1836 struct message msg;
1837
1838 msg.message = message;
1839 msg.flags = sent|wparam|lparam|custdraw;
1840 msg.wParam = wParam;
1841 msg.lParam = lParam;
1842 msg.id = nmhdr->code;
1843 msg.stage = nmlvcd->nmcd.dwDrawStage;
1844 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1845
1846 switch(nmlvcd->nmcd.dwDrawStage) {
1847 case CDDS_PREPAINT:
1848 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1849 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1850 case CDDS_ITEMPREPAINT:
1851 nmlvcd->clrTextBk = CLR_DEFAULT;
1852 nmlvcd->clrText = RGB(0, 255, 0);
1853 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1854 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1855 clr = GetBkColor(nmlvcd->nmcd.hdc);
1856 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1857 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1858 if (nmlvcd->iSubItem)
1859 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1860 else
1861 ok(clr == c0ffee, "clr=%.8x\n", clr);
1862 return CDRF_NOTIFYPOSTPAINT;
1863 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1864 clr = GetBkColor(nmlvcd->nmcd.hdc);
1865 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1866 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1867 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1868 return CDRF_DODEFAULT;
1869 }
1870 return CDRF_DODEFAULT;
1871 }
1872 }
1873
1874 return DefWindowProcA(hwnd, message, wParam, lParam);
1875 }
1876
1877 static void test_customdraw(void)
1878 {
1879 HWND hwnd;
1880 WNDPROC oldwndproc;
1881
1882 hwnd = create_listview_control(LVS_REPORT);
1883
1884 insert_column(hwnd, 0);
1885 insert_column(hwnd, 1);
1886 insert_item(hwnd, 0);
1887
1888 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1889 (LONG_PTR)cd_wndproc);
1890
1891 InvalidateRect(hwnd, NULL, TRUE);
1892 UpdateWindow(hwnd);
1893
1894 /* message tests */
1895 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1896 InvalidateRect(hwnd, NULL, TRUE);
1897 UpdateWindow(hwnd);
1898 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1899
1900 DestroyWindow(hwnd);
1901
1902 hwnd = create_listview_control(LVS_LIST);
1903
1904 insert_column(hwnd, 0);
1905 insert_column(hwnd, 1);
1906 insert_item(hwnd, 0);
1907
1908 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1909 InvalidateRect(hwnd, NULL, TRUE);
1910 UpdateWindow(hwnd);
1911 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1912
1913 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1914 DestroyWindow(hwnd);
1915 }
1916
1917 static void test_icon_spacing(void)
1918 {
1919 /* LVM_SETICONSPACING */
1920 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1921
1922 HWND hwnd;
1923 WORD w, h;
1924 INT r;
1925
1926 hwnd = create_listview_control(LVS_ICON);
1927 ok(hwnd != NULL, "failed to create a listview window\n");
1928
1929 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1930 expect(NFR_ANSI, r);
1931
1932 /* reset the icon spacing to defaults */
1933 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1934
1935 /* now we can request what the defaults are */
1936 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1937 w = LOWORD(r);
1938 h = HIWORD(r);
1939
1940 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1941
1942 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1943 ok(r == MAKELONG(w, h) ||
1944 broken(r == MAKELONG(w, w)), /* win98 */
1945 "Expected %d, got %d\n", MAKELONG(w, h), r);
1946
1947 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1948 if (r == 0)
1949 {
1950 /* version 4.0 */
1951 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1952 DestroyWindow(hwnd);
1953 return;
1954 }
1955 expect(MAKELONG(20,30), r);
1956
1957 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1958 expect(MAKELONG(25,35), r);
1959
1960 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1961
1962 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1963 DestroyWindow(hwnd);
1964 }
1965
1966 static void test_color(void)
1967 {
1968 RECT rect;
1969 HWND hwnd;
1970 DWORD r;
1971 int i;
1972
1973 COLORREF color;
1974 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1975
1976 hwnd = create_listview_control(LVS_REPORT);
1977 ok(hwnd != NULL, "failed to create a listview window\n");
1978
1979 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1980
1981 for (i = 0; i < 4; i++)
1982 {
1983 color = colors[i];
1984
1985 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
1986 expect(TRUE, r);
1987 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
1988 expect(color, r);
1989
1990 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
1991 expect (TRUE, r);
1992 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1993 expect(color, r);
1994
1995 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1996 expect(TRUE, r);
1997 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1998 expect(color, r);
1999 }
2000
2001 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
2002 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2003
2004 /* invalidation test done separately to avoid a message chain mess */
2005 r = ValidateRect(hwnd, NULL);
2006 expect(TRUE, r);
2007 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2008 expect(TRUE, r);
2009
2010 rect.right = rect.bottom = 1;
2011 r = GetUpdateRect(hwnd, &rect, TRUE);
2012 todo_wine expect(FALSE, r);
2013 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2014
2015 r = ValidateRect(hwnd, NULL);
2016 expect(TRUE, r);
2017 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2018 expect(TRUE, r);
2019
2020 rect.right = rect.bottom = 1;
2021 r = GetUpdateRect(hwnd, &rect, TRUE);
2022 todo_wine expect(FALSE, r);
2023 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2024
2025 r = ValidateRect(hwnd, NULL);
2026 expect(TRUE, r);
2027 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2028 expect(TRUE, r);
2029
2030 rect.right = rect.bottom = 1;
2031 r = GetUpdateRect(hwnd, &rect, TRUE);
2032 todo_wine expect(FALSE, r);
2033 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2034
2035 DestroyWindow(hwnd);
2036 }
2037
2038 static void test_item_count(void)
2039 {
2040 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2041
2042 HWND hwnd;
2043 DWORD r;
2044 HDC hdc;
2045 HFONT hOldFont;
2046 TEXTMETRICA tm;
2047 RECT rect;
2048 INT height;
2049
2050 LVITEMA item0;
2051 LVITEMA item1;
2052 LVITEMA item2;
2053 static CHAR item0text[] = "item0";
2054 static CHAR item1text[] = "item1";
2055 static CHAR item2text[] = "item2";
2056
2057 hwnd = create_listview_control(LVS_REPORT);
2058 ok(hwnd != NULL, "failed to create a listview window\n");
2059
2060 /* resize in dpiaware manner to fit all 3 items added */
2061 hdc = GetDC(0);
2062 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2063 GetTextMetricsA(hdc, &tm);
2064 /* 2 extra pixels for bounds and header border */
2065 height = tm.tmHeight + 2;
2066 SelectObject(hdc, hOldFont);
2067 ReleaseDC(0, hdc);
2068
2069 GetWindowRect(hwnd, &rect);
2070 /* 3 items + 1 header + 1 to be sure */
2071 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2072
2073 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2074
2075 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2076 expect(0, r);
2077
2078 /* [item0] */
2079 item0.mask = LVIF_TEXT;
2080 item0.iItem = 0;
2081 item0.iSubItem = 0;
2082 item0.pszText = item0text;
2083 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2084 expect(0, r);
2085
2086 /* [item0, item1] */
2087 item1.mask = LVIF_TEXT;
2088 item1.iItem = 1;
2089 item1.iSubItem = 0;
2090 item1.pszText = item1text;
2091 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2092 expect(1, r);
2093
2094 /* [item0, item1, item2] */
2095 item2.mask = LVIF_TEXT;
2096 item2.iItem = 2;
2097 item2.iSubItem = 0;
2098 item2.pszText = item2text;
2099 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2100 expect(2, r);
2101
2102 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2103 expect(3, r);
2104
2105 /* [item0, item1] */
2106 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2107 expect(TRUE, r);
2108
2109 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2110 expect(2, r);
2111
2112 /* [] */
2113 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2114 expect(TRUE, r);
2115
2116 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2117 expect(0, r);
2118
2119 /* [item0] */
2120 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2121 expect(0, r);
2122
2123 /* [item0, item1] */
2124 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2125 expect(1, r);
2126
2127 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2128 expect(2, r);
2129
2130 /* [item0, item1, item2] */
2131 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2132 expect(2, r);
2133
2134 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2135 expect(3, r);
2136
2137 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2138
2139 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2140 DestroyWindow(hwnd);
2141 }
2142
2143 static void test_item_position(void)
2144 {
2145 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2146
2147 HWND hwnd;
2148 DWORD r;
2149 POINT position;
2150
2151 LVITEMA item0;
2152 LVITEMA item1;
2153 LVITEMA item2;
2154 static CHAR item0text[] = "item0";
2155 static CHAR item1text[] = "item1";
2156 static CHAR item2text[] = "item2";
2157
2158 hwnd = create_listview_control(LVS_ICON);
2159 ok(hwnd != NULL, "failed to create a listview window\n");
2160
2161 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2162
2163 /* [item0] */
2164 item0.mask = LVIF_TEXT;
2165 item0.iItem = 0;
2166 item0.iSubItem = 0;
2167 item0.pszText = item0text;
2168 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2169 expect(0, r);
2170
2171 /* [item0, item1] */
2172 item1.mask = LVIF_TEXT;
2173 item1.iItem = 1;
2174 item1.iSubItem = 0;
2175 item1.pszText = item1text;
2176 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2177 expect(1, r);
2178
2179 /* [item0, item1, item2] */
2180 item2.mask = LVIF_TEXT;
2181 item2.iItem = 2;
2182 item2.iSubItem = 0;
2183 item2.pszText = item2text;
2184 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2185 expect(2, r);
2186
2187 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2188 expect(TRUE, r);
2189 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2190 expect(TRUE, r);
2191 expect2(10, 5, position.x, position.y);
2192
2193 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2194 expect(TRUE, r);
2195 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2196 expect(TRUE, r);
2197 expect2(0, 0, position.x, position.y);
2198
2199 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2200 expect(TRUE, r);
2201 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2202 expect(TRUE, r);
2203 expect2(20, 20, position.x, position.y);
2204
2205 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2206
2207 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2208 DestroyWindow(hwnd);
2209 }
2210
2211 static void test_getorigin(void)
2212 {
2213 /* LVM_GETORIGIN */
2214
2215 HWND hwnd;
2216 DWORD r;
2217 POINT position;
2218
2219 position.x = position.y = 0;
2220
2221 hwnd = create_listview_control(LVS_ICON);
2222 ok(hwnd != NULL, "failed to create a listview window\n");
2223 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2224
2225 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2226 expect(TRUE, r);
2227 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2228 DestroyWindow(hwnd);
2229
2230 hwnd = create_listview_control(LVS_SMALLICON);
2231 ok(hwnd != NULL, "failed to create a listview window\n");
2232 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2233
2234 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2235 expect(TRUE, r);
2236 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2237 DestroyWindow(hwnd);
2238
2239 hwnd = create_listview_control(LVS_LIST);
2240 ok(hwnd != NULL, "failed to create a listview window\n");
2241 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2242
2243 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2244 expect(FALSE, r);
2245 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2246 DestroyWindow(hwnd);
2247
2248 hwnd = create_listview_control(LVS_REPORT);
2249 ok(hwnd != NULL, "failed to create a listview window\n");
2250 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2251
2252 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2253 expect(FALSE, r);
2254 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2255 DestroyWindow(hwnd);
2256 }
2257
2258 static void test_multiselect(void)
2259 {
2260 typedef struct t_select_task
2261 {
2262 const char *descr;
2263 int initPos;
2264 int loopVK;
2265 int count;
2266 int result;
2267 } select_task;
2268
2269 HWND hwnd;
2270 INT r;
2271 int i,j,item_count,selected_count;
2272 static const int items=5;
2273 BYTE kstate[256];
2274 select_task task;
2275 LONG_PTR style;
2276 LVITEMA item;
2277
2278 static struct t_select_task task_list[] = {
2279 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2280 { "using VK_UP", -1, VK_UP, -1, -1 },
2281 { "using VK_END", 0, VK_END, 1, -1 },
2282 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2283 };
2284
2285 hwnd = create_listview_control(LVS_REPORT);
2286
2287 for (i = 0; i < items; i++)
2288 insert_item(hwnd, 0);
2289
2290 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2291 expect(items, item_count);
2292
2293 for (i = 0; i < 4; i++) {
2294 LVITEMA item;
2295
2296 task = task_list[i];
2297
2298 /* deselect all items */
2299 item.state = 0;
2300 item.stateMask = LVIS_SELECTED;
2301 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2302 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2303
2304 /* set initial position */
2305 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2306
2307 item.state = LVIS_SELECTED;
2308 item.stateMask = LVIS_SELECTED;
2309 SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2310
2311 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2312 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2313
2314 /* Set SHIFT key pressed */
2315 GetKeyboardState(kstate);
2316 kstate[VK_SHIFT]=0x80;
2317 SetKeyboardState(kstate);
2318
2319 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2320 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2321 expect(0,r);
2322 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2323 expect(0,r);
2324 }
2325
2326 selected_count = (int)SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2327
2328 ok((task.result == -1 ? item_count : task.result) == selected_count, "Failed multiple selection %s. There should be %d selected items (is %d)\n", task.descr, item_count, selected_count);
2329
2330 /* Set SHIFT key released */
2331 GetKeyboardState(kstate);
2332 kstate[VK_SHIFT]=0x00;
2333 SetKeyboardState(kstate);
2334 }
2335 DestroyWindow(hwnd);
2336
2337 /* make multiple selection, then switch to LVS_SINGLESEL */
2338 hwnd = create_listview_control(LVS_REPORT);
2339 for (i=0;i<items;i++) {
2340 insert_item(hwnd, 0);
2341 }
2342 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2343 expect(items,item_count);
2344
2345 /* try with NULL pointer */
2346 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2347 expect(FALSE, r);
2348
2349 /* select all, check notifications */
2350 item.state = 0;
2351 item.stateMask = LVIS_SELECTED;
2352 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2353
2354 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2355
2356 item.stateMask = LVIS_SELECTED;
2357 item.state = LVIS_SELECTED;
2358 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2359 expect(TRUE, r);
2360
2361 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2362 "select all notification", FALSE);
2363
2364 /* select all again (all selected already) */
2365 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2366
2367 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2368
2369 item.stateMask = LVIS_SELECTED;
2370 item.state = LVIS_SELECTED;
2371 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2372 expect(TRUE, r);
2373
2374 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2375 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2376 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2377
2378 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2379 "select all notification 2", FALSE);
2380
2381 /* deselect all items */
2382 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2383
2384 item.state = 0;
2385 item.stateMask = LVIS_SELECTED;
2386 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2387
2388 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2389 "deselect all notification", FALSE);
2390
2391 /* deselect all items again */
2392 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2393 item.state = 0;
2394 item.stateMask = LVIS_SELECTED;
2395 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2396 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2397
2398 /* any non-zero state value does the same */
2399 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2400
2401 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2402
2403 item.stateMask = LVIS_SELECTED;
2404 item.state = LVIS_CUT;
2405 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2406 expect(TRUE, r);
2407
2408 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2409 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2410 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2411
2412 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2413 "set state all notification 3", FALSE);
2414
2415 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2416 for (i = 0; i < 3; i++) {
2417 item.state = LVIS_SELECTED;
2418 item.stateMask = LVIS_SELECTED;
2419 SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2420 }
2421
2422 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2423 expect(3, r);
2424 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2425 expect(-1, r);
2426
2427 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2428 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2429 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2430 /* check that style is accepted */
2431 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2432 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2433
2434 for (i=0;i<3;i++) {
2435 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2436 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2437 }
2438 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2439 expect(3, r);
2440 SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2441 expect(3, r);
2442
2443 /* select one more */
2444 item.state = LVIS_SELECTED;
2445 item.stateMask = LVIS_SELECTED;
2446 SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2447
2448 for (i=0;i<3;i++) {
2449 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2450 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2451 }
2452
2453 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2454 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2455
2456 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2457 expect(1, r);
2458 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2459 expect(-1, r);
2460
2461 /* try to select all on LVS_SINGLESEL */
2462 memset(&item, 0, sizeof(item));
2463 item.stateMask = LVIS_SELECTED;
2464 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2465 expect(TRUE, r);
2466 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2467
2468 item.stateMask = LVIS_SELECTED;
2469 item.state = LVIS_SELECTED;
2470 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2471 expect(FALSE, r);
2472
2473 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2474 expect(0, r);
2475 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2476 expect(-1, r);
2477
2478 /* try to deselect all on LVS_SINGLESEL */
2479 item.stateMask = LVIS_SELECTED;
2480 item.state = LVIS_SELECTED;
2481 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2482 expect(TRUE, r);
2483
2484 item.stateMask = LVIS_SELECTED;
2485 item.state = 0;
2486 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2487 expect(TRUE, r);
2488 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2489 expect(0, r);
2490
2491 /* 1. selection mark is update when new focused item is set */
2492 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2493 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2494
2495 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2496 expect(-1, r);
2497
2498 item.stateMask = LVIS_FOCUSED;
2499 item.state = LVIS_FOCUSED;
2500 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2501 expect(TRUE, r);
2502
2503 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2504 expect(0, r);
2505
2506 /* it's not updated if already set */
2507 item.stateMask = LVIS_FOCUSED;
2508 item.state = LVIS_FOCUSED;
2509 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2510 expect(TRUE, r);
2511
2512 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2513 expect(0, r);
2514
2515 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2516 expect(0, r);
2517
2518 item.stateMask = LVIS_FOCUSED;
2519 item.state = LVIS_FOCUSED;
2520 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2521 expect(TRUE, r);
2522
2523 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2524 expect(-1, r);
2525
2526 /* need to reset focused item first */
2527 item.stateMask = LVIS_FOCUSED;
2528 item.state = 0;
2529 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2530 expect(TRUE, r);
2531
2532 item.stateMask = LVIS_FOCUSED;
2533 item.state = LVIS_FOCUSED;
2534 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2535 expect(TRUE, r);
2536
2537 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2538 expect(2, r);
2539
2540 item.stateMask = LVIS_FOCUSED;
2541 item.state = 0;
2542 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2543 expect(TRUE, r);
2544
2545 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2546 expect(2, r);
2547
2548 /* 2. same tests, with LVM_SETITEM */
2549 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2550 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2551
2552 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2553 expect(2, r);
2554
2555 item.stateMask = LVIS_FOCUSED;
2556 item.state = LVIS_FOCUSED;
2557 item.mask = LVIF_STATE;
2558 item.iItem = item.iSubItem = 0;
2559 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2560 expect(TRUE, r);
2561
2562 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2563 expect(0, r);
2564
2565 /* it's not updated if already set */
2566 item.stateMask = LVIS_FOCUSED;
2567 item.state = LVIS_FOCUSED;
2568 item.mask = LVIF_STATE;
2569 item.iItem = 1;
2570 item.iSubItem = 0;
2571 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2572 expect(TRUE, r);
2573
2574 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2575 expect(0, r);
2576
2577 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2578 expect(0, r);
2579
2580 item.stateMask = LVIS_FOCUSED;
2581 item.state = LVIS_FOCUSED;
2582 item.mask = LVIF_STATE;
2583 item.iItem = 1;
2584 item.iSubItem = 0;
2585 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2586 expect(TRUE, r);
2587
2588 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2589 expect(-1, r);
2590
2591 /* need to reset focused item first */
2592 item.stateMask = LVIS_FOCUSED;
2593 item.state = 0;
2594 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2595 expect(TRUE, r);
2596
2597 item.stateMask = LVIS_FOCUSED;
2598 item.state = LVIS_FOCUSED;
2599 item.mask = LVIF_STATE;
2600 item.iItem = 2;
2601 item.iSubItem = 0;
2602 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2603 expect(TRUE, r);
2604
2605 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2606 expect(2, r);
2607
2608 item.stateMask = LVIS_FOCUSED;
2609 item.state = 0;
2610 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2611 expect(TRUE, r);
2612
2613 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2614 expect(2, r);
2615
2616 DestroyWindow(hwnd);
2617 }
2618
2619 static void test_subitem_rect(void)
2620 {
2621 HWND hwnd;
2622 DWORD r;
2623 LVCOLUMNA col;
2624 RECT rect, rect2;
2625 INT arr[3];
2626
2627 /* test LVM_GETSUBITEMRECT for header */
2628 hwnd = create_listview_control(LVS_REPORT);
2629 ok(hwnd != NULL, "failed to create a listview window\n");
2630 /* add some columns */
2631 memset(&col, 0, sizeof(LVCOLUMNA));
2632 col.mask = LVCF_WIDTH;
2633 col.cx = 100;
2634 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2635 expect(0, r);
2636 col.cx = 150;
2637 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2638 expect(1, r);
2639 col.cx = 200;
2640 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2641 expect(2, r);
2642 /* item = -1 means header, subitem index is 1 based */
2643 rect.left = LVIR_BOUNDS;
2644 rect.top = 0;
2645 rect.right = rect.bottom = 0;
2646 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2647 expect(0, r);
2648
2649 rect.left = LVIR_BOUNDS;
2650 rect.top = 1;
2651 rect.right = rect.bottom = 0;
2652 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2653 expect(1, r);
2654
2655 expect(100, rect.left);
2656 expect(250, rect.right);
2657 expect(3, rect.top);
2658
2659 rect.left = LVIR_BOUNDS;
2660 rect.top = 2;
2661 rect.right = rect.bottom = 0;
2662 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2663 expect(1, r);
2664
2665 expect(250, rect.left);
2666 expect(450, rect.right);
2667 expect(3, rect.top);
2668
2669 /* item LVS_REPORT padding isn't applied to subitems */
2670 insert_item(hwnd, 0);
2671
2672 rect.left = LVIR_BOUNDS;
2673 rect.top = 1;
2674 rect.right = rect.bottom = 0;
2675 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2676 expect(1, r);
2677 expect(100, rect.left);
2678 expect(250, rect.right);
2679
2680 rect.left = LVIR_ICON;
2681 rect.top = 1;
2682 rect.right = rect.bottom = 0;
2683 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2684 expect(1, r);
2685 /* no icon attached - zero width rectangle, with no left padding */
2686 expect(100, rect.left);
2687 expect(100, rect.right);
2688
2689 rect.left = LVIR_LABEL;
2690 rect.top = 1;
2691 rect.right = rect.bottom = 0;
2692 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2693 expect(1, r);
2694 /* same as full LVIR_BOUNDS */
2695 expect(100, rect.left);
2696 expect(250, rect.right);
2697
2698 SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2699
2700 rect.left = LVIR_BOUNDS;
2701 rect.top = 1;
2702 rect.right = rect.bottom = 0;
2703 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2704 expect(1, r);
2705 expect(90, rect.left);
2706 expect(240, rect.right);
2707
2708 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2709
2710 /* test header interaction */
2711 subclass_header(hwnd);
2712 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2713
2714 rect.left = LVIR_BOUNDS;
2715 rect.top = 1;
2716 rect.right = rect.bottom = 0;
2717 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2718 expect(1, r);
2719
2720 rect.left = LVIR_BOUNDS;
2721 rect.top = 1;
2722 rect.right = rect.bottom = 0;
2723 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2724 expect(1, r);
2725
2726 rect.left = LVIR_BOUNDS;
2727 rect.top = 1;
2728 rect.right = rect.bottom = 0;
2729 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2730 expect(1, r);
2731
2732 rect.left = LVIR_BOUNDS;
2733 rect.top = 1;
2734 rect.right = rect.bottom = 0;
2735 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2736 expect(1, r);
2737
2738 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2739
2740 DestroyWindow(hwnd);
2741
2742 /* test subitem rects after re-arranging columns */
2743 hwnd = create_listview_control(LVS_REPORT);
2744 ok(hwnd != NULL, "failed to create a listview window\n");
2745 memset(&col, 0, sizeof(LVCOLUMNA));
2746 col.mask = LVCF_WIDTH;
2747
2748 col.cx = 100;
2749 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2750 expect(0, r);
2751
2752 col.cx = 200;
2753 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2754 expect(1, r);
2755
2756 col.cx = 300;
2757 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2758 expect(2, r);
2759
2760 insert_item(hwnd, 0);
2761 insert_item(hwnd, 1);
2762
2763 /* wrong item is refused for main item */
2764 rect.left = LVIR_BOUNDS;
2765 rect.top = 0;
2766 rect.right = rect.bottom = -1;
2767 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2768 expect(FALSE, r);
2769
2770 /* for subitems rectangle is calculated even if there's no item added */
2771 rect.left = LVIR_BOUNDS;
2772 rect.top = 1;
2773 rect.right = rect.bottom = -1;
2774 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2775 expect(TRUE, r);
2776
2777 rect2.left = LVIR_BOUNDS;
2778 rect2.top = 1;
2779 rect2.right = rect2.bottom = -1;
2780 r = Send