[COMCTL32_WINETEST] Sync with Wine Staging 1.9.4. CORE-10912
[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 ownerdata_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 todo_wine_if(todo_item)
797 {
798 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
799 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
800 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
801 }
802
803 if (todo_flags)
804 {
805 todo_wine
806 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
807 }
808 else if (broken_flags)
809 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
810 "Expected flags %x, got %x\n", flags, lpht.flags);
811 else
812 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
813 }
814
815 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
816
817 /* Performs a single LVM_SUBITEMHITTEST test */
818 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
819 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
820 {
821 LVHITTESTINFO lpht;
822 INT ret;
823
824 lpht.pt.x = x;
825 lpht.pt.y = y;
826
827 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
828
829 todo_wine_if(todo_item)
830 {
831 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
832 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
833 }
834
835 todo_wine_if(todo_subitem)
836 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
837
838 todo_wine_if(todo_flags)
839 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
840 }
841
842 #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__)
843
844 static void test_images(void)
845 {
846 HWND hwnd;
847 INT r;
848 LVITEMA item;
849 HIMAGELIST himl;
850 HBITMAP hbmp;
851 RECT r1, r2;
852 static CHAR hello[] = "hello";
853
854 himl = ImageList_Create(40, 40, 0, 4, 4);
855 ok(himl != NULL, "failed to create imagelist\n");
856
857 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
858 ok(hbmp != NULL, "failed to create bitmap\n");
859
860 r = ImageList_Add(himl, hbmp, 0);
861 ok(r == 0, "should be zero\n");
862
863 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
864 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
865 ok(hwnd != NULL, "failed to create listview window\n");
866
867 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
868 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
869
870 ok(r == 0, "should return zero\n");
871
872 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
873 ok(r == 0, "should return zero\n");
874
875 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
876 ok(r != 0, "got 0\n");
877
878 /* returns dimensions */
879
880 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
881 ok(r == 0, "should be zero items\n");
882
883 item.mask = LVIF_IMAGE | LVIF_TEXT;
884 item.iItem = 0;
885 item.iSubItem = 1;
886 item.iImage = 0;
887 item.pszText = 0;
888 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
889 ok(r == -1, "should fail\n");
890
891 item.iSubItem = 0;
892 item.pszText = hello;
893 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
894 ok(r == 0, "should not fail\n");
895
896 memset(&r1, 0, sizeof r1);
897 r1.left = LVIR_ICON;
898 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
899 expect(1, r);
900
901 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
902 ok(r == TRUE, "should not fail\n");
903
904 item.iSubItem = 0;
905 item.pszText = hello;
906 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
907 ok(r == 0, "should not fail\n");
908
909 memset(&r2, 0, sizeof r2);
910 r2.left = LVIR_ICON;
911 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
912 expect(1, r);
913
914 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
915
916 DestroyWindow(hwnd);
917 }
918
919 static void test_checkboxes(void)
920 {
921 HWND hwnd;
922 LVITEMA item;
923 DWORD r;
924 static CHAR text[] = "Text",
925 text2[] = "Text2",
926 text3[] = "Text3";
927
928 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
929 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
930 ok(hwnd != NULL, "failed to create listview window\n");
931
932 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
933 item.mask = LVIF_TEXT | LVIF_STATE;
934 item.stateMask = 0xffff;
935 item.state = 0xfccc;
936 item.iItem = 0;
937 item.iSubItem = 0;
938 item.pszText = text;
939 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
940 expect(0, r);
941
942 item.iItem = 0;
943 item.mask = LVIF_STATE;
944 item.stateMask = 0xffff;
945 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
946 expect(1, r);
947 ok(item.state == 0xfccc, "state %x\n", item.state);
948
949 /* Don't set LVIF_STATE */
950 item.mask = LVIF_TEXT;
951 item.stateMask = 0xffff;
952 item.state = 0xfccc;
953 item.iItem = 1;
954 item.iSubItem = 0;
955 item.pszText = text;
956 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
957 expect(1, r);
958
959 item.iItem = 1;
960 item.mask = LVIF_STATE;
961 item.stateMask = 0xffff;
962 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
963 expect(1, r);
964 ok(item.state == 0, "state %x\n", item.state);
965
966 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
967 expect(0, r);
968
969 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
970 item.iItem = 0;
971 item.mask = LVIF_STATE;
972 item.stateMask = 0xffff;
973 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
974 expect(1, r);
975 if (item.state != 0x1ccc)
976 {
977 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
978 DestroyWindow(hwnd);
979 return;
980 }
981
982 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
983 item.iItem = 2;
984 item.mask = LVIF_TEXT;
985 item.state = 0;
986 item.pszText = text2;
987 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
988 expect(2, r);
989
990 item.iItem = 2;
991 item.mask = LVIF_STATE;
992 item.stateMask = 0xffff;
993 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
994 expect(1, r);
995 ok(item.state == 0x1000, "state %x\n", item.state);
996
997 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
998 item.iItem = 3;
999 item.mask = LVIF_TEXT | LVIF_STATE;
1000 item.stateMask = 0xffff;
1001 item.state = 0x2aaa;
1002 item.pszText = text3;
1003 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1004 expect(3, r);
1005
1006 item.iItem = 3;
1007 item.mask = LVIF_STATE;
1008 item.stateMask = 0xffff;
1009 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1010 expect(1, r);
1011 ok(item.state == 0x1aaa, "state %x\n", item.state);
1012
1013 /* Set an item's state to checked */
1014 item.iItem = 3;
1015 item.mask = LVIF_STATE;
1016 item.stateMask = 0xf000;
1017 item.state = 0x2000;
1018 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1019 expect(1, r);
1020
1021 item.iItem = 3;
1022 item.mask = LVIF_STATE;
1023 item.stateMask = 0xffff;
1024 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1025 expect(1, r);
1026 ok(item.state == 0x2aaa, "state %x\n", item.state);
1027
1028 /* Check that only the bits we asked for are returned,
1029 * and that all the others are set to zero
1030 */
1031 item.iItem = 3;
1032 item.mask = LVIF_STATE;
1033 item.stateMask = 0xf000;
1034 item.state = 0xffff;
1035 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1036 expect(1, r);
1037 ok(item.state == 0x2000, "state %x\n", item.state);
1038
1039 /* Set the style again and check that doesn't change an item's state */
1040 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1041 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1042
1043 item.iItem = 3;
1044 item.mask = LVIF_STATE;
1045 item.stateMask = 0xffff;
1046 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1047 expect(1, r);
1048 ok(item.state == 0x2aaa, "state %x\n", item.state);
1049
1050 /* Unsetting the checkbox extended style doesn't change an item's state */
1051 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1052 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1053
1054 item.iItem = 3;
1055 item.mask = LVIF_STATE;
1056 item.stateMask = 0xffff;
1057 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1058 expect(1, r);
1059 ok(item.state == 0x2aaa, "state %x\n", item.state);
1060
1061 /* Now setting the style again will change an item's state */
1062 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1063 expect(0, r);
1064
1065 item.iItem = 3;
1066 item.mask = LVIF_STATE;
1067 item.stateMask = 0xffff;
1068 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1069 expect(1, r);
1070 ok(item.state == 0x1aaa, "state %x\n", item.state);
1071
1072 /* Toggle checkbox tests (bug 9934) */
1073 memset (&item, 0xcc, sizeof(item));
1074 item.mask = LVIF_STATE;
1075 item.iItem = 3;
1076 item.iSubItem = 0;
1077 item.state = LVIS_FOCUSED;
1078 item.stateMask = LVIS_FOCUSED;
1079 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1080 expect(1, r);
1081
1082 item.iItem = 3;
1083 item.mask = LVIF_STATE;
1084 item.stateMask = 0xffff;
1085 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1086 expect(1, r);
1087 ok(item.state == 0x1aab, "state %x\n", item.state);
1088
1089 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1090 expect(0, r);
1091 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1092 expect(0, r);
1093
1094 item.iItem = 3;
1095 item.mask = LVIF_STATE;
1096 item.stateMask = 0xffff;
1097 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1098 expect(1, r);
1099 ok(item.state == 0x2aab, "state %x\n", item.state);
1100
1101 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1102 expect(0, r);
1103 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1104 expect(0, r);
1105
1106 item.iItem = 3;
1107 item.mask = LVIF_STATE;
1108 item.stateMask = 0xffff;
1109 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1110 expect(1, r);
1111 ok(item.state == 0x1aab, "state %x\n", item.state);
1112
1113 DestroyWindow(hwnd);
1114 }
1115
1116 static void insert_column(HWND hwnd, int idx)
1117 {
1118 LVCOLUMNA column;
1119 INT rc;
1120
1121 memset(&column, 0xcc, sizeof(column));
1122 column.mask = LVCF_SUBITEM;
1123 column.iSubItem = idx;
1124
1125 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1126 expect(idx, rc);
1127 }
1128
1129 static void insert_item(HWND hwnd, int idx)
1130 {
1131 static CHAR text[] = "foo";
1132
1133 LVITEMA item;
1134 INT rc;
1135
1136 memset(&item, 0xcc, sizeof (item));
1137 item.mask = LVIF_TEXT;
1138 item.iItem = idx;
1139 item.iSubItem = 0;
1140 item.pszText = text;
1141
1142 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1143 expect(idx, rc);
1144 }
1145
1146 static void test_items(void)
1147 {
1148 const LPARAM lparamTest = 0x42;
1149 static CHAR text[] = "Text";
1150 char buffA[5];
1151 HWND hwnd;
1152 LVITEMA item;
1153 DWORD r;
1154
1155 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1156 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1157 ok(hwnd != NULL, "failed to create listview window\n");
1158
1159 /*
1160 * Test setting/getting item params
1161 */
1162
1163 /* Set up two columns */
1164 insert_column(hwnd, 0);
1165 insert_column(hwnd, 1);
1166
1167 /* LVIS_SELECTED with zero stateMask */
1168 /* set */
1169 memset (&item, 0, sizeof (item));
1170 item.mask = LVIF_STATE;
1171 item.state = LVIS_SELECTED;
1172 item.stateMask = 0;
1173 item.iItem = 0;
1174 item.iSubItem = 0;
1175 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1176 expect(0, r);
1177 /* get */
1178 memset (&item, 0xcc, sizeof (item));
1179 item.mask = LVIF_STATE;
1180 item.stateMask = LVIS_SELECTED;
1181 item.state = 0;
1182 item.iItem = 0;
1183 item.iSubItem = 0;
1184 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1185 expect(1, r);
1186 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1187 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1188
1189 /* LVIS_SELECTED with zero stateMask */
1190 /* set */
1191 memset (&item, 0, sizeof (item));
1192 item.mask = LVIF_STATE;
1193 item.state = LVIS_FOCUSED;
1194 item.stateMask = 0;
1195 item.iItem = 0;
1196 item.iSubItem = 0;
1197 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1198 expect(0, r);
1199 /* get */
1200 memset (&item, 0xcc, sizeof (item));
1201 item.mask = LVIF_STATE;
1202 item.stateMask = LVIS_FOCUSED;
1203 item.state = 0;
1204 item.iItem = 0;
1205 item.iSubItem = 0;
1206 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1207 expect(1, r);
1208 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1209 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1210
1211 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1212 /* set */
1213 memset (&item, 0, sizeof (item));
1214 item.mask = LVIF_STATE;
1215 item.state = LVIS_CUT;
1216 item.stateMask = LVIS_FOCUSED;
1217 item.iItem = 0;
1218 item.iSubItem = 0;
1219 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1220 expect(0, r);
1221 /* get */
1222 memset (&item, 0xcc, sizeof (item));
1223 item.mask = LVIF_STATE;
1224 item.stateMask = LVIS_CUT;
1225 item.state = 0;
1226 item.iItem = 0;
1227 item.iSubItem = 0;
1228 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1229 expect(1, r);
1230 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1231 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1232
1233 /* Insert an item with just a param */
1234 memset (&item, 0xcc, sizeof (item));
1235 item.mask = LVIF_PARAM;
1236 item.iItem = 0;
1237 item.iSubItem = 0;
1238 item.lParam = lparamTest;
1239 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1240 expect(0, r);
1241
1242 /* Test getting of the param */
1243 memset (&item, 0xcc, sizeof (item));
1244 item.mask = LVIF_PARAM;
1245 item.iItem = 0;
1246 item.iSubItem = 0;
1247 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1248 expect(1, r);
1249 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1250
1251 /* Set up a subitem */
1252 memset (&item, 0xcc, sizeof (item));
1253 item.mask = LVIF_TEXT;
1254 item.iItem = 0;
1255 item.iSubItem = 1;
1256 item.pszText = text;
1257 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1258 expect(1, r);
1259
1260 item.mask = LVIF_TEXT;
1261 item.iItem = 0;
1262 item.iSubItem = 1;
1263 item.pszText = buffA;
1264 item.cchTextMax = sizeof(buffA);
1265 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1266 expect(1, r);
1267 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1268
1269 /* set up with extra flag */
1270 /* 1. reset subitem text */
1271 item.mask = LVIF_TEXT;
1272 item.iItem = 0;
1273 item.iSubItem = 1;
1274 item.pszText = NULL;
1275 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1276 expect(1, r);
1277
1278 item.mask = LVIF_TEXT;
1279 item.iItem = 0;
1280 item.iSubItem = 1;
1281 item.pszText = buffA;
1282 buffA[0] = 'a';
1283 item.cchTextMax = sizeof(buffA);
1284 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1285 expect(1, r);
1286 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1287
1288 /* 2. set new text with extra flag specified */
1289 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1290 item.iItem = 0;
1291 item.iSubItem = 1;
1292 item.pszText = text;
1293 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1294 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1295
1296 if (r == 1)
1297 {
1298 item.mask = LVIF_TEXT;
1299 item.iItem = 0;
1300 item.iSubItem = 1;
1301 item.pszText = buffA;
1302 buffA[0] = 'a';
1303 item.cchTextMax = sizeof(buffA);
1304 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1305 expect(1, r);
1306 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1307 }
1308
1309 /* Query param from subitem: returns main item param */
1310 memset (&item, 0xcc, sizeof (item));
1311 item.mask = LVIF_PARAM;
1312 item.iItem = 0;
1313 item.iSubItem = 1;
1314 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1315 expect(1, r);
1316 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1317
1318 /* Set up param on first subitem: no effect */
1319 memset (&item, 0xcc, sizeof (item));
1320 item.mask = LVIF_PARAM;
1321 item.iItem = 0;
1322 item.iSubItem = 1;
1323 item.lParam = lparamTest+1;
1324 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1325 expect(0, r);
1326
1327 /* Query param from subitem again: should still return main item param */
1328 memset (&item, 0xcc, sizeof (item));
1329 item.mask = LVIF_PARAM;
1330 item.iItem = 0;
1331 item.iSubItem = 1;
1332 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1333 expect(1, r);
1334 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1335
1336 /**** Some tests of state highlighting ****/
1337 memset (&item, 0xcc, sizeof (item));
1338 item.mask = LVIF_STATE;
1339 item.iItem = 0;
1340 item.iSubItem = 0;
1341 item.state = LVIS_SELECTED;
1342 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1343 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1344 expect(1, r);
1345 item.iSubItem = 1;
1346 item.state = LVIS_DROPHILITED;
1347 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1348 expect(1, r);
1349
1350 memset (&item, 0xcc, sizeof (item));
1351 item.mask = LVIF_STATE;
1352 item.iItem = 0;
1353 item.iSubItem = 0;
1354 item.stateMask = -1;
1355 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1356 expect(1, r);
1357 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1358 item.iSubItem = 1;
1359 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1360 expect(1, r);
1361 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1362
1363 /* some notnull but meaningless masks */
1364 memset (&item, 0, sizeof(item));
1365 item.mask = LVIF_NORECOMPUTE;
1366 item.iItem = 0;
1367 item.iSubItem = 0;
1368 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1369 expect(1, r);
1370 memset (&item, 0, sizeof(item));
1371 item.mask = LVIF_DI_SETITEM;
1372 item.iItem = 0;
1373 item.iSubItem = 0;
1374 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1375 expect(1, r);
1376
1377 /* set text to callback value already having it */
1378 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1379 expect(TRUE, r);
1380 memset (&item, 0, sizeof (item));
1381 item.mask = LVIF_TEXT;
1382 item.pszText = LPSTR_TEXTCALLBACKA;
1383 item.iItem = 0;
1384 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1385 expect(0, r);
1386 memset (&item, 0, sizeof (item));
1387
1388 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1389
1390 item.pszText = LPSTR_TEXTCALLBACKA;
1391 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1392 expect(TRUE, r);
1393
1394 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1395 "check callback text comparison rule", FALSE);
1396
1397 DestroyWindow(hwnd);
1398 }
1399
1400 static void test_columns(void)
1401 {
1402 HWND hwnd, header;
1403 LVCOLUMNA column;
1404 LVITEMA item;
1405 INT order[2];
1406 CHAR buff[5];
1407 DWORD rc;
1408
1409 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_LIST,
1410 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1411 ok(hwnd != NULL, "failed to create listview window\n");
1412
1413 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1414 ok(header == NULL, "got %p\n", header);
1415
1416 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1417 ok(rc == 0, "got %d\n", rc);
1418
1419 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1420 ok(header == NULL, "got %p\n", header);
1421
1422 DestroyWindow(hwnd);
1423
1424 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1425 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1426 ok(hwnd != NULL, "failed to create listview window\n");
1427
1428 /* Add a column with no mask */
1429 memset(&column, 0xcc, sizeof(column));
1430 column.mask = 0;
1431 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1432 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1433
1434 /* Check its width */
1435 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1436 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1437
1438 DestroyWindow(hwnd);
1439
1440 /* LVM_GETCOLUMNORDERARRAY */
1441 hwnd = create_listview_control(LVS_REPORT);
1442 subclass_header(hwnd);
1443
1444 memset(&column, 0, sizeof(column));
1445 column.mask = LVCF_WIDTH;
1446 column.cx = 100;
1447 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1448 expect(0, rc);
1449
1450 column.cx = 200;
1451 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1452 expect(1, rc);
1453
1454 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1455
1456 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1457 expect(1, rc);
1458 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1459 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1460
1461 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1462 expect(0, rc);
1463
1464 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1465
1466 /* LVM_SETCOLUMNORDERARRAY */
1467 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1468
1469 order[0] = 0;
1470 order[1] = 1;
1471 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1472 expect(1, rc);
1473
1474 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1475 expect(0, rc);
1476
1477 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1478
1479 /* after column added subitem is considered as present */
1480 insert_item(hwnd, 0);
1481
1482 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1483
1484 item.pszText = buff;
1485 item.cchTextMax = sizeof(buff);
1486 item.iItem = 0;
1487 item.iSubItem = 1;
1488 item.mask = LVIF_TEXT;
1489 memset(&g_itema, 0, sizeof(g_itema));
1490 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1491 expect(1, rc);
1492 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1493
1494 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1495 "get subitem text after column added", FALSE);
1496
1497 DestroyWindow(hwnd);
1498 }
1499
1500 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1501 static WNDPROC listviewWndProc;
1502 static HIMAGELIST test_create_imagelist;
1503
1504 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1505 {
1506 LRESULT ret;
1507
1508 if (uMsg == WM_CREATE)
1509 {
1510 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1511 lpcs->style |= LVS_REPORT;
1512 }
1513 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1514 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1515 return ret;
1516 }
1517
1518 static void test_create(void)
1519 {
1520 HWND hList;
1521 HWND hHeader;
1522 LONG_PTR ret;
1523 LONG r;
1524 LVCOLUMNA col;
1525 RECT rect;
1526 WNDCLASSEXA cls;
1527 DWORD style;
1528
1529 cls.cbSize = sizeof(WNDCLASSEXA);
1530 ok(GetClassInfoExA(GetModuleHandleA(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1531 listviewWndProc = cls.lpfnWndProc;
1532 cls.lpfnWndProc = create_test_wndproc;
1533 cls.lpszClassName = "MyListView32";
1534 ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
1535
1536 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1537 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1538 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1539 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1540
1541 if (!IsWindow(hHeader))
1542 {
1543 /* version 4.0 */
1544 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1545 DestroyWindow(hList);
1546 return;
1547 }
1548
1549 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1550 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1551 DestroyWindow(hList);
1552
1553 /* header isn't created on LVS_ICON and LVS_LIST styles */
1554 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1555 GetModuleHandleA(NULL), 0);
1556 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1557 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1558 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1559 /* insert column */
1560 memset(&col, 0, sizeof(LVCOLUMNA));
1561 col.mask = LVCF_WIDTH;
1562 col.cx = 100;
1563 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1564 expect(0, r);
1565 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1566 ok(IsWindow(hHeader), "Header should be created\n");
1567 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1568 style = GetWindowLongA(hHeader, GWL_STYLE);
1569 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1570 DestroyWindow(hList);
1571
1572 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1573 GetModuleHandleA(NULL), 0);
1574 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1575 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1576 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1577 /* insert column */
1578 memset(&col, 0, sizeof(LVCOLUMNA));
1579 col.mask = LVCF_WIDTH;
1580 col.cx = 100;
1581 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1582 expect(0, r);
1583 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1584 ok(IsWindow(hHeader), "Header should be created\n");
1585 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1586 DestroyWindow(hList);
1587
1588 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1589 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1590 GetModuleHandleA(NULL), 0);
1591 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1592 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1593 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1594 ok(IsWindow(hHeader), "Header should be created\n");
1595 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1596 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1597 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1598 ok(IsWindow(hHeader), "Header should be created\n");
1599 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1600 DestroyWindow(hList);
1601
1602 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1603 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1604 GetModuleHandleA(NULL), 0);
1605 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1606 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1607 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1608 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1609 ok(IsWindow(hHeader), "Header should be created\n");
1610 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1611 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1612 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1613 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1614 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1615 ok(IsWindow(hHeader), "Header should be created\n");
1616 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1617 DestroyWindow(hList);
1618
1619 /* LVS_REPORT without WS_VISIBLE */
1620 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1621 GetModuleHandleA(NULL), 0);
1622 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1623 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1624 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1625 /* insert column */
1626 memset(&col, 0, sizeof(LVCOLUMNA));
1627 col.mask = LVCF_WIDTH;
1628 col.cx = 100;
1629 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1630 expect(0, r);
1631 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1632 ok(IsWindow(hHeader), "Header should be created\n");
1633 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1634 DestroyWindow(hList);
1635
1636 /* LVS_REPORT without WS_VISIBLE, try to show it */
1637 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1638 GetModuleHandleA(NULL), 0);
1639 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1640 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1641 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1642 ShowWindow(hList, SW_SHOW);
1643 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1644 ok(IsWindow(hHeader), "Header should be created\n");
1645 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1646 DestroyWindow(hList);
1647
1648 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1649 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1650 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1651 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1652 ok(IsWindow(hHeader), "Header should be created\n");
1653 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1654 /* HDS_DRAGDROP set by default */
1655 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1656 DestroyWindow(hList);
1657
1658 /* setting LVS_EX_HEADERDRAGDROP creates header */
1659 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1660 GetModuleHandleA(NULL), 0);
1661 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1662 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1663 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1664 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1665 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1666 ok(IsWindow(hHeader) ||
1667 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1668 "Header should be created\n");
1669 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1670 DestroyWindow(hList);
1671
1672 /* setting LVS_EX_GRIDLINES creates header */
1673 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1674 GetModuleHandleA(NULL), 0);
1675 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1676 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1677 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1678 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1679 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1680 ok(IsWindow(hHeader) ||
1681 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1682 "Header should be created\n");
1683 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1684 DestroyWindow(hList);
1685
1686 /* setting LVS_EX_FULLROWSELECT creates header */
1687 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1688 GetModuleHandleA(NULL), 0);
1689 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1690 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1691 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1692 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1693 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1694 ok(IsWindow(hHeader) ||
1695 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1696 "Header should be created\n");
1697 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1698 DestroyWindow(hList);
1699
1700 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1701 hList = create_listview_control(LVS_ICON);
1702 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1703 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1704 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1705 DestroyWindow(hList);
1706
1707 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1708 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1709 GetModuleHandleA(NULL), 0);
1710 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1711 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1712
1713 rect.left = LVIR_BOUNDS;
1714 rect.top = 1;
1715 rect.right = rect.bottom = -10;
1716 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1717 /* right value contains garbage, probably because header columns are not set up */
1718 expect(0, rect.bottom);
1719 expect(1, r);
1720
1721 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1722 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1723 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1724
1725 DestroyWindow(hList);
1726
1727 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1728 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1729 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1730 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1731 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1732 DestroyWindow(hList);
1733 }
1734
1735 static void test_redraw(void)
1736 {
1737 HWND hwnd;
1738 HDC hdc;
1739 BOOL res;
1740 DWORD r;
1741
1742 hwnd = create_listview_control(LVS_REPORT);
1743 subclass_header(hwnd);
1744
1745 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1746
1747 InvalidateRect(hwnd, NULL, TRUE);
1748 UpdateWindow(hwnd);
1749 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1750
1751 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1752
1753 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1754 /* 1. Without backbuffer */
1755 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1756 expect(TRUE, res);
1757
1758 hdc = GetWindowDC(hwndparent);
1759
1760 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1761 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1762 ok(r == 1, "Expected not zero result\n");
1763 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1764 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1765
1766 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1767 expect(TRUE, res);
1768
1769 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1770 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1771 expect(1, r);
1772 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1773 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1774
1775 /* 2. With backbuffer */
1776 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1777 LVS_EX_DOUBLEBUFFER);
1778 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1779 expect(TRUE, res);
1780
1781 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1782 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1783 expect(1, r);
1784 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1785 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1786
1787 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1788 expect(TRUE, res);
1789
1790 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1791 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1792 todo_wine expect(1, r);
1793 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1794 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1795
1796 ReleaseDC(hwndparent, hdc);
1797
1798 DestroyWindow(hwnd);
1799 }
1800
1801 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1802 {
1803 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1804
1805 if(message == WM_NOTIFY) {
1806 NMHDR *nmhdr = (NMHDR*)lParam;
1807 if(nmhdr->code == NM_CUSTOMDRAW) {
1808 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1809 struct message msg;
1810
1811 msg.message = message;
1812 msg.flags = sent|wparam|lparam|custdraw;
1813 msg.wParam = wParam;
1814 msg.lParam = lParam;
1815 msg.id = nmhdr->code;
1816 msg.stage = nmlvcd->nmcd.dwDrawStage;
1817 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1818
1819 switch(nmlvcd->nmcd.dwDrawStage) {
1820 case CDDS_PREPAINT:
1821 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1822 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1823 case CDDS_ITEMPREPAINT:
1824 nmlvcd->clrTextBk = CLR_DEFAULT;
1825 nmlvcd->clrText = RGB(0, 255, 0);
1826 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1827 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1828 clr = GetBkColor(nmlvcd->nmcd.hdc);
1829 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1830 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1831 if (nmlvcd->iSubItem)
1832 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1833 else
1834 ok(clr == c0ffee, "clr=%.8x\n", clr);
1835 return CDRF_NOTIFYPOSTPAINT;
1836 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1837 clr = GetBkColor(nmlvcd->nmcd.hdc);
1838 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1839 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1840 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1841 return CDRF_DODEFAULT;
1842 }
1843 return CDRF_DODEFAULT;
1844 }
1845 }
1846
1847 return DefWindowProcA(hwnd, message, wParam, lParam);
1848 }
1849
1850 static void test_customdraw(void)
1851 {
1852 HWND hwnd;
1853 WNDPROC oldwndproc;
1854
1855 hwnd = create_listview_control(LVS_REPORT);
1856
1857 insert_column(hwnd, 0);
1858 insert_column(hwnd, 1);
1859 insert_item(hwnd, 0);
1860
1861 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1862 (LONG_PTR)cd_wndproc);
1863
1864 InvalidateRect(hwnd, NULL, TRUE);
1865 UpdateWindow(hwnd);
1866
1867 /* message tests */
1868 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1869 InvalidateRect(hwnd, NULL, TRUE);
1870 UpdateWindow(hwnd);
1871 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1872
1873 DestroyWindow(hwnd);
1874
1875 hwnd = create_listview_control(LVS_LIST);
1876
1877 insert_column(hwnd, 0);
1878 insert_column(hwnd, 1);
1879 insert_item(hwnd, 0);
1880
1881 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1882 InvalidateRect(hwnd, NULL, TRUE);
1883 UpdateWindow(hwnd);
1884 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1885
1886 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1887 DestroyWindow(hwnd);
1888 }
1889
1890 static void test_icon_spacing(void)
1891 {
1892 /* LVM_SETICONSPACING */
1893 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1894
1895 HWND hwnd;
1896 WORD w, h;
1897 INT r;
1898
1899 hwnd = create_listview_control(LVS_ICON);
1900 ok(hwnd != NULL, "failed to create a listview window\n");
1901
1902 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1903 expect(NFR_ANSI, r);
1904
1905 /* reset the icon spacing to defaults */
1906 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1907
1908 /* now we can request what the defaults are */
1909 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1910 w = LOWORD(r);
1911 h = HIWORD(r);
1912
1913 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1914
1915 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1916 ok(r == MAKELONG(w, h) ||
1917 broken(r == MAKELONG(w, w)), /* win98 */
1918 "Expected %d, got %d\n", MAKELONG(w, h), r);
1919
1920 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1921 if (r == 0)
1922 {
1923 /* version 4.0 */
1924 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1925 DestroyWindow(hwnd);
1926 return;
1927 }
1928 expect(MAKELONG(20,30), r);
1929
1930 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1931 expect(MAKELONG(25,35), r);
1932
1933 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1934
1935 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1936 DestroyWindow(hwnd);
1937 }
1938
1939 static void test_color(void)
1940 {
1941 RECT rect;
1942 HWND hwnd;
1943 DWORD r;
1944 int i;
1945
1946 COLORREF color;
1947 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1948
1949 hwnd = create_listview_control(LVS_REPORT);
1950 ok(hwnd != NULL, "failed to create a listview window\n");
1951
1952 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1953
1954 for (i = 0; i < 4; i++)
1955 {
1956 color = colors[i];
1957
1958 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
1959 expect(TRUE, r);
1960 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
1961 expect(color, r);
1962
1963 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
1964 expect (TRUE, r);
1965 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1966 expect(color, r);
1967
1968 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1969 expect(TRUE, r);
1970 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1971 expect(color, r);
1972 }
1973
1974 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1975 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1976
1977 /* invalidation test done separately to avoid a message chain mess */
1978 r = ValidateRect(hwnd, NULL);
1979 expect(TRUE, r);
1980 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1981 expect(TRUE, r);
1982
1983 rect.right = rect.bottom = 1;
1984 r = GetUpdateRect(hwnd, &rect, TRUE);
1985 todo_wine expect(FALSE, r);
1986 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1987
1988 r = ValidateRect(hwnd, NULL);
1989 expect(TRUE, r);
1990 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1991 expect(TRUE, r);
1992
1993 rect.right = rect.bottom = 1;
1994 r = GetUpdateRect(hwnd, &rect, TRUE);
1995 todo_wine expect(FALSE, r);
1996 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1997
1998 r = ValidateRect(hwnd, NULL);
1999 expect(TRUE, r);
2000 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2001 expect(TRUE, r);
2002
2003 rect.right = rect.bottom = 1;
2004 r = GetUpdateRect(hwnd, &rect, TRUE);
2005 todo_wine expect(FALSE, r);
2006 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2007
2008 DestroyWindow(hwnd);
2009 }
2010
2011 static void test_item_count(void)
2012 {
2013 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2014
2015 HWND hwnd;
2016 DWORD r;
2017 HDC hdc;
2018 HFONT hOldFont;
2019 TEXTMETRICA tm;
2020 RECT rect;
2021 INT height;
2022
2023 LVITEMA item0;
2024 LVITEMA item1;
2025 LVITEMA item2;
2026 static CHAR item0text[] = "item0";
2027 static CHAR item1text[] = "item1";
2028 static CHAR item2text[] = "item2";
2029
2030 hwnd = create_listview_control(LVS_REPORT);
2031 ok(hwnd != NULL, "failed to create a listview window\n");
2032
2033 /* resize in dpiaware manner to fit all 3 items added */
2034 hdc = GetDC(0);
2035 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2036 GetTextMetricsA(hdc, &tm);
2037 /* 2 extra pixels for bounds and header border */
2038 height = tm.tmHeight + 2;
2039 SelectObject(hdc, hOldFont);
2040 ReleaseDC(0, hdc);
2041
2042 GetWindowRect(hwnd, &rect);
2043 /* 3 items + 1 header + 1 to be sure */
2044 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2045
2046 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2047
2048 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2049 expect(0, r);
2050
2051 /* [item0] */
2052 item0.mask = LVIF_TEXT;
2053 item0.iItem = 0;
2054 item0.iSubItem = 0;
2055 item0.pszText = item0text;
2056 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2057 expect(0, r);
2058
2059 /* [item0, item1] */
2060 item1.mask = LVIF_TEXT;
2061 item1.iItem = 1;
2062 item1.iSubItem = 0;
2063 item1.pszText = item1text;
2064 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2065 expect(1, r);
2066
2067 /* [item0, item1, item2] */
2068 item2.mask = LVIF_TEXT;
2069 item2.iItem = 2;
2070 item2.iSubItem = 0;
2071 item2.pszText = item2text;
2072 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2073 expect(2, r);
2074
2075 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2076 expect(3, r);
2077
2078 /* [item0, item1] */
2079 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2080 expect(TRUE, r);
2081
2082 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2083 expect(2, r);
2084
2085 /* [] */
2086 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2087 expect(TRUE, r);
2088
2089 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2090 expect(0, r);
2091
2092 /* [item0] */
2093 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2094 expect(0, r);
2095
2096 /* [item0, item1] */
2097 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2098 expect(1, r);
2099
2100 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2101 expect(2, r);
2102
2103 /* [item0, item1, item2] */
2104 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2105 expect(2, r);
2106
2107 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2108 expect(3, r);
2109
2110 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2111
2112 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2113 DestroyWindow(hwnd);
2114 }
2115
2116 static void test_item_position(void)
2117 {
2118 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2119
2120 HWND hwnd;
2121 DWORD r;
2122 POINT position;
2123
2124 LVITEMA item0;
2125 LVITEMA item1;
2126 LVITEMA item2;
2127 static CHAR item0text[] = "item0";
2128 static CHAR item1text[] = "item1";
2129 static CHAR item2text[] = "item2";
2130
2131 hwnd = create_listview_control(LVS_ICON);
2132 ok(hwnd != NULL, "failed to create a listview window\n");
2133
2134 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2135
2136 /* [item0] */
2137 item0.mask = LVIF_TEXT;
2138 item0.iItem = 0;
2139 item0.iSubItem = 0;
2140 item0.pszText = item0text;
2141 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2142 expect(0, r);
2143
2144 /* [item0, item1] */
2145 item1.mask = LVIF_TEXT;
2146 item1.iItem = 1;
2147 item1.iSubItem = 0;
2148 item1.pszText = item1text;
2149 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2150 expect(1, r);
2151
2152 /* [item0, item1, item2] */
2153 item2.mask = LVIF_TEXT;
2154 item2.iItem = 2;
2155 item2.iSubItem = 0;
2156 item2.pszText = item2text;
2157 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2158 expect(2, r);
2159
2160 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2161 expect(TRUE, r);
2162 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2163 expect(TRUE, r);
2164 expect2(10, 5, position.x, position.y);
2165
2166 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2167 expect(TRUE, r);
2168 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2169 expect(TRUE, r);
2170 expect2(0, 0, position.x, position.y);
2171
2172 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2173 expect(TRUE, r);
2174 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2175 expect(TRUE, r);
2176 expect2(20, 20, position.x, position.y);
2177
2178 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2179
2180 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2181 DestroyWindow(hwnd);
2182 }
2183
2184 static void test_getorigin(void)
2185 {
2186 /* LVM_GETORIGIN */
2187
2188 HWND hwnd;
2189 DWORD r;
2190 POINT position;
2191
2192 position.x = position.y = 0;
2193
2194 hwnd = create_listview_control(LVS_ICON);
2195 ok(hwnd != NULL, "failed to create a listview window\n");
2196 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2197
2198 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2199 expect(TRUE, r);
2200 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2201 DestroyWindow(hwnd);
2202
2203 hwnd = create_listview_control(LVS_SMALLICON);
2204 ok(hwnd != NULL, "failed to create a listview window\n");
2205 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2206
2207 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2208 expect(TRUE, r);
2209 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2210 DestroyWindow(hwnd);
2211
2212 hwnd = create_listview_control(LVS_LIST);
2213 ok(hwnd != NULL, "failed to create a listview window\n");
2214 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2215
2216 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2217 expect(FALSE, r);
2218 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2219 DestroyWindow(hwnd);
2220
2221 hwnd = create_listview_control(LVS_REPORT);
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(FALSE, r);
2227 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2228 DestroyWindow(hwnd);
2229 }
2230
2231 static void test_multiselect(void)
2232 {
2233 typedef struct t_select_task
2234 {
2235 const char *descr;
2236 int initPos;
2237 int loopVK;
2238 int count;
2239 int result;
2240 } select_task;
2241
2242 HWND hwnd;
2243 INT r;
2244 int i,j,item_count,selected_count;
2245 static const int items=5;
2246 BYTE kstate[256];
2247 select_task task;
2248 LONG_PTR style;
2249 LVITEMA item;
2250
2251 static struct t_select_task task_list[] = {
2252 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2253 { "using VK_UP", -1, VK_UP, -1, -1 },
2254 { "using VK_END", 0, VK_END, 1, -1 },
2255 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2256 };
2257
2258 hwnd = create_listview_control(LVS_REPORT);
2259
2260 for (i = 0; i < items; i++)
2261 insert_item(hwnd, 0);
2262
2263 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2264 expect(items, item_count);
2265
2266 for (i = 0; i < 4; i++) {
2267 LVITEMA item;
2268
2269 task = task_list[i];
2270
2271 /* deselect all items */
2272 item.state = 0;
2273 item.stateMask = LVIS_SELECTED;
2274 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2275 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2276
2277 /* set initial position */
2278 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2279
2280 item.state = LVIS_SELECTED;
2281 item.stateMask = LVIS_SELECTED;
2282 SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2283
2284 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2285 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2286
2287 /* Set SHIFT key pressed */
2288 GetKeyboardState(kstate);
2289 kstate[VK_SHIFT]=0x80;
2290 SetKeyboardState(kstate);
2291
2292 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2293 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2294 expect(0,r);
2295 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2296 expect(0,r);
2297 }
2298
2299 selected_count = (int)SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2300
2301 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);
2302
2303 /* Set SHIFT key released */
2304 GetKeyboardState(kstate);
2305 kstate[VK_SHIFT]=0x00;
2306 SetKeyboardState(kstate);
2307 }
2308 DestroyWindow(hwnd);
2309
2310 /* make multiple selection, then switch to LVS_SINGLESEL */
2311 hwnd = create_listview_control(LVS_REPORT);
2312 for (i=0;i<items;i++) {
2313 insert_item(hwnd, 0);
2314 }
2315 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2316 expect(items,item_count);
2317
2318 /* try with NULL pointer */
2319 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2320 expect(FALSE, r);
2321
2322 /* select all, check notifications */
2323 item.state = 0;
2324 item.stateMask = LVIS_SELECTED;
2325 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2326
2327 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2328
2329 item.stateMask = LVIS_SELECTED;
2330 item.state = LVIS_SELECTED;
2331 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2332 expect(TRUE, r);
2333
2334 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2335 "select all notification", FALSE);
2336
2337 /* select all again (all selected already) */
2338 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2339
2340 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2341
2342 item.stateMask = LVIS_SELECTED;
2343 item.state = LVIS_SELECTED;
2344 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2345 expect(TRUE, r);
2346
2347 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2348 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2349 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2350
2351 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2352 "select all notification 2", FALSE);
2353
2354 /* deselect all items */
2355 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2356
2357 item.state = 0;
2358 item.stateMask = LVIS_SELECTED;
2359 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2360
2361 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2362 "deselect all notification", FALSE);
2363
2364 /* deselect all items again */
2365 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2366 item.state = 0;
2367 item.stateMask = LVIS_SELECTED;
2368 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2369 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2370
2371 /* any non-zero state value does the same */
2372 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2373
2374 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2375
2376 item.stateMask = LVIS_SELECTED;
2377 item.state = LVIS_CUT;
2378 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2379 expect(TRUE, r);
2380
2381 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2382 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2383 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2384
2385 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2386 "set state all notification 3", FALSE);
2387
2388 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2389 for (i = 0; i < 3; i++) {
2390 item.state = LVIS_SELECTED;
2391 item.stateMask = LVIS_SELECTED;
2392 SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2393 }
2394
2395 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2396 expect(3, r);
2397 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2398 expect(-1, r);
2399
2400 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2401 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2402 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2403 /* check that style is accepted */
2404 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2405 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2406
2407 for (i=0;i<3;i++) {
2408 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2409 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2410 }
2411 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2412 expect(3, r);
2413 SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2414 expect(3, r);
2415
2416 /* select one more */
2417 item.state = LVIS_SELECTED;
2418 item.stateMask = LVIS_SELECTED;
2419 SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2420
2421 for (i=0;i<3;i++) {
2422 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2423 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2424 }
2425
2426 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2427 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2428
2429 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2430 expect(1, r);
2431 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2432 expect(-1, r);
2433
2434 /* try to select all on LVS_SINGLESEL */
2435 memset(&item, 0, sizeof(item));
2436 item.stateMask = LVIS_SELECTED;
2437 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2438 expect(TRUE, r);
2439 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2440
2441 item.stateMask = LVIS_SELECTED;
2442 item.state = LVIS_SELECTED;
2443 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2444 expect(FALSE, r);
2445
2446 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2447 expect(0, r);
2448 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2449 expect(-1, r);
2450
2451 /* try to deselect all on LVS_SINGLESEL */
2452 item.stateMask = LVIS_SELECTED;
2453 item.state = LVIS_SELECTED;
2454 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2455 expect(TRUE, r);
2456
2457 item.stateMask = LVIS_SELECTED;
2458 item.state = 0;
2459 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2460 expect(TRUE, r);
2461 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2462 expect(0, r);
2463
2464 /* 1. selection mark is update when new focused item is set */
2465 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2466 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2467
2468 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2469 expect(-1, r);
2470
2471 item.stateMask = LVIS_FOCUSED;
2472 item.state = LVIS_FOCUSED;
2473 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2474 expect(TRUE, r);
2475
2476 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2477 expect(0, r);
2478
2479 /* it's not updated if already set */
2480 item.stateMask = LVIS_FOCUSED;
2481 item.state = LVIS_FOCUSED;
2482 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2483 expect(TRUE, r);
2484
2485 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2486 expect(0, r);
2487
2488 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2489 expect(0, r);
2490
2491 item.stateMask = LVIS_FOCUSED;
2492 item.state = LVIS_FOCUSED;
2493 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2494 expect(TRUE, r);
2495
2496 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2497 expect(-1, r);
2498
2499 /* need to reset focused item first */
2500 item.stateMask = LVIS_FOCUSED;
2501 item.state = 0;
2502 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2503 expect(TRUE, r);
2504
2505 item.stateMask = LVIS_FOCUSED;
2506 item.state = LVIS_FOCUSED;
2507 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2508 expect(TRUE, r);
2509
2510 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2511 expect(2, r);
2512
2513 item.stateMask = LVIS_FOCUSED;
2514 item.state = 0;
2515 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2516 expect(TRUE, r);
2517
2518 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2519 expect(2, r);
2520
2521 /* 2. same tests, with LVM_SETITEM */
2522 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2523 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2524
2525 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2526 expect(2, r);
2527
2528 item.stateMask = LVIS_FOCUSED;
2529 item.state = LVIS_FOCUSED;
2530 item.mask = LVIF_STATE;
2531 item.iItem = item.iSubItem = 0;
2532 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2533 expect(TRUE, r);
2534
2535 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2536 expect(0, r);
2537
2538 /* it's not updated if already set */
2539 item.stateMask = LVIS_FOCUSED;
2540 item.state = LVIS_FOCUSED;
2541 item.mask = LVIF_STATE;
2542 item.iItem = 1;
2543 item.iSubItem = 0;
2544 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2545 expect(TRUE, r);
2546
2547 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2548 expect(0, r);
2549
2550 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2551 expect(0, r);
2552
2553 item.stateMask = LVIS_FOCUSED;
2554 item.state = LVIS_FOCUSED;
2555 item.mask = LVIF_STATE;
2556 item.iItem = 1;
2557 item.iSubItem = 0;
2558 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2559 expect(TRUE, r);
2560
2561 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2562 expect(-1, r);
2563
2564 /* need to reset focused item first */
2565 item.stateMask = LVIS_FOCUSED;
2566 item.state = 0;
2567 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2568 expect(TRUE, r);
2569
2570 item.stateMask = LVIS_FOCUSED;
2571 item.state = LVIS_FOCUSED;
2572 item.mask = LVIF_STATE;
2573 item.iItem = 2;
2574 item.iSubItem = 0;
2575 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2576 expect(TRUE, r);
2577
2578 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2579 expect(2, r);
2580
2581 item.stateMask = LVIS_FOCUSED;
2582 item.state = 0;
2583 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2584 expect(TRUE, r);
2585
2586 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2587 expect(2, r);
2588
2589 DestroyWindow(hwnd);
2590 }
2591
2592 static void test_subitem_rect(void)
2593 {
2594 HWND hwnd;
2595 DWORD r;
2596 LVCOLUMNA col;
2597 RECT rect, rect2;
2598 INT arr[3];
2599
2600 /* test LVM_GETSUBITEMRECT for header */
2601 hwnd = create_listview_control(LVS_REPORT);
2602 ok(hwnd != NULL, "failed to create a listview window\n");
2603 /* add some columns */
2604 memset(&col, 0, sizeof(LVCOLUMNA));
2605 col.mask = LVCF_WIDTH;
2606 col.cx = 100;
2607 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2608 expect(0, r);
2609 col.cx = 150;
2610 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2611 expect(1, r);
2612 col.cx = 200;
2613 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2614 expect(2, r);
2615 /* item = -1 means header, subitem index is 1 based */
2616 rect.left = LVIR_BOUNDS;
2617 rect.top = 0;
2618 rect.right = rect.bottom = 0;
2619 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2620 expect(0, r);
2621
2622 rect.left = LVIR_BOUNDS;
2623 rect.top = 1;
2624 rect.right = rect.bottom = 0;
2625 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2626 expect(1, r);
2627
2628 expect(100, rect.left);
2629 expect(250, rect.right);
2630 expect(3, rect.top);
2631
2632 rect.left = LVIR_BOUNDS;
2633 rect.top = 2;
2634 rect.right = rect.bottom = 0;
2635 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2636 expect(1, r);
2637
2638 expect(250, rect.left);
2639 expect(450, rect.right);
2640 expect(3, rect.top);
2641
2642 /* item LVS_REPORT padding isn't applied to subitems */
2643 insert_item(hwnd, 0);
2644
2645 rect.left = LVIR_BOUNDS;
2646 rect.top = 1;
2647 rect.right = rect.bottom = 0;
2648 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2649 expect(1, r);
2650 expect(100, rect.left);
2651 expect(250, rect.right);
2652
2653 rect.left = LVIR_ICON;
2654 rect.top = 1;
2655 rect.right = rect.bottom = 0;
2656 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2657 expect(1, r);
2658 /* no icon attached - zero width rectangle, with no left padding */
2659 expect(100, rect.left);
2660 expect(100, rect.right);
2661
2662 rect.left = LVIR_LABEL;
2663 rect.top = 1;
2664 rect.right = rect.bottom = 0;
2665 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2666 expect(1, r);
2667 /* same as full LVIR_BOUNDS */
2668 expect(100, rect.left);
2669 expect(250, rect.right);
2670
2671 SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2672
2673 rect.left = LVIR_BOUNDS;
2674 rect.top = 1;
2675 rect.right = rect.bottom = 0;
2676 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2677 expect(1, r);
2678 expect(90, rect.left);
2679 expect(240, rect.right);
2680
2681 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2682
2683 /* test header interaction */
2684 subclass_header(hwnd);
2685 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2686
2687 rect.left = LVIR_BOUNDS;
2688 rect.top = 1;
2689 rect.right = rect.bottom = 0;
2690 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2691 expect(1, r);
2692
2693 rect.left = LVIR_BOUNDS;
2694 rect.top = 1;
2695 rect.right = rect.bottom = 0;
2696 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2697 expect(1, r);
2698
2699 rect.left = LVIR_BOUNDS;
2700 rect.top = 1;
2701 rect.right = rect.bottom = 0;
2702 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2703 expect(1, r);
2704
2705 rect.left = LVIR_BOUNDS;
2706 rect.top = 1;
2707 rect.right = rect.bottom = 0;
2708 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2709 expect(1, r);
2710
2711 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2712
2713 DestroyWindow(hwnd);
2714
2715 /* test subitem rects after re-arranging columns */
2716 hwnd = create_listview_control(LVS_REPORT);
2717 ok(hwnd != NULL, "failed to create a listview window\n");
2718 memset(&col, 0, sizeof(LVCOLUMNA));
2719 col.mask = LVCF_WIDTH;
2720
2721 col.cx = 100;
2722 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2723 expect(0, r);
2724
2725 col.cx = 200;
2726 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2727 expect(1, r);
2728
2729 col.cx = 300;
2730 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2731 expect(2, r);
2732
2733 insert_item(hwnd, 0);
2734 insert_item(hwnd, 1);
2735
2736 /* wrong item is refused for main item */
2737 rect.left = LVIR_BOUNDS;
2738 rect.top = 0;
2739 rect.right = rect.bottom = -1;
2740 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2741 expect(FALSE, r);
2742
2743 /* for subitems rectangle is calculated even if there's no item added */
2744 rect.left = LVIR_BOUNDS;
2745 rect.top = 1;
2746 rect.right = rect.bottom = -1;
2747 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2748 expect(TRUE, r);
2749
2750 rect2.left = LVIR_BOUNDS;
2751 rect2.top = 1;
2752 rect2.right = rect2.bottom = -1;
2753 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2754 expect(TRUE, r);
2755 expect(rect.right, rect2.right);
2756 expect(rect.left, rect2.left);
2757 expect(rect.bottom, rect2.top);
2758 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2759
2760 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2761 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2762 expect(TRUE, r);
2763
2764 rect.left = LVIR_BOUNDS;
2765 rect.top = 0;
2766 rect.right = rect.bottom = -1;
2767 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2768 expect(TRUE, r);
2769 expect(0, rect.left);
2770 expect(600, rect.right);
2771
2772 rect.left = LVIR_BOUNDS;
2773 rect.top = 1;
2774 rect.right = rect.bottom = -1;
2775 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2776 expect(TRUE, r);
2777 expect(0, rect