67c40c78336b00acbcc8ac94ec0ac5a25dbc552e
[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.left);
2778 expect(200, rect.right);
2779
2780 rect2.left = LVIR_BOUNDS;
2781 rect2.top = 1;
2782 rect2.right = rect2.bottom = -1;
2783 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2784 expect(TRUE, r);
2785 expect(0, rect2.left);
2786 expect(200, rect2.right);
2787 /* items are of the same height */
2788 ok(rect2.top > 0, "expected positive item height\n");
2789 expect(rect.bottom, rect2.top);
2790 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2791
2792 rect.left = LVIR_BOUNDS;
2793 rect.top = 2;
2794 rect.right = rect.bottom = -1;
2795 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2796 expect(TRUE, r);
2797 expect(300, rect.left);
2798 expect(600, rect.right);
2799
2800 DestroyWindow(hwnd);
2801
2802 /* try it for non LVS_REPORT style */
2803 hwnd = CreateWindowA("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2804 GetModuleHandleA(NULL), 0);
2805 rect.left = LVIR_BOUNDS;
2806 rect.top = 1;
2807 rect.right = rect.bottom = -10;
2808 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2809 expect(0, r);
2810 /* rect is unchanged */
2811 expect(0, rect.left);
2812 expect(-10, rect.right);
2813 expect(1, rect.top);
2814 expect(-10, rect.bottom);
2815 DestroyWindow(hwnd);
2816 }
2817
2818 /* comparison callback for test_sorting */
2819 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2820 {
2821 if (first == second) return 0;
2822 return (first > second ? 1 : -1);
2823 }
2824
2825 static void test_sorting(void)
2826 {
2827 HWND hwnd;
2828 LVITEMA item = {0};
2829 INT r;
2830 LONG_PTR style;
2831 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2832 CHAR buff[10];
2833
2834 hwnd = create_listview_control(LVS_REPORT);
2835 ok(hwnd != NULL, "failed to create a listview window\n");
2836
2837 /* insert some items */
2838 item.mask = LVIF_PARAM | LVIF_STATE;
2839 item.state = LVIS_SELECTED;
2840 item.iItem = 0;
2841 item.iSubItem = 0;
2842 item.lParam = 3;
2843 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2844 expect(0, r);
2845
2846 item.mask = LVIF_PARAM;
2847 item.iItem = 1;
2848 item.iSubItem = 0;
2849 item.lParam = 2;
2850 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2851 expect(1, r);
2852
2853 item.mask = LVIF_STATE | LVIF_PARAM;
2854 item.state = LVIS_SELECTED;
2855 item.iItem = 2;
2856 item.iSubItem = 0;
2857 item.lParam = 4;
2858 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2859 expect(2, r);
2860
2861 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2862 expect(-1, r);
2863
2864 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2865 expect(2, r);
2866
2867 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2868 expect(TRUE, r);
2869
2870 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2871 expect(2, r);
2872 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2873 expect(-1, r);
2874 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2875 expect(0, r);
2876 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2877 expect(LVIS_SELECTED, r);
2878 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2879 expect(LVIS_SELECTED, r);
2880
2881 DestroyWindow(hwnd);
2882
2883 /* switch to LVS_SORTASCENDING when some items added */
2884 hwnd = create_listview_control(LVS_REPORT);
2885 ok(hwnd != NULL, "failed to create a listview window\n");
2886
2887 item.mask = LVIF_TEXT;
2888 item.iItem = 0;
2889 item.iSubItem = 0;
2890 item.pszText = names[1];
2891 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2892 expect(0, r);
2893
2894 item.mask = LVIF_TEXT;
2895 item.iItem = 1;
2896 item.iSubItem = 0;
2897 item.pszText = names[2];
2898 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2899 expect(1, r);
2900
2901 item.mask = LVIF_TEXT;
2902 item.iItem = 2;
2903 item.iSubItem = 0;
2904 item.pszText = names[0];
2905 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2906 expect(2, r);
2907
2908 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2909 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2910 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2911 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2912
2913 /* no sorting performed when switched to LVS_SORTASCENDING */
2914 item.mask = LVIF_TEXT;
2915 item.iItem = 0;
2916 item.pszText = buff;
2917 item.cchTextMax = sizeof(buff);
2918 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2919 expect(TRUE, r);
2920 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2921
2922 item.iItem = 1;
2923 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2924 expect(TRUE, r);
2925 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2926
2927 item.iItem = 2;
2928 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2929 expect(TRUE, r);
2930 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2931
2932 /* adding new item doesn't resort list */
2933 item.mask = LVIF_TEXT;
2934 item.iItem = 3;
2935 item.iSubItem = 0;
2936 item.pszText = names[3];
2937 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2938 expect(3, r);
2939
2940 item.mask = LVIF_TEXT;
2941 item.iItem = 0;
2942 item.pszText = buff;
2943 item.cchTextMax = sizeof(buff);
2944 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2945 expect(TRUE, r);
2946 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2947
2948 item.iItem = 1;
2949 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2950 expect(TRUE, r);
2951 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2952
2953 item.iItem = 2;
2954 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2955 expect(TRUE, r);
2956 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2957
2958 item.iItem = 3;
2959 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2960 expect(TRUE, r);
2961 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2962
2963 /* corner case - item should be placed at first position */
2964 item.mask = LVIF_TEXT;
2965 item.iItem = 4;
2966 item.iSubItem = 0;
2967 item.pszText = names[4];
2968 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2969 expect(0, r);
2970
2971 item.iItem = 0;
2972 item.pszText = buff;
2973 item.cchTextMax = sizeof(buff);
2974 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2975 expect(TRUE, r);
2976 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2977
2978 item.iItem = 1;
2979 item.pszText = buff;
2980 item.cchTextMax = sizeof(buff);
2981 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2982 expect(TRUE, r);
2983 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2984
2985 item.iItem = 2;
2986 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2987 expect(TRUE, r);
2988 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2989
2990 item.iItem = 3;
2991 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2992 expect(TRUE, r);
2993 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2994
2995 item.iItem = 4;
2996 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2997 expect(TRUE, r);
2998 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2999
3000 DestroyWindow(hwnd);
3001 }
3002
3003 static void test_ownerdata(void)
3004 {
3005 static char test_str[] = "test";
3006
3007 HWND hwnd;
3008 LONG_PTR style, ret;
3009 DWORD res;
3010 LVITEMA item;
3011
3012 /* it isn't possible to set LVS_OWNERDATA after creation */
3013 if (g_is_below_5)
3014 {
3015 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3016 }
3017 else
3018 {
3019 hwnd = create_listview_control(LVS_REPORT);
3020 ok(hwnd != NULL, "failed to create a listview window\n");
3021 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3022 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3023
3024 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3025
3026 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3027 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3028 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3029 "try to switch to LVS_OWNERDATA seq", FALSE);
3030
3031 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3032 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3033 DestroyWindow(hwnd);
3034 }
3035
3036 /* try to set LVS_OWNERDATA after creation just having it */
3037 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3038 ok(hwnd != NULL, "failed to create a listview window\n");
3039 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3040 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3041
3042 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3043
3044 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3045 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3046 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3047 "try to switch to LVS_OWNERDATA seq", FALSE);
3048 DestroyWindow(hwnd);
3049
3050 /* try to remove LVS_OWNERDATA after creation just having it */
3051 if (g_is_below_5)
3052 {
3053 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3054 }
3055 else
3056 {
3057 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3058 ok(hwnd != NULL, "failed to create a listview window\n");
3059 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3060 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3061
3062 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3063
3064 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3065 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3066 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3067 "try to switch to LVS_OWNERDATA seq", FALSE);
3068 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3069 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3070 DestroyWindow(hwnd);
3071 }
3072
3073 /* try select an item */
3074 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3075 ok(hwnd != NULL, "failed to create a listview window\n");
3076 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3077 expect(1, res);
3078 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3079 expect(0, res);
3080 memset(&item, 0, sizeof(item));
3081 item.stateMask = LVIS_SELECTED;
3082 item.state = LVIS_SELECTED;
3083 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3084 expect(TRUE, res);
3085 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3086 expect(1, res);
3087 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3088 expect(1, res);
3089 DestroyWindow(hwnd);
3090
3091 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3092 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3093 ok(hwnd != NULL, "failed to create a listview window\n");
3094 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3095 expect(1, res);
3096 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3097 expect(1, res);
3098 memset(&item, 0, sizeof(item));
3099 item.mask = LVIF_STATE;
3100 item.iItem = 0;
3101 item.stateMask = LVIS_SELECTED;
3102 item.state = LVIS_SELECTED;
3103 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3104 expect(FALSE, res);
3105 memset(&item, 0, sizeof(item));
3106 item.pszText = test_str;
3107 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3108 expect(FALSE, res);
3109 DestroyWindow(hwnd);
3110
3111 /* check notifications after focused/selected changed */
3112 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3113 ok(hwnd != NULL, "failed to create a listview window\n");
3114 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3115 expect(1, res);
3116
3117 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3118
3119 memset(&item, 0, sizeof(item));
3120 item.stateMask = LVIS_SELECTED;
3121 item.state = LVIS_SELECTED;
3122 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3123 expect(TRUE, res);
3124
3125 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3126 "ownerdata select notification", TRUE);
3127
3128 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3129
3130 memset(&item, 0, sizeof(item));
3131 item.stateMask = LVIS_FOCUSED;
3132 item.state = LVIS_FOCUSED;
3133 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3134 expect(TRUE, res);
3135
3136 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3137 "ownerdata focus notification", TRUE);
3138
3139 /* select all, check notifications */
3140 item.stateMask = LVIS_SELECTED;
3141 item.state = 0;
3142 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3143 expect(TRUE, res);
3144
3145 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3146
3147 item.stateMask = LVIS_SELECTED;
3148 item.state = LVIS_SELECTED;
3149
3150 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3151 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3152 expect(TRUE, res);
3153 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3154 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3155 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3156 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3157 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3158 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3159 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3160
3161 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3162 "ownerdata select all notification", FALSE);
3163
3164 /* select all again, note that all items are selected already */
3165 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3166 item.stateMask = LVIS_SELECTED;
3167 item.state = LVIS_SELECTED;
3168
3169 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3170 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3171 expect(TRUE, res);
3172 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3173 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3174 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3175 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3176 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3177 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3178 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3179
3180 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3181 "ownerdata select all notification", FALSE);
3182
3183 /* deselect all */
3184 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3185 item.stateMask = LVIS_SELECTED;
3186 item.state = 0;
3187
3188 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3189 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3190 expect(TRUE, res);
3191 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3192 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3193 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3194 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3195 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3196 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3197 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3198
3199 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3200 "ownerdata deselect all notification", TRUE);
3201
3202 /* nothing selected, deselect all again */
3203 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3204 item.stateMask = LVIS_SELECTED;
3205 item.state = 0;
3206
3207 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3208 expect(TRUE, res);
3209
3210 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3211
3212 /* select one, then deselect all */
3213 item.stateMask = LVIS_SELECTED;
3214 item.state = LVIS_SELECTED;
3215 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3216 expect(TRUE, res);
3217 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3218 item.stateMask = LVIS_SELECTED;
3219 item.state = 0;
3220
3221 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3222 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3223 expect(TRUE, res);
3224 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3225 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3226 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3227 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3228 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3229 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3230 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3231
3232 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3233 "ownerdata select all notification", TRUE);
3234
3235 /* remove focused, try to focus all */
3236 item.stateMask = LVIS_FOCUSED;
3237 item.state = LVIS_FOCUSED;
3238 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3239 expect(TRUE, res);
3240 item.stateMask = LVIS_FOCUSED;
3241 item.state = 0;
3242 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3243 expect(TRUE, res);
3244 item.stateMask = LVIS_FOCUSED;
3245 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3246 expect(0, res);
3247
3248 /* setting all to focused returns failure value */
3249 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3250 item.stateMask = LVIS_FOCUSED;
3251 item.state = LVIS_FOCUSED;
3252
3253 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3254 expect(FALSE, res);
3255
3256 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3257 "ownerdata focus all notification", FALSE);
3258
3259 /* focus single item, remove all */
3260 item.stateMask = LVIS_FOCUSED;
3261 item.state = LVIS_FOCUSED;
3262 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3263 expect(TRUE, res);
3264 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3265 item.stateMask = LVIS_FOCUSED;
3266 item.state = 0;
3267
3268 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3269 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3270 expect(TRUE, res);
3271 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3272 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3273 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3274 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3275 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3276 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3277 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3278
3279 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3280 "ownerdata remove focus all notification", TRUE);
3281
3282 /* set all cut */
3283 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3284 item.stateMask = LVIS_CUT;
3285 item.state = LVIS_CUT;
3286
3287 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3288 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3289 expect(TRUE, res);
3290 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3291 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3292 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3293 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3294 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3295 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3296 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3297
3298 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3299 "ownerdata cut all notification", FALSE);
3300
3301 /* all marked cut, try again */
3302 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3303 item.stateMask = LVIS_CUT;
3304 item.state = LVIS_CUT;
3305
3306 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3307 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3308 expect(TRUE, res);
3309 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3310 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3311 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3312 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3313 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3314 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3315 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3316
3317 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3318 "ownerdata cut all notification #2", FALSE);
3319
3320 DestroyWindow(hwnd);
3321
3322 /* check notifications on LVM_GETITEM */
3323 /* zero callback mask */
3324 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3325 ok(hwnd != NULL, "failed to create a listview window\n");
3326 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3327 expect(1, res);
3328
3329 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3330
3331 memset(&item, 0, sizeof(item));
3332 item.stateMask = LVIS_SELECTED;
3333 item.mask = LVIF_STATE;
3334 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3335 expect(TRUE, res);
3336
3337 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3338 "ownerdata getitem selected state 1", FALSE);
3339
3340 /* non zero callback mask but not we asking for */
3341 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3342 expect(TRUE, res);
3343
3344 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3345
3346 memset(&item, 0, sizeof(item));
3347 item.stateMask = LVIS_SELECTED;
3348 item.mask = LVIF_STATE;
3349 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3350 expect(TRUE, res);
3351
3352 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3353 "ownerdata getitem selected state 2", FALSE);
3354
3355 /* LVIS_OVERLAYMASK callback mask, asking for index */
3356 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3357
3358 memset(&item, 0, sizeof(item));
3359 item.stateMask = LVIS_OVERLAYMASK;
3360 item.mask = LVIF_STATE;
3361 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3362 expect(TRUE, res);
3363
3364 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3365 "ownerdata getitem selected state 2", FALSE);
3366
3367 DestroyWindow(hwnd);
3368
3369 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3370 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3371 ok(hwnd != NULL, "failed to create a listview window\n");
3372 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3373 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3374 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3375 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3376 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3377 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3378 DestroyWindow(hwnd);
3379 /* apparently it's allowed to switch these style on after creation */
3380 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3381 ok(hwnd != NULL, "failed to create a listview window\n");
3382 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3383 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3384 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3385 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3386 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3387 DestroyWindow(hwnd);
3388
3389 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3390 ok(hwnd != NULL, "failed to create a listview window\n");
3391 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3392 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3393 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3394 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3395 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3396 DestroyWindow(hwnd);
3397
3398 /* The focused item is updated after the invalidation */
3399 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3400 ok(hwnd != NULL, "failed to create a listview window\n");
3401 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3402 expect(TRUE, res);
3403
3404 memset(&item, 0, sizeof(item));
3405 item.stateMask = LVIS_FOCUSED;
3406 item.state = LVIS_FOCUSED;
3407 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3408 expect(TRUE, res);
3409
3410 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3411 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3412 expect(TRUE, res);
3413 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3414 "ownerdata setitemcount", FALSE);
3415
3416 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3417 expect(-1, res);
3418 DestroyWindow(hwnd);
3419 }
3420
3421 static void test_norecompute(void)
3422 {
3423 static CHAR testA[] = "test";
3424 CHAR buff[10];
3425 LVITEMA item;
3426 HWND hwnd;
3427 DWORD res;
3428
3429 /* self containing control */
3430 hwnd = create_listview_control(LVS_REPORT);
3431 ok(hwnd != NULL, "failed to create a listview window\n");
3432 memset(&item, 0, sizeof(item));
3433 item.mask = LVIF_TEXT | LVIF_STATE;
3434 item.iItem = 0;
3435 item.stateMask = LVIS_SELECTED;
3436 item.state = LVIS_SELECTED;
3437 item.pszText = testA;
3438 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3439 expect(0, res);
3440 /* retrieve with LVIF_NORECOMPUTE */
3441 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3442 item.iItem = 0;
3443 item.pszText = buff;
3444 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3445 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3446 expect(TRUE, res);
3447 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3448
3449 item.mask = LVIF_TEXT;
3450 item.iItem = 1;
3451 item.pszText = LPSTR_TEXTCALLBACKA;
3452 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3453 expect(1, res);
3454
3455 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3456 item.iItem = 1;
3457 item.pszText = buff;
3458 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3459
3460 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3461 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3462 expect(TRUE, res);
3463 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3464 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3465 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3466
3467 DestroyWindow(hwnd);
3468
3469 /* LVS_OWNERDATA */
3470 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3471 ok(hwnd != NULL, "failed to create a listview window\n");
3472
3473 item.mask = LVIF_STATE;
3474 item.stateMask = LVIS_SELECTED;
3475 item.state = LVIS_SELECTED;
3476 item.iItem = 0;
3477 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3478 expect(0, res);
3479
3480 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3481 item.iItem = 0;
3482 item.pszText = buff;
3483 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3484 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3485 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3486 expect(TRUE, res);
3487 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3488 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3489 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3490
3491 DestroyWindow(hwnd);
3492 }
3493
3494 static void test_nosortheader(void)
3495 {
3496 HWND hwnd, header;
3497 LONG_PTR style;
3498
3499 hwnd = create_listview_control(LVS_REPORT);
3500 ok(hwnd != NULL, "failed to create a listview window\n");
3501
3502 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3503 ok(IsWindow(header), "header expected\n");
3504
3505 style = GetWindowLongPtrA(header, GWL_STYLE);
3506 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3507
3508 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3509 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3510 /* HDS_BUTTONS retained */
3511 style = GetWindowLongPtrA(header, GWL_STYLE);
3512 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3513
3514 DestroyWindow(hwnd);
3515
3516 /* create with LVS_NOSORTHEADER */
3517 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3518 ok(hwnd != NULL, "failed to create a listview window\n");
3519
3520 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3521 ok(IsWindow(header), "header expected\n");
3522
3523 style = GetWindowLongPtrA(header, GWL_STYLE);
3524 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3525
3526 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3527 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3528 /* not changed here */
3529 style = GetWindowLongPtrA(header, GWL_STYLE);
3530 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3531
3532 DestroyWindow(hwnd);
3533 }
3534
3535 static void test_setredraw(void)
3536 {
3537 HWND hwnd;
3538 DWORD_PTR style;
3539 DWORD ret;
3540 HDC hdc;
3541 RECT rect;
3542
3543 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3544 ok(hwnd != NULL, "failed to create a listview window\n");
3545
3546 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3547 ListView seems to handle it internally without DefWinProc */
3548
3549 /* default value first */
3550 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3551 expect(0, ret);
3552 /* disable */
3553 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3554 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3555 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3556 expect(0, ret);
3557 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3558 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3559 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3560 expect(0, ret);
3561
3562 /* check update rect after redrawing */
3563 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3564 expect(0, ret);
3565 InvalidateRect(hwnd, NULL, FALSE);
3566 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3567 rect.right = rect.bottom = 1;
3568 GetUpdateRect(hwnd, &rect, FALSE);
3569 expect(0, rect.right);
3570 expect(0, rect.bottom);
3571
3572 /* WM_ERASEBKGND */
3573 hdc = GetWindowDC(hwndparent);
3574 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3575 expect(TRUE, ret);
3576 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3577 expect(0, ret);
3578 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3579 expect(TRUE, ret);
3580 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3581 expect(0, ret);
3582 ReleaseDC(hwndparent, hdc);
3583
3584 /* check notification messages to show that repainting is disabled */
3585 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3586 expect(TRUE, ret);
3587 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3588 expect(0, ret);
3589 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3590
3591 InvalidateRect(hwnd, NULL, TRUE);
3592 UpdateWindow(hwnd);
3593 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3594 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3595
3596 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3597 expect(TRUE, ret);
3598 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3599 InvalidateRect(hwnd, NULL, TRUE);
3600 UpdateWindow(hwnd);
3601 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3602 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3603
3604 /* message isn't forwarded to header */
3605 subclass_header(hwnd);
3606 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3607 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3608 expect(0, ret);
3609 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3610 "WM_SETREDRAW: not forwarded to header", FALSE);
3611
3612 DestroyWindow(hwnd);
3613 }
3614
3615 static void test_hittest(void)
3616 {
3617 HWND hwnd;
3618 DWORD r;
3619 RECT bounds;
3620 LVITEMA item;
3621 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3622 POINT pos;
3623 INT x, y, i;
3624 WORD vert;
3625 HIMAGELIST himl, himl2;
3626 HBITMAP hbmp;
3627
3628 hwnd = create_listview_control(LVS_REPORT);
3629 ok(hwnd != NULL, "failed to create a listview window\n");
3630
3631 /* LVS_REPORT with a single subitem (2 columns) */
3632 insert_column(hwnd, 0);
3633 insert_column(hwnd, 1);
3634 insert_item(hwnd, 0);
3635
3636 item.iSubItem = 0;
3637 /* the only purpose of that line is to be as long as a half item rect */
3638 item.pszText = text;
3639 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3640 expect(TRUE, r);
3641
3642 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3643 expect(TRUE, r);
3644 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3645 expect(TRUE, r);
3646
3647 memset(&bounds, 0, sizeof(bounds));
3648 bounds.left = LVIR_BOUNDS;
3649 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3650 expect(1, r);
3651 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3652 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3653 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3654 vert = HIWORD(r);
3655 ok(bounds.bottom - bounds.top == vert,
3656 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3657 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3658 expect(TRUE, r);
3659
3660 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3661
3662 /* outside columns by x position - valid is [0, 199] */
3663 x = -1;
3664 y = pos.y + (bounds.bottom - bounds.top) / 2;
3665 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3666 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3667
3668 x = pos.x + 50; /* column half width */
3669 y = pos.y + (bounds.bottom - bounds.top) / 2;
3670 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3671 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3672 x = pos.x + 150; /* outside column */
3673 y = pos.y + (bounds.bottom - bounds.top) / 2;
3674 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3675 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3676 y = (bounds.bottom - bounds.top) / 2;
3677 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3678 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3679 /* outside possible client rectangle (to right) */
3680 x = pos.x + 500;
3681 y = pos.y + (bounds.bottom - bounds.top) / 2;
3682 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3683 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3684 y = (bounds.bottom - bounds.top) / 2;
3685 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3686 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3687 /* subitem returned with -1 item too */
3688 x = pos.x + 150;
3689 y = bounds.top - vert;
3690 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3691 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3692 /* return values appear to underflow with negative indices */
3693 i = -2;
3694 y = y - vert;
3695 while (i > -10) {
3696 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3697 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3698 y = y - vert;
3699 i--;
3700 }
3701 /* parent client area is 100x100 by default */
3702 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3703 x = pos.x + 150; /* outside column */
3704 y = pos.y + (bounds.bottom - bounds.top) / 2;
3705 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3706 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3707 y = (bounds.bottom - bounds.top) / 2;
3708 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3709 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3710 /* the same with LVS_EX_FULLROWSELECT */
3711 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3712 x = pos.x + 150; /* outside column */
3713 y = pos.y + (bounds.bottom - bounds.top) / 2;
3714 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3715 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3716 y = (bounds.bottom - bounds.top) / 2;
3717 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3718 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3719 x = pos.x + 150; /* outside column */
3720 y = pos.y + (bounds.bottom - bounds.top) / 2;
3721 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3722 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3723 y = (bounds.bottom - bounds.top) / 2;
3724 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3725 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3726 /* outside possible client rectangle (to right) */
3727 x = pos.x + 500;
3728 y = pos.y + (bounds.bottom - bounds.top) / 2;
3729 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3730 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3731 y = (bounds.bottom - bounds.top) / 2;
3732 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3733 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3734 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3735 himl = ImageList_Create(16, 16, 0, 4, 4);
3736 ok(himl != NULL, "failed to create imagelist\n");
3737 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3738 ok(hbmp != NULL, "failed to create bitmap\n");
3739 r = ImageList_Add(himl, hbmp, 0);
3740 ok(r == 0, "should be zero\n");
3741 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3742 ok(hbmp != NULL, "failed to create bitmap\n");
3743 r = ImageList_Add(himl, hbmp, 0);
3744 ok(r == 1, "should be one\n");
3745
3746 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3747 expect(0, r);
3748
3749 item.mask = LVIF_IMAGE;
3750 item.iImage = 0;
3751 item.iItem = 0;
3752 item.iSubItem = 0;
3753 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3754 expect(TRUE, r);
3755 /* on state icon */
3756 x = pos.x + 8;
3757 y = pos.y + (bounds.bottom - bounds.top) / 2;
3758 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3759 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3760 y = (bounds.bottom - bounds.top) / 2;
3761 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3762
3763 /* state icons indices are 1 based, check with valid index */
3764 item.mask = LVIF_STATE;
3765 item.state = INDEXTOSTATEIMAGEMASK(1);
3766 item.stateMask = LVIS_STATEIMAGEMASK;
3767 item.iItem = 0;
3768 item.iSubItem = 0;
3769 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3770 expect(TRUE, r);
3771 /* on state icon */
3772 x = pos.x + 8;
3773 y = pos.y + (bounds.bottom - bounds.top) / 2;
3774 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3775 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3776 y = (bounds.bottom - bounds.top) / 2;
3777 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3778
3779 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3780 ok(himl2 == himl, "should return handle\n");
3781
3782 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3783 expect(0, r);
3784 /* on item icon */
3785 x = pos.x + 8;
3786 y = pos.y + (bounds.bottom - bounds.top) / 2;
3787 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3788 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3789 y = (bounds.bottom - bounds.top) / 2;
3790 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3791
3792 DestroyWindow(hwnd);
3793 }
3794
3795 static void test_getviewrect(void)
3796 {
3797 HWND hwnd;
3798 DWORD r;
3799 RECT rect;
3800 LVITEMA item;
3801
3802 hwnd = create_listview_control(LVS_REPORT);
3803 ok(hwnd != NULL, "failed to create a listview window\n");
3804
3805 /* empty */
3806 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3807 expect(TRUE, r);
3808
3809 insert_column(hwnd, 0);
3810 insert_column(hwnd, 1);
3811
3812 memset(&item, 0, sizeof(item));
3813 item.iItem = 0;
3814 item.iSubItem = 0;
3815 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3816
3817 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3818 expect(TRUE, r);
3819 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3820 expect(TRUE, r);
3821
3822 rect.left = rect.right = rect.top = rect.bottom = -1;
3823 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3824 expect(TRUE, r);
3825 /* left is set to (2e31-1) - XP SP2 */
3826 expect(0, rect.right);
3827 expect(0, rect.top);
3828 expect(0, rect.bottom);
3829
3830 /* switch to LVS_ICON */
3831 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
3832
3833 rect.left = rect.right = rect.top = rect.bottom = -1;
3834 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3835 expect(TRUE, r);
3836 expect(0, rect.left);
3837 expect(0, rect.top);
3838 /* precise value differs for 2k, XP and Vista */
3839 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3840 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3841
3842 DestroyWindow(hwnd);
3843 }
3844
3845 static void test_getitemposition(void)
3846 {
3847 HWND hwnd, header;
3848 DWORD r;
3849 POINT pt;
3850 RECT rect;
3851
3852 hwnd = create_listview_control(LVS_REPORT);
3853 ok(hwnd != NULL, "failed to create a listview window\n");
3854 header = subclass_header(hwnd);
3855
3856 /* LVS_REPORT, single item, no columns added */
3857 insert_item(hwnd, 0);
3858
3859 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3860
3861 pt.x = pt.y = -1;
3862 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3863 expect(TRUE, r);
3864 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3865
3866 /* LVS_REPORT, single item, single column */
3867 insert_column(hwnd, 0);
3868
3869 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3870
3871 pt.x = pt.y = -1;
3872 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3873 expect(TRUE, r);
3874 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3875
3876 memset(&rect, 0, sizeof(rect));
3877 SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3878 /* some padding? */
3879 expect(2, pt.x);
3880 /* offset by header height */
3881 expect(rect.bottom - rect.top, pt.y);
3882
3883 DestroyWindow(hwnd);
3884 }
3885
3886 static void test_columnscreation(void)
3887 {
3888 HWND hwnd, header;
3889 DWORD r;
3890
3891 hwnd = create_listview_control(LVS_REPORT);
3892 ok(hwnd != NULL, "failed to create a listview window\n");
3893
3894 insert_item(hwnd, 0);
3895
3896 /* headers columns aren't created automatically */
3897 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3898 ok(IsWindow(header), "Expected header handle\n");
3899 r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
3900 expect(0, r);
3901
3902 DestroyWindow(hwnd);
3903 }
3904
3905 static void test_getitemrect(void)
3906 {
3907 HWND hwnd;
3908 HIMAGELIST himl, himl_ret;
3909 HBITMAP hbm;
3910 RECT rect;
3911 DWORD r;
3912 LVITEMA item;
3913 LVCOLUMNA col;
3914 INT order[2];
3915 POINT pt;
3916
3917 /* rectangle isn't empty for empty text items */
3918 hwnd = create_listview_control(LVS_LIST);
3919 memset(&item, 0, sizeof(item));
3920 item.mask = 0;
3921 item.iItem = 0;
3922 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3923 expect(0, r);
3924 rect.left = LVIR_LABEL;
3925 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3926 expect(TRUE, r);
3927 expect(0, rect.left);
3928 expect(0, rect.top);
3929 /* estimate it as width / height ratio */
3930 todo_wine
3931 ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom);
3932 DestroyWindow(hwnd);
3933
3934 hwnd = create_listview_control(LVS_REPORT);
3935 ok(hwnd != NULL, "failed to create a listview window\n");
3936
3937 /* empty item */
3938 memset(&item, 0, sizeof(item));
3939 item.iItem = 0;
3940 item.iSubItem = 0;
3941 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3942 expect(0, r);
3943
3944 rect.left = LVIR_BOUNDS;
3945 rect.right = rect.top = rect.bottom = -1;
3946 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3947 expect(TRUE, r);
3948
3949 /* zero width rectangle with no padding */
3950 expect(0, rect.left);
3951 expect(0, rect.right);
3952
3953 insert_column(hwnd, 0);
3954 insert_column(hwnd, 1);
3955
3956 col.mask = LVCF_WIDTH;
3957 col.cx = 50;
3958 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
3959 expect(TRUE, r);
3960
3961 col.mask = LVCF_WIDTH;
3962 col.cx = 100;
3963 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
3964 expect(TRUE, r);
3965
3966 rect.left = LVIR_BOUNDS;
3967 rect.right = rect.top = rect.bottom = -1;
3968 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3969 expect(TRUE, r);
3970
3971 /* still no left padding */
3972 expect(0, rect.left);
3973 expect(150, rect.right);
3974
3975 rect.left = LVIR_SELECTBOUNDS;
3976 rect.right = rect.top = rect.bottom = -1;
3977 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3978 expect(TRUE, r);
3979 /* padding */
3980 expect(2, rect.left);
3981
3982 rect.left = LVIR_LABEL;
3983 rect.right = rect.top = rect.bottom = -1;
3984 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3985 expect(TRUE, r);
3986 /* padding, column width */
3987 expect(2, rect.left);
3988 expect(50, rect.right);
3989
3990 /* no icons attached */
3991 rect.left = LVIR_ICON;
3992 rect.right = rect.top = rect.bottom = -1;
3993 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3994 expect(TRUE, r);
3995 /* padding */
3996 expect(2, rect.left);
3997 expect(2, rect.right);
3998
3999 /* change order */
4000 order[0] = 1; order[1] = 0;
4001 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4002 expect(TRUE, r);
4003 pt.x = -1;
4004 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4005 expect(TRUE, r);
4006 /* 1 indexed column width + padding */
4007 expect(102, pt.x);
4008 /* rect is at zero too */
4009 rect.left = LVIR_BOUNDS;
4010 rect.right = rect.top = rect.bottom = -1;
4011 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4012 expect(TRUE, r);
4013 expect(0, rect.left);
4014 /* just width sum */
4015 expect(150, rect.right);
4016
4017 rect.left = LVIR_SELECTBOUNDS;
4018 rect.right = rect.top = rect.bottom = -1;
4019 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4020 expect(TRUE, r);
4021 /* column width + padding */
4022 expect(102, rect.left);
4023
4024 /* back to initial order */
4025 order[0] = 0; order[1] = 1;
4026 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4027 expect(TRUE, r);
4028
4029 /* state icons */
4030 himl = ImageList_Create(16, 16, 0, 2, 2);
4031 ok(himl != NULL, "failed to create imagelist\n");
4032 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4033 ok(hbm != NULL, "failed to create bitmap\n");
4034 r = ImageList_Add(himl, hbm, 0);
4035 expect(0, r);
4036 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4037 ok(hbm != NULL, "failed to create bitmap\n");
4038 r = ImageList_Add(himl, hbm, 0);
4039 expect(1, r);
4040
4041 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4042 expect(0, r);
4043
4044 item.mask = LVIF_STATE;
4045 item.state = INDEXTOSTATEIMAGEMASK(1);
4046 item.stateMask = LVIS_STATEIMAGEMASK;
4047 item.iItem = 0;
4048 item.iSubItem = 0;
4049 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4050 expect(TRUE, r);
4051
4052 /* icon bounds */
4053 rect.left = LVIR_ICON;
4054 rect.right = rect.top = rect.bottom = -1;
4055 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4056 expect(TRUE, r);
4057 /* padding + stateicon width */
4058 expect(18, rect.left);
4059 expect(18, rect.right);
4060 /* label bounds */
4061 rect.left = LVIR_LABEL;
4062 rect.right = rect.top = rect.bottom = -1;
4063 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4064 expect(TRUE, r);
4065 /* padding + stateicon width -> column width */
4066 expect(18, rect.left);
4067 expect(50, rect.right);
4068
4069 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4070 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4071
4072 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4073 expect(0, r);
4074
4075 item.mask = LVIF_STATE | LVIF_IMAGE;
4076 item.iImage = 1;
4077 item.state = 0;
4078 item.stateMask = ~0;
4079 item.iItem = 0;
4080 item.iSubItem = 0;
4081 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4082 expect(TRUE, r);
4083
4084 /* icon bounds */
4085 rect.left = LVIR_ICON;
4086 rect.right = rect.top = rect.bottom = -1;
4087 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4088 expect(TRUE, r);
4089 /* padding, icon width */
4090 expect(2, rect.left);
4091 expect(18, rect.right);
4092 /* label bounds */
4093 rect.left = LVIR_LABEL;
4094 rect.right = rect.top = rect.bottom = -1;
4095 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4096 expect(TRUE, r);
4097 /* padding + icon width -> column width */
4098 expect(18, rect.left);
4099 expect(50, rect.right);
4100
4101 /* select bounds */
4102 rect.left = LVIR_SELECTBOUNDS;
4103 rect.right = rect.top = rect.bottom = -1;
4104 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4105 expect(TRUE, r);
4106 /* padding, column width */
4107 expect(2, rect.left);
4108 expect(50, rect.right);
4109
4110 /* try with indentation */
4111 item.mask = LVIF_INDENT;
4112 item.iIndent = 1;
4113 item.iItem = 0;
4114 item.iSubItem = 0;
4115 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4116 expect(TRUE, r);
4117
4118 /* bounds */
4119 rect.left = LVIR_BOUNDS;
4120 rect.right = rect.top = rect.bottom = -1;
4121 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4122 expect(TRUE, r);
4123 /* padding + 1 icon width, column width */
4124 expect(0, rect.left);
4125 expect(150, rect.right);
4126
4127 /* select bounds */
4128 rect.left = LVIR_SELECTBOUNDS;
4129 rect.right = rect.top = rect.bottom = -1;
4130 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4131 expect(TRUE, r);
4132 /* padding + 1 icon width, column width */
4133 expect(2 + 16, rect.left);
4134 expect(50, rect.right);
4135
4136 /* label bounds */
4137 rect.left = LVIR_LABEL;
4138 rect.right = rect.top = rect.bottom = -1;
4139 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4140 expect(TRUE, r);
4141 /* padding + 2 icon widths, column width */
4142 expect(2 + 16*2, rect.left);
4143 expect(50, rect.right);
4144
4145 /* icon bounds */
4146 rect.left = LVIR_ICON;
4147 rect.right = rect.top = rect.bottom = -1;
4148 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4149 expect(TRUE, r);
4150 /* padding + 1 icon width indentation, icon width */
4151 expect(2 + 16, rect.left);
4152 expect(34, rect.right);
4153
4154 DestroyWindow(hwnd);
4155 }
4156
4157 static void test_editbox(void)
4158 {
4159 static CHAR testitemA[] = "testitem";
4160 static CHAR testitem1A[] = "testitem_quitelongname";
4161 static CHAR testitem2A[] = "testITEM_quitelongname";
4162 static CHAR buffer[25];
4163 HWND hwnd, hwndedit, hwndedit2, header;
4164 LVITEMA item;
4165 INT r;
4166
4167 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4168 ok(hwnd != NULL, "failed to create a listview window\n");
4169
4170 insert_column(hwnd, 0);
4171
4172 memset(&item, 0, sizeof(item));
4173 item.mask = LVIF_TEXT;
4174 item.pszText = testitemA;
4175 item.iItem = 0;
4176 item.iSubItem = 0;
4177 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4178 expect(0, r);
4179
4180 /* test notifications without edit created */
4181 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4182 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4183 expect(0, r);
4184 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4185 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4186 /* same thing but with valid window */
4187 hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4188 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4189 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4190 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4191 expect(0, r);
4192 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4193 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4194 DestroyWindow(hwndedit);
4195
4196 /* setting focus is necessary */
4197 SetFocus(hwnd);
4198 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4199 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4200
4201 /* test children Z-order after Edit box created */
4202 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4203 ok(IsWindow(header), "Expected header to be created\n");
4204 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4205 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4206
4207 /* modify initial string */
4208 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4209 expect(TRUE, r);
4210
4211 /* edit window is resized and repositioned,
4212 check again for Z-order - it should be preserved */
4213 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4214 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4215
4216 /* return focus to listview */
4217 SetFocus(hwnd);
4218
4219 memset(&item, 0, sizeof(item));
4220 item.mask = LVIF_TEXT;
4221 item.pszText = buffer;
4222 item.cchTextMax = sizeof(buffer);
4223 item.iItem = 0;
4224 item.iSubItem = 0;
4225 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4226 expect(TRUE, r);
4227
4228 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4229
4230 /* send LVM_EDITLABEL on already created edit */
4231 SetFocus(hwnd);
4232 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4233 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4234 /* focus will be set to edit */
4235 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4236 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4237 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4238
4239 /* creating label disabled when control isn't focused */
4240 SetFocus(0);
4241 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4242 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4243
4244 /* check EN_KILLFOCUS handling */
4245 memset(&item, 0, sizeof(item));
4246 item.pszText = testitemA;
4247 item.iItem = 0;
4248 item.iSubItem = 0;
4249 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4250 expect(TRUE, r);
4251
4252 SetFocus(hwnd);
4253 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4254 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4255 /* modify edit and notify control that it lost focus */
4256 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4257 expect(TRUE, r);
4258 g_editbox_disp_info.item.pszText = NULL;
4259 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4260 expect(0, r);
4261 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4262
4263 memset(&item, 0, sizeof(item));
4264 item.pszText = buffer;
4265 item.cchTextMax = sizeof(buffer);
4266 item.iItem = 0;
4267 item.iSubItem = 0;
4268 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4269 expect(lstrlenA(item.pszText), r);
4270 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4271 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4272
4273 /* change item name to differ in casing only */
4274 SetFocus(hwnd);
4275 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4276 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4277 /* modify edit and notify control that it lost focus */
4278 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4279 expect(TRUE, r);
4280 g_editbox_disp_info.item.pszText = NULL;
4281 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4282 expect(0, r);
4283 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4284
4285 memset(&item, 0, sizeof(item));
4286 item.pszText = buffer;
4287 item.cchTextMax = sizeof(buffer);
4288 item.iItem = 0;
4289 item.iSubItem = 0;
4290 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4291 expect(lstrlenA(item.pszText), r);
4292 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4293 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4294
4295 /* end edit without saving */
4296 SetFocus(hwnd);
4297 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4298 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4299 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4300 expect(0, r);
4301 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4302 "edit box - end edit, no change, escape", TRUE);
4303 /* end edit with saving */
4304 SetFocus(hwnd);
4305 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4306 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4307 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4308 expect(0, r);
4309 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4310 "edit box - end edit, no change, return", TRUE);
4311
4312 memset(&item, 0, sizeof(item));
4313 item.pszText = buffer;
4314 item.cchTextMax = sizeof(buffer);
4315 item.iItem = 0;
4316 item.iSubItem = 0;
4317 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4318 expect(lstrlenA(item.pszText), r);
4319 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4320
4321 /* LVM_EDITLABEL with -1 destroys current edit */
4322 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4323 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4324 /* no edit present */
4325 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4326 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4327 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4328 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4329 /* edit present */
4330 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4331 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4332 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4333 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4334 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4335 /* check another negative value */
4336 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4337 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4338 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4339 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4340 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4341 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4342 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4343 /* and value greater than max item index */
4344 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4345 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4346 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4347 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4348 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4349 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4350 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4351 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4352
4353 /* messaging tests */
4354 SetFocus(hwnd);
4355 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4356 blockEdit = FALSE;
4357 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4358 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4359 /* testing only sizing messages */
4360 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4361 "edit box create - sizing", FALSE);
4362
4363 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4364 SetFocus(hwnd);
4365 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4366 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4368 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4369 expect(0, r);
4370 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4371 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4372
4373 DestroyWindow(hwnd);
4374 }
4375
4376 static void test_notifyformat(void)
4377 {
4378 HWND hwnd, header;
4379 DWORD r;
4380
4381 hwnd = create_listview_control(LVS_REPORT);
4382 ok(hwnd != NULL, "failed to create a listview window\n");
4383
4384 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4385 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4386 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4387 expect(0, r);
4388 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4389 /* set */
4390 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4391 expect(0, r);
4392 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4393 if (r == 1)
4394 {
4395 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4396 expect(1, r);
4397 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4398 expect(0, r);
4399 }
4400 else
4401 {
4402 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
4403 DestroyWindow(hwnd);
4404 return;
4405 }
4406
4407 DestroyWindow(hwnd);
4408
4409 /* test failure in parent WM_NOTIFYFORMAT */
4410 notifyFormat = 0;
4411 hwnd = create_listview_control(LVS_REPORT);
4412 ok(hwnd != NULL, "failed to create a listview window\n");
4413 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4414 ok(IsWindow(header), "expected header to be created\n");
4415 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4416 expect(0, r);
4417 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4418 ok( r == 1, "Expected 1, got %d\n", r );
4419 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4420 ok(r != 0, "Expected valid format\n");
4421
4422 notifyFormat = NFR_UNICODE;
4423 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4424 expect(NFR_UNICODE, r);
4425 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4426 expect(1, r);
4427 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4428 ok( r == 1, "Expected 1, got %d\n", r );
4429
4430 notifyFormat = NFR_ANSI;
4431 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4432 expect(NFR_ANSI, r);
4433 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4434 expect(0, r);
4435 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4436 ok( r == 1, "Expected 1, got %d\n", r );
4437
4438 DestroyWindow(hwnd);
4439
4440 hwndparentW = create_parent_window(TRUE);
4441 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4442 if (!IsWindow(hwndparentW)) return;
4443
4444 notifyFormat = -1;
4445 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4446 ok(hwnd != NULL, "failed to create a listview window\n");
4447 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4448 ok(IsWindow(header), "expected header to be created\n");
4449 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4450 expect(1, r);
4451 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4452 expect(1, r);
4453 DestroyWindow(hwnd);
4454 /* receiving error code defaulting to ansi */
4455 notifyFormat = 0;
4456 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4457 ok(hwnd != NULL, "failed to create a listview window\n");
4458 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4459 ok(IsWindow(header), "expected header to be created\n");
4460 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4461 expect(0, r);
4462 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4463 expect(1, r);
4464 DestroyWindow(hwnd);
4465 /* receiving ansi code from unicode window, use it */
4466 notifyFormat = NFR_ANSI;
4467 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4468 ok(hwnd != NULL, "failed to create a listview window\n");
4469 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4470 ok(IsWindow(header), "expected header to be created\n");
4471 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4472 expect(0, r);
4473 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4474 expect(1, r);
4475 DestroyWindow(hwnd);
4476 /* unicode listview with ansi parent window */
4477 notifyFormat = -1;
4478 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4479 ok(hwnd != NULL, "failed to create a listview window\n");
4480 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4481 ok(IsWindow(header), "expected header to be created\n");
4482 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4483 expect(0, r);
4484 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4485 expect(1, r);
4486 DestroyWindow(hwnd);
4487 /* unicode listview with ansi parent window, return error code */
4488 notifyFormat = 0;
4489 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4490 ok(hwnd != NULL, "failed to create a listview window\n");
4491 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4492 ok(IsWindow(header), "expected header to be created\n");
4493 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4494 expect(0, r);
4495 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4496 expect(1, r);
4497 DestroyWindow(hwnd);
4498
4499 DestroyWindow(hwndparentW);
4500 }
4501
4502 static void test_indentation(void)
4503 {
4504 HWND hwnd;
4505 LVITEMA item;
4506 DWORD r;
4507
4508 hwnd = create_listview_control(LVS_REPORT);
4509 ok(hwnd != NULL, "failed to create a listview window\n");
4510
4511 memset(&item, 0, sizeof(item));
4512 item.mask = LVIF_INDENT;
4513 item.iItem = 0;
4514 item.iIndent = I_INDENTCALLBACK;
4515 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4516 expect(0, r);
4517
4518 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4519
4520 item.iItem = 0;
4521 item.mask = LVIF_INDENT;
4522 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4523 expect(TRUE, r);
4524
4525 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4526 "get indent dispinfo", FALSE);
4527
4528 DestroyWindow(hwnd);
4529 }
4530
4531 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4532 {
4533 return 0;
4534 }
4535
4536 static BOOL is_below_comctl_5(void)
4537 {
4538 HWND hwnd;
4539 BOOL ret;
4540
4541 hwnd = create_listview_control(LVS_REPORT);
4542 ok(hwnd != NULL, "failed to create a listview window\n");
4543 insert_item(hwnd, 0);
4544
4545 ret = SendMessageA(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4546
4547 DestroyWindow(hwnd);
4548
4549 return !ret;
4550 }
4551
4552 static void test_get_set_view(void)
4553 {
4554 HWND hwnd;
4555 DWORD ret;
4556 DWORD_PTR style;
4557
4558 /* test style->view mapping */
4559 hwnd = create_listview_control(LVS_REPORT);
4560 ok(hwnd != NULL, "failed to create a listview window\n");
4561
4562 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4563 expect(LV_VIEW_DETAILS, ret);
4564
4565 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4566 /* LVS_ICON == 0 */
4567 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4568 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4569 expect(LV_VIEW_ICON, ret);
4570
4571 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4572 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4573 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4574 expect(LV_VIEW_SMALLICON, ret);
4575
4576 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4577 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4578 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4579 expect(LV_VIEW_LIST, ret);
4580
4581 /* switching view doesn't touch window style */
4582 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4583 expect(1, ret);
4584 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4585 ok(style & LVS_LIST, "Expected style to be preserved\n");
4586 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4587 expect(1, ret);
4588 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4589 ok(style & LVS_LIST, "Expected style to be preserved\n");
4590 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4591 expect(1, ret);
4592 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4593 ok(style & LVS_LIST, "Expected style to be preserved\n");
4594
4595 /* now change window style to see if view is remapped */
4596 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4597 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4598 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4599 expect(LV_VIEW_SMALLICON, ret);
4600
4601 DestroyWindow(hwnd);
4602 }
4603
4604 static void test_canceleditlabel(void)
4605 {
4606 HWND hwnd, hwndedit;
4607 DWORD ret;
4608 CHAR buff[10];
4609 LVITEMA itema;
4610 static CHAR test[] = "test";
4611 static const CHAR test1[] = "test1";
4612
4613 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4614 ok(hwnd != NULL, "failed to create a listview window\n");
4615
4616 insert_item(hwnd, 0);
4617
4618 /* try without edit created */
4619 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4620 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4621 expect(TRUE, ret);
4622 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4623 "cancel edit label without edit", FALSE);
4624
4625 /* cancel without data change */
4626 SetFocus(hwnd);
4627 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4628 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4629 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4630 expect(TRUE, ret);
4631 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4632
4633 /* cancel after data change */
4634 memset(&itema, 0, sizeof(itema));
4635 itema.pszText = test;
4636 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4637 expect(TRUE, ret);
4638 SetFocus(hwnd);
4639 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4640 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4641 ret = SetWindowTextA(hwndedit, test1);
4642 expect(1, ret);
4643 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4644 expect(TRUE, ret);
4645 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4646 memset(&itema, 0, sizeof(itema));
4647 itema.pszText = buff;
4648 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4649 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4650 expect(5, ret);
4651 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4652
4653 DestroyWindow(hwnd);
4654 }
4655
4656 static void test_mapidindex(void)
4657 {
4658 HWND hwnd;
4659 INT ret;
4660
4661 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4662 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4663 ok(hwnd != NULL, "failed to create a listview window\n");
4664 insert_item(hwnd, 0);
4665 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4666 expect(-1, ret);
4667 DestroyWindow(hwnd);
4668
4669 hwnd = create_listview_control(LVS_REPORT);
4670 ok(hwnd != NULL, "failed to create a listview window\n");
4671
4672 /* LVM_MAPINDEXTOID with invalid index */
4673 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4674 expect(-1, ret);
4675
4676 insert_item(hwnd, 0);
4677 insert_item(hwnd, 1);
4678
4679 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4680 expect(-1, ret);
4681 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4682 expect(-1, ret);
4683
4684 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4685 expect(0, ret);
4686 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4687 expect(1, ret);
4688 /* remove 0 indexed item, id retained */
4689 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4690 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4691 expect(1, ret);
4692 /* new id starts from previous value */
4693 insert_item(hwnd, 1);
4694 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4695 expect(2, ret);
4696
4697 /* get index by id */
4698 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4699 expect(-1, ret);
4700 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4701 expect(-1, ret);
4702 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4703 expect(0, ret);
4704 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4705 expect(1, ret);
4706
4707 DestroyWindow(hwnd);
4708 }
4709
4710 static void test_getitemspacing(void)
4711 {
4712 HWND hwnd;
4713 DWORD ret;
4714 INT cx, cy;
4715 HIMAGELIST himl40, himl80;
4716
4717 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4718 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4719
4720 /* LVS_ICON */
4721 hwnd = create_listview_control(LVS_ICON);
4722 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4723 expect(cx, LOWORD(ret));
4724 expect(cy, HIWORD(ret));
4725
4726 /* now try with icons */
4727 himl40 = ImageList_Create(40, 40, 0, 4, 4);
4728 ok(himl40 != NULL, "failed to create imagelist\n");
4729 himl80 = ImageList_Create(80, 80, 0, 4, 4);
4730 ok(himl80 != NULL, "failed to create imagelist\n");
4731 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4732 expect(0, ret);
4733
4734 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4735 /* spacing + icon size returned */
4736 expect(cx + 40, LOWORD(ret));
4737 expect(cy + 40, HIWORD(ret));
4738 /* try changing icon size */
4739 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4740
4741 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4742 /* spacing + icon size returned */
4743 expect(cx + 80, LOWORD(ret));
4744 expect(cy + 80, HIWORD(ret));
4745
4746 /* set own icon spacing */
4747 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4748 expect(cx + 80, LOWORD(ret));
4749 expect(cy + 80, HIWORD(ret));
4750
4751 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4752 /* set size returned */
4753 expect(100, LOWORD(ret));
4754 expect(100, HIWORD(ret));
4755
4756 /* now change image list - icon spacing should be unaffected */
4757 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4758
4759 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4760 /* set size returned */
4761 expect(100, LOWORD(ret));
4762 expect(100, HIWORD(ret));
4763
4764 /* spacing = 0 - keep previous value */
4765 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4766 expect(100, LOWORD(ret));
4767 expect(100, HIWORD(ret));
4768
4769 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4770 expect(100, LOWORD(ret));
4771
4772 expect(0xFFFF, HIWORD(ret));
4773
4774 if (sizeof(void*) == 8)
4775 {
4776 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4777 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4778 expect(100, LOWORD(ret));
4779 expect(0xFFFF, HIWORD(ret));
4780
4781 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4782 expect(0xFFFF, LOWORD(ret));
4783 expect(0xFFFF, HIWORD(ret));
4784 }
4785 else
4786 {
4787 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4788 expect(100, LOWORD(ret));
4789 expect(0xFFFF, HIWORD(ret));
4790 }
4791 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4792 /* spacing + icon size returned */
4793 expect(cx + 40, LOWORD(ret));
4794 expect(cy + 40, HIWORD(ret));
4795
4796 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4797 ImageList_Destroy(himl80);
4798 DestroyWindow(hwnd);
4799 /* LVS_SMALLICON */
4800 hwnd = create_listview_control(LVS_SMALLICON);
4801 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4802 expect(cx, LOWORD(ret));
4803 expect(cy, HIWORD(ret));
4804
4805 /* spacing does not depend on selected view type */
4806 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4807 expect(0, ret);
4808
4809 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4810 /* spacing + icon size returned */
4811 expect(cx + 40, LOWORD(ret));
4812 expect(cy + 40, HIWORD(ret));
4813
4814 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4815 ImageList_Destroy(himl40);
4816 DestroyWindow(hwnd);
4817 /* LVS_REPORT */
4818 hwnd = create_listview_control(LVS_REPORT);
4819 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4820 expect(cx, LOWORD(ret));
4821 expect(cy, HIWORD(ret));
4822
4823 DestroyWindow(hwnd);
4824 /* LVS_LIST */
4825 hwnd = create_listview_control(LVS_LIST);
4826 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4827 expect(cx, LOWORD(ret));
4828 expect(cy, HIWORD(ret));
4829
4830 DestroyWindow(hwnd);
4831 }
4832
4833 static INT get_current_font_height(HWND listview)
4834 {
4835 TEXTMETRICA tm;
4836 HFONT hfont;
4837 HWND hwnd;
4838 HDC hdc;
4839
4840 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
4841 if (!hwnd)
4842 hwnd = listview;
4843
4844 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
4845 if (!hfont) {
4846 hdc = GetDC(hwnd);
4847 GetTextMetricsA(hdc, &tm);
4848 ReleaseDC(hwnd, hdc);
4849 }
4850 else {
4851 HFONT oldfont;
4852
4853 hdc = GetDC(0);
4854 oldfont = SelectObject(hdc, hfont);
4855 GetTextMetricsA(hdc, &tm);
4856 SelectObject(hdc, oldfont);
4857 ReleaseDC(0, hdc);
4858 }
4859
4860 return tm.tmHeight;
4861 }
4862
4863 static void test_getcolumnwidth(void)
4864 {
4865 HWND hwnd;
4866 INT ret;
4867 DWORD_PTR style;
4868 LVCOLUMNA col;
4869 LVITEMA itema;
4870 INT height;
4871
4872 /* default column width */
4873 hwnd = create_listview_control(LVS_ICON);
4874 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4875 expect(0, ret);
4876 style = GetWindowLongA(hwnd, GWL_STYLE);
4877 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
4878 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4879 todo_wine expect(8, ret);
4880 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
4881 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
4882 col.mask = 0;
4883 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4884 expect(0, ret);
4885 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4886 expect(10, ret);
4887 DestroyWindow(hwnd);
4888
4889 /* default column width with item added */
4890 hwnd = create_listview_control(LVS_LIST);
4891 memset(&itema, 0, sizeof(itema));
4892 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4893 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4894 height = get_current_font_height(hwnd);
4895 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
4896 DestroyWindow(hwnd);
4897 }
4898
4899 static void test_scrollnotify(void)
4900 {
4901 HWND hwnd;
4902 DWORD ret;
4903
4904 hwnd = create_listview_control(LVS_REPORT);
4905
4906 insert_column(hwnd, 0);
4907 insert_column(hwnd, 1);
4908 insert_item(hwnd, 0);
4909
4910 /* make it scrollable - resize */
4911 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4912 expect(TRUE, ret);
4913 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4914 expect(TRUE, ret);
4915
4916 /* try with dummy call */
4917 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4918 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
4919 expect(TRUE, ret);
4920 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4921 "scroll notify 1", TRUE);
4922
4923 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4924 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
4925 expect(TRUE, ret);
4926 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4927 "scroll notify 2", TRUE);
4928
4929 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4930 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
4931 expect(TRUE, ret);
4932 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4933 "scroll notify 3", TRUE);
4934
4935 DestroyWindow(hwnd);
4936 }
4937
4938 static void test_LVS_EX_TRANSPARENTBKGND(void)
4939 {
4940 HWND hwnd;
4941 DWORD ret;
4942 HDC hdc;
4943
4944 hwnd = create_listview_control(LVS_REPORT);
4945
4946 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4947 expect(TRUE, ret);
4948
4949 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4950 LVS_EX_TRANSPARENTBKGND);
4951
4952 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
4953 if (ret != CLR_NONE)
4954 {
4955 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4956 DestroyWindow(hwnd);
4957 return;
4958 }
4959
4960 /* try to set some back color and check this style bit */
4961 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4962 expect(TRUE, ret);
4963 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4964 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4965
4966 /* now test what this style actually does */
4967 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4968 LVS_EX_TRANSPARENTBKGND);
4969
4970 hdc = GetWindowDC(hwndparent);
4971
4972 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4973 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4974 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4975 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4976
4977 ReleaseDC(hwndparent, hdc);
4978
4979 DestroyWindow(hwnd);
4980 }
4981
4982 static void test_approximate_viewrect(void)
4983 {
4984 HWND hwnd;
4985 DWORD ret;
4986 HIMAGELIST himl;
4987 HBITMAP hbmp;
4988 LVITEMA itema;
4989 static CHAR test[] = "abracadabra, a very long item label";
4990
4991 hwnd = create_listview_control(LVS_ICON);
4992 himl = ImageList_Create(40, 40, 0, 4, 4);
4993 ok(himl != NULL, "failed to create imagelist\n");
4994 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4995 ok(hbmp != NULL, "failed to create bitmap\n");
4996 ret = ImageList_Add(himl, hbmp, 0);
4997 expect(0, ret);
4998 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4999 expect(0, ret);
5000
5001 itema.mask = LVIF_IMAGE;
5002 itema.iImage = 0;
5003 itema.iItem = 0;
5004 itema.iSubItem = 0;
5005 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5006 expect(0, ret);
5007
5008 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
5009 if (ret == 0)
5010 {
5011 /* version 4.0 */
5012 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
5013 return;
5014 }
5015
5016 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5017 expect(MAKELONG(77,827), ret);
5018
5019 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5020 ok(ret != 0, "got 0\n");
5021
5022 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5023 expect(MAKELONG(102,302), ret);
5024
5025 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5026 expect(MAKELONG(52,52), ret);
5027
5028 itema.pszText = test;
5029 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5030 expect(TRUE, ret);
5031 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5032 expect(MAKELONG(52,52), ret);
5033
5034 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5035 expect(MAKELONG(52,2), ret);
5036 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5037 expect(MAKELONG(52,52), ret);
5038 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5039 expect(MAKELONG(102,52), ret);
5040 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5041 expect(MAKELONG(102,102), ret);
5042 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5043 expect(MAKELONG(102,102), ret);
5044 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5045 expect(MAKELONG(102,152), ret);
5046 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5047 expect(MAKELONG(102,152), ret);
5048 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5049 expect(MAKELONG(152,152), ret);
5050
5051 DestroyWindow(hwnd);
5052 }
5053
5054 static void test_finditem(void)
5055 {
5056 LVFINDINFOA fi;
5057 static char f[5];
5058 HWND hwnd;
5059 INT r;
5060
5061 hwnd = create_listview_control(LVS_REPORT);
5062 insert_item(hwnd, 0);
5063
5064 memset(&fi, 0, sizeof(fi));
5065
5066 /* full string search, inserted text was "foo" */
5067 strcpy(f, "foo");
5068 fi.flags = LVFI_STRING;
5069 fi.psz = f;
5070 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5071 expect(0, r);
5072 /* partial string search, inserted text was "foo" */
5073 strcpy(f, "fo");
5074 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5075 fi.psz = f;
5076 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5077 expect(0, r);
5078 /* partial string search, part after start char */
5079 strcpy(f, "oo");
5080 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5081 fi.psz = f;
5082 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5083 expect(-1, r);
5084
5085 /* try with LVFI_SUBSTRING */
5086 strcpy(f, "fo");
5087 fi.flags = LVFI_SUBSTRING;
5088 fi.psz = f;
5089 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5090 if (r == -1)
5091 {
5092 win_skip("LVFI_SUBSTRING not supported\n");
5093 DestroyWindow(hwnd);
5094 return;
5095 }
5096 expect(0, r);
5097 strcpy(f, "f");
5098 fi.flags = LVFI_SUBSTRING;
5099 fi.psz = f;
5100 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5101 expect(0, r);
5102 strcpy(f, "o");
5103 fi.flags = LVFI_SUBSTRING;
5104 fi.psz = f;
5105 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5106 expect(-1, r);
5107
5108 strcpy(f, "f");
5109 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5110 fi.psz = f;
5111 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5112 expect(0, r);
5113
5114 DestroyWindow(hwnd);
5115 }
5116
5117 static void test_LVS_EX_HEADERINALLVIEWS(void)
5118 {
5119 HWND hwnd, header;
5120 DWORD style;
5121
5122 hwnd = create_listview_control(LVS_ICON);
5123
5124 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5125 LVS_EX_HEADERINALLVIEWS);
5126
5127 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5128 if (!IsWindow(header))
5129 {
5130 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5131 DestroyWindow(hwnd);
5132 return;
5133 }
5134
5135 /* LVS_NOCOLUMNHEADER works as before */
5136 style = GetWindowLongA(hwnd, GWL_STYLE);
5137 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5138 style = GetWindowLongA(header, GWL_STYLE);
5139 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5140 style = GetWindowLongA(hwnd, GWL_STYLE);
5141 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5142 style = GetWindowLongA(header, GWL_STYLE);
5143 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5144
5145 /* try to remove style */
5146 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5147 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5148 ok(IsWindow(header), "Expected header to be created\n");
5149 style = GetWindowLongA(header, GWL_STYLE);
5150 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5151
5152 DestroyWindow(hwnd);
5153
5154 /* check other styles */
5155 hwnd = create_listview_control(LVS_LIST);
5156 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5157 LVS_EX_HEADERINALLVIEWS);
5158 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5159 ok(IsWindow(header), "Expected header to be created\n");
5160 DestroyWindow(hwnd);
5161
5162 hwnd = create_listview_control(LVS_SMALLICON);
5163 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5164 LVS_EX_HEADERINALLVIEWS);
5165 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5166 ok(IsWindow(header), "Expected header to be created\n");
5167 DestroyWindow(hwnd);
5168
5169 hwnd = create_listview_control(LVS_REPORT);
5170 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5171 LVS_EX_HEADERINALLVIEWS);
5172 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5173 ok(IsWindow(header), "Expected header to be created\n");
5174 DestroyWindow(hwnd);
5175 }
5176
5177 static void test_hover(void)
5178 {
5179 HWND hwnd, fg;
5180 DWORD r;
5181
5182 hwnd = create_listview_control(LVS_ICON);
5183 SetForegroundWindow(hwndparent);
5184 fg = GetForegroundWindow();
5185 if (fg != hwndparent)
5186 {
5187 skip("Window is not in the foreground. Skipping hover tests.\n");
5188 DestroyWindow(hwnd);
5189 return;
5190 }
5191
5192 /* test WM_MOUSEHOVER forwarding */
5193 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5194 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5195 expect(0, r);
5196 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5197 g_block_hover = TRUE;
5198 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5199 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5200 expect(0, r);
5201 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5202 g_block_hover = FALSE;
5203
5204 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5205 expect(HOVER_DEFAULT, r);
5206 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5207 expect(500, r);
5208
5209 DestroyWindow(hwnd);
5210 }
5211
5212 static void test_destroynotify(void)
5213 {
5214 HWND hwnd;
5215 BOOL ret;
5216
5217 hwnd = create_listview_control(LVS_REPORT);
5218 ok(hwnd != NULL, "failed to create listview window\n");
5219
5220 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5221 DestroyWindow(hwnd);
5222 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5223
5224 /* same for ownerdata list */
5225 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5226 ok(hwnd != NULL, "failed to create listview window\n");
5227
5228 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5229 DestroyWindow(hwnd);
5230 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5231
5232 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5233 ok(hwnd != NULL, "failed to create listview window\n");
5234
5235 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5236 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5237 ok(ret == TRUE, "got %d\n", ret);
5238 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5239 DestroyWindow(hwnd);
5240 }
5241
5242 static void test_header_notification(void)
5243 {
5244 static char textA[] = "newtext";
5245 HWND list, header;
5246 HDITEMA item;
5247 NMHEADERA nmh;
5248 LVCOLUMNA col;
5249 DWORD ret;
5250 BOOL r;
5251
5252 list = create_listview_control(LVS_REPORT);
5253 ok(list != NULL, "failed to create listview window\n");
5254
5255 memset(&col, 0, sizeof(col));
5256 col.mask = LVCF_WIDTH;
5257 col.cx = 100;
5258 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5259 expect(0, ret);
5260
5261 /* check list parent notification after header item changed,
5262 this test should be placed before header subclassing to avoid
5263 Listview -> Header messages to be logged */
5264 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5265
5266 col.mask = LVCF_TEXT;
5267 col.pszText = textA;
5268 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5269 expect(TRUE, r);
5270
5271 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5272 "header notify, listview", FALSE);
5273 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5274 "header notify, parent", FALSE);
5275
5276 header = subclass_header(list);
5277
5278 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5279 expect(1, ret);
5280
5281 memset(&item, 0, sizeof(item));
5282 item.mask = HDI_WIDTH;
5283 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5284 expect(1, ret);
5285 expect(100, item.cxy);
5286
5287 nmh.hdr.hwndFrom = header;
5288 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5289 nmh.hdr.code = HDN_ITEMCHANGEDA;
5290 nmh.iItem = 0;
5291 nmh.iButton = 0;
5292 item.mask = HDI_WIDTH;
5293 item.cxy = 50;
5294 nmh.pitem = &item;
5295 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5296 expect(0, ret);
5297
5298 DestroyWindow(list);
5299 }
5300
5301 static void test_header_notification2(void)
5302 {
5303 static char textA[] = "newtext";
5304 HWND list, header;
5305 HDITEMW itemW;
5306 NMHEADERW nmhdr;
5307 LVCOLUMNA col;
5308 DWORD ret;
5309 WCHAR buffer[100];
5310 struct message parent_header_notify_seq[] = {
5311 { WM_NOTIFY, sent|id, 0, 0, 0 },
5312 { 0 }
5313 };
5314
5315 list = create_listview_control(LVS_REPORT);
5316 ok(list != NULL, "failed to create listview window\n");
5317
5318 memset(&col, 0, sizeof(col));
5319 col.mask = LVCF_WIDTH | LVCF_TEXT;
5320 col.cx = 100;
5321 col.pszText = textA;
5322 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5323 expect(0, ret);
5324
5325 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5326 ok(header != 0, "No header\n");
5327 memset(&itemW, 0, sizeof(itemW));
5328 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5329 itemW.pszText = buffer;
5330 itemW.cchTextMax = sizeof(buffer);
5331 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5332 expect(1, ret);
5333
5334 nmhdr.hdr.hwndFrom = header;
5335 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5336 nmhdr.iItem = 0;
5337 nmhdr.iButton = 0;
5338 nmhdr.pitem = &itemW;
5339
5340 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5341 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5342 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5343 ok(ret == 0, "got %d\n", ret);
5344 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5345 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5346 "header notify, parent", TRUE);
5347 todo_wine
5348 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5349 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5350 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5351 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5352 ok(ret == 0, "got %d\n", ret);
5353 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5354 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5355 "header notify, parent", TRUE);
5356 todo_wine
5357 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5358 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5359 SetFocus(list);
5360 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5361 nmhdr.hdr.code = HDN_ITEMCLICKW;
5362 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5363 ok(ret == 0, "got %d\n", ret);
5364 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5365 "header notify, parent", FALSE);
5366 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5368 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5369 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5370 ok(ret == 0, "got %d\n", ret);
5371 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5372 "header notify, parent", FALSE);
5373 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5374 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5375 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5376 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5377 ok(ret == 0, "got %d\n", ret);
5378 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5379 "header notify, parent", TRUE);
5380 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5381 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5382 nmhdr.hdr.code = HDN_BEGINTRACKW;
5383 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5384 ok(ret == 0, "got %d\n", ret);
5385 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5386 "header notify, parent", FALSE);
5387 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5388 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5389 nmhdr.hdr.code = HDN_ENDTRACKW;
5390 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5391 ok(ret == 0, "got %d\n", ret);
5392 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5393 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5394 "header notify, parent", FALSE);
5395 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5396 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5397 nmhdr.hdr.code = HDN_TRACKW;
5398 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5399 ok(ret == 0, "got %d\n", ret);
5400 parent_header_notify_seq[0].id = HDN_TRACKA;
5401 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5402 "header notify, parent", FALSE);
5403 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5404 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5405 nmhdr.hdr.code = HDN_BEGINDRAG;
5406 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5407 ok(ret == 1, "got %d\n", ret);
5408 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5409 "header notify, parent", FALSE);
5410 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5411 nmhdr.hdr.code = HDN_ENDDRAG;
5412 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5413 ok(ret == 0, "got %d\n", ret);
5414 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5415 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5416 "header notify, parent", FALSE);
5417 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5418 nmhdr.hdr.code = HDN_FILTERCHANGE;
5419 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5420 ok(ret == 0, "got %d\n", ret);
5421 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5422 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5423 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5424 "header notify, parent", FALSE);
5425 parent_header_notify_seq[0].flags &= ~optional;
5426 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5427 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5428 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5429 ok(ret == 0, "got %d\n", ret);
5430 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5431 "header notify, parent", FALSE);
5432 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5433 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5434 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5435 ok(ret == 0, "got %d\n", ret);
5436 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5437 "header notify, parent", FALSE);
5438 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5439 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5440 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5441 ok(ret == 0, "got %d\n", ret);
5442 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5443 "header notify, parent", FALSE);
5444 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5445 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5446 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5447 ok(ret == 0, "got %d\n", ret);
5448 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5449 "header notify, parent", FALSE);
5450
5451 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5452
5453 DestroyWindow(list);
5454 }
5455
5456 static void test_createdragimage(void)
5457 {
5458 HIMAGELIST himl;
5459 POINT pt;
5460 HWND list;
5461
5462 list = create_listview_control(LVS_ICON);
5463 ok(list != NULL, "failed to create listview window\n");
5464
5465 insert_item(list, 0);
5466
5467 /* NULL point */
5468 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5469 ok(himl == NULL, "got %p\n", himl);
5470
5471 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5472 ok(himl != NULL, "got %p\n", himl);
5473 ImageList_Destroy(himl);
5474
5475 DestroyWindow(list);
5476 }
5477
5478 static void test_dispinfo(void)
5479 {
5480 static const char testA[] = "TEST";
5481 WCHAR buff[10];
5482 LVITEMA item;
5483 HWND hwnd;
5484 DWORD ret;
5485
5486 hwnd = create_listview_control(LVS_ICON);
5487 ok(hwnd != NULL, "failed to create listview window\n");
5488
5489 insert_item(hwnd, 0);
5490
5491 memset(&item, 0, sizeof(item));
5492 item.pszText = LPSTR_TEXTCALLBACKA;
5493 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5494 expect(1, ret);
5495
5496 g_disp_A_to_W = TRUE;
5497 item.pszText = (char*)buff;
5498 item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
5499 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5500 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5501 g_disp_A_to_W = FALSE;
5502
5503 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5504 "got %s, expected %s\n", item.pszText, testA);
5505
5506 DestroyWindow(hwnd);
5507 }
5508
5509 static void test_LVM_SETITEMTEXT(void)
5510 {
5511 static char testA[] = "TEST";
5512 LVITEMA item;
5513 HWND hwnd;
5514 DWORD ret;
5515
5516 hwnd = create_listview_control(LVS_ICON);
5517 ok(hwnd != NULL, "failed to create listview window\n");
5518
5519 insert_item(hwnd, 0);
5520
5521 /* null item pointer */
5522 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5523 expect(FALSE, ret);
5524
5525 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5526 expect(FALSE, ret);
5527
5528 /* index out of bounds */
5529 item.pszText = testA;
5530 item.cchTextMax = 0; /* ignored */
5531 item.iSubItem = 0;
5532
5533 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5534 expect(FALSE, ret);
5535
5536 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5537 expect(FALSE, ret);
5538
5539 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5540 expect(TRUE, ret);
5541
5542 DestroyWindow(hwnd);
5543 }
5544
5545 static void test_imagelists(void)
5546 {
5547 HWND hwnd, header;
5548 HIMAGELIST himl1, himl2, himl3;
5549 LRESULT ret;
5550
5551 himl1 = ImageList_Create(40, 40, 0, 4, 4);
5552 himl2 = ImageList_Create(40, 40, 0, 4, 4);
5553 himl3 = ImageList_Create(40, 40, 0, 4, 4);
5554 ok(himl1 != NULL, "Failed to create imagelist\n");
5555 ok(himl2 != NULL, "Failed to create imagelist\n");
5556 ok(himl3 != NULL, "Failed to create imagelist\n");
5557
5558 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5559 header = subclass_header(hwnd);
5560
5561 ok(header != NULL, "Expected header\n");
5562 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5563 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5564
5565 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5566
5567 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5568 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5569 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5570 "set normal image list", FALSE);
5571
5572 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5573
5574 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5575 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5576 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5577 "set state image list", TRUE);
5578
5579 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5580 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5581
5582 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5583
5584 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5585 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5586 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5587 "set small image list", FALSE);
5588
5589 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5590 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5591 DestroyWindow(hwnd);
5592
5593 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5594
5595 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5596
5597 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5598 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5599 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5600 "set normal image list", FALSE);
5601
5602 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5603
5604 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5605 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5606 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5607 "set state image list", FALSE);
5608
5609 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5610
5611 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5612 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5613 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5614 "set small image list", FALSE);
5615
5616 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5617 ok(header == NULL, "Expected no header, got %p\n", header);
5618
5619 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
5620
5621 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5622 ok(header != NULL, "Expected header, got NULL\n");
5623
5624 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5625 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5626
5627 DestroyWindow(hwnd);
5628 }
5629
5630 static void test_deleteitem(void)
5631 {
5632 LVITEMA item;
5633 UINT state;
5634 HWND hwnd;
5635 BOOL ret;
5636
5637 hwnd = create_listview_control(LVS_REPORT);
5638
5639 insert_item(hwnd, 0);
5640 insert_item(hwnd, 0);
5641 insert_item(hwnd, 0);
5642 insert_item(hwnd, 0);
5643 insert_item(hwnd, 0);
5644
5645 g_focus_test_LVN_DELETEITEM = TRUE;
5646
5647 /* delete focused item (not the last index) */
5648 item.stateMask = LVIS_FOCUSED;
5649 item.state = LVIS_FOCUSED;
5650 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5651 ok(ret == TRUE, "got %d\n", ret);
5652 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5653 ok(ret == TRUE, "got %d\n", ret);
5654 /* next item gets focus */
5655 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5656 ok(state == LVIS_FOCUSED, "got %x\n", state);
5657
5658 /* focus last item and delete it */
5659 item.stateMask = LVIS_FOCUSED;
5660 item.state = LVIS_FOCUSED;
5661 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5662 ok(ret == TRUE, "got %d\n", ret);
5663 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5664 ok(ret == TRUE, "got %d\n", ret);
5665 /* new last item gets focus */
5666 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5667 ok(state == LVIS_FOCUSED, "got %x\n", state);
5668
5669 /* focus first item and delete it */
5670 item.stateMask = LVIS_FOCUSED;
5671 item.state = LVIS_FOCUSED;
5672 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5673 ok(ret == TRUE, "got %d\n", ret);
5674 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5675 ok(ret == TRUE, "got %d\n", ret);
5676 /* new first item gets focus */
5677 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5678 ok(state == LVIS_FOCUSED, "got %x\n", state);
5679
5680 g_focus_test_LVN_DELETEITEM = FALSE;
5681
5682 DestroyWindow(hwnd);
5683 }
5684
5685 static void test_insertitem(void)
5686 {
5687 LVITEMA item;
5688 UINT state;
5689 HWND hwnd;
5690 INT ret;
5691
5692 hwnd = create_listview_control(LVS_REPORT);
5693
5694 /* insert item 0 focused */
5695 item.mask = LVIF_STATE;
5696 item.state = LVIS_FOCUSED;
5697 item.stateMask = LVIS_FOCUSED;
5698 item.iItem = 0;
5699 item.iSubItem = 0;
5700 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5701 ok(ret == 0, "got %d\n", ret);
5702
5703 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5704 ok(state == LVIS_FOCUSED, "got %x\n", state);
5705
5706 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5707
5708 /* insert item 1, focus shift */
5709 item.mask = LVIF_STATE;
5710 item.state = LVIS_FOCUSED;
5711 item.stateMask = LVIS_FOCUSED;
5712 item.iItem = 1;
5713 item.iSubItem = 0;
5714 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5715 ok(ret == 1, "got %d\n", ret);
5716
5717 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5718
5719 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5720 ok(state == LVIS_FOCUSED, "got %x\n", state);
5721
5722 /* insert item 2, no focus shift */
5723 item.mask = LVIF_STATE;
5724 item.state = 0;
5725 item.stateMask = LVIS_FOCUSED;
5726 item.iItem = 2;
5727 item.iSubItem = 0;
5728 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5729 ok(ret == 2, "got %d\n", ret);
5730
5731 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5732 ok(state == LVIS_FOCUSED, "got %x\n", state);
5733
5734 DestroyWindow(hwnd);
5735 }
5736
5737 static void test_header_proc(void)
5738 {
5739 HWND hwnd, header, hdr;
5740 WNDPROC proc1, proc2;
5741
5742 hwnd = create_listview_control(LVS_REPORT);
5743
5744 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5745 ok(header != NULL, "got %p\n", header);
5746
5747 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
5748 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
5749 0, 0, 0, 0,
5750 NULL, NULL, NULL, NULL);
5751 ok(hdr != NULL, "got %p\n", hdr);
5752
5753 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
5754 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
5755 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
5756
5757 DestroyWindow(hdr);
5758 DestroyWindow(hwnd);
5759 }
5760
5761 static void flush_events(void)
5762 {
5763 MSG msg;
5764 int diff = 200;
5765 int min_timeout = 100;
5766 DWORD time = GetTickCount() + diff;
5767
5768 while (diff > 0)
5769 {
5770 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
5771 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
5772 diff = time - GetTickCount();
5773 }
5774 }
5775
5776 static void test_oneclickactivate(void)
5777 {
5778 TRACKMOUSEEVENT track;
5779 char item1[] = "item1";
5780 LVITEMA item;
5781 HWND hwnd, fg;
5782 RECT rect;
5783 INT r;
5784
5785 hwnd = CreateWindowExA(0, "SysListView32", "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
5786 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
5787 ok(hwnd != NULL, "failed to create listview window\n");
5788 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
5789 ok(r == 0, "should return zero\n");
5790
5791 SetForegroundWindow(hwndparent);
5792 flush_events();
5793 fg = GetForegroundWindow();
5794 if (fg != hwndparent)
5795 {
5796 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
5797 DestroyWindow(hwnd);
5798 return;
5799 }
5800
5801 item.mask = LVIF_TEXT;
5802 item.iItem = 0;
5803 item.iSubItem = 0;
5804 item.iImage = 0;
5805 item.pszText = item1;
5806 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
5807 ok(r == 0, "should not fail\n");
5808
5809 GetWindowRect(hwnd, &rect);
5810 SetCursorPos(rect.left+5, rect.top+5);
5811 flush_events();
5812 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
5813 expect(0, r);
5814
5815 track.cbSize = sizeof(track);
5816 track.dwFlags = TME_QUERY;
5817 _TrackMouseEvent(&track);
5818 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
5819 ok(track.dwFlags == TME_LEAVE, "dwFlags = %x\n", track.dwFlags);
5820
5821 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5822 expect(0, r);
5823 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
5824 expect(0, r);
5825 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5826 expect(1, r);
5827
5828 DestroyWindow(hwnd);
5829 }
5830
5831 START_TEST(listview)
5832 {
5833 HMODULE hComctl32;
5834 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
5835
5836 ULONG_PTR ctx_cookie;
5837 HANDLE hCtx;
5838
5839 hComctl32 = GetModuleHandleA("comctl32.dll");
5840 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
5841 if (pInitCommonControlsEx)
5842 {
5843 INITCOMMONCONTROLSEX iccex;
5844 iccex.dwSize = sizeof(iccex);
5845 iccex.dwICC = ICC_LISTVIEW_CLASSES;
5846 pInitCommonControlsEx(&iccex);
5847 }
5848 else
5849 InitCommonControls();
5850
5851 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
5852
5853 hwndparent = create_parent_window(FALSE);
5854 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5855
5856 g_is_below_5 = is_below_comctl_5();
5857
5858 test_header_notification();
5859 test_header_notification2();
5860 test_images();
5861 test_checkboxes();
5862 test_items();
5863 test_create();
5864 test_redraw();
5865 test_customdraw();
5866 test_icon_spacing();
5867 test_color();
5868 test_item_count();
5869 test_item_position();
5870 test_columns();
5871 test_getorigin();
5872 test_multiselect();
5873 test_getitemrect();
5874 test_subitem_rect();
5875 test_sorting();
5876 test_ownerdata();
5877 test_norecompute();
5878 test_nosortheader();
5879 test_setredraw();
5880 test_hittest();
5881 test_getviewrect();
5882 test_getitemposition();
5883 test_columnscreation();
5884 test_editbox();
5885 test_notifyformat();
5886 test_indentation();
5887 test_getitemspacing();
5888 test_getcolumnwidth();
5889 test_approximate_viewrect();
5890 test_finditem();
5891 test_hover();
5892 test_destroynotify();
5893 test_createdragimage();
5894 test_dispinfo();
5895 test_LVM_SETITEMTEXT();
5896 test_imagelists();
5897 test_deleteitem();
5898 test_insertitem();
5899 test_header_proc();
5900 test_oneclickactivate();
5901
5902 if (!load_v6_module(&ctx_cookie, &hCtx))
5903 {
5904 DestroyWindow(hwndparent);
5905 return;
5906 }
5907
5908 /* comctl32 version 6 tests start here */
5909 test_get_set_view();
5910 test_canceleditlabel();
5911 test_mapidindex();
5912 test_scrollnotify();
5913 test_LVS_EX_TRANSPARENTBKGND();
5914 test_LVS_EX_HEADERINALLVIEWS();
5915 test_deleteitem();
5916 test_multiselect();
5917 test_insertitem();
5918 test_header_proc();
5919
5920 unload_v6_module(ctx_cookie, hCtx);
5921
5922 DestroyWindow(hwndparent);
5923 }