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