listview.c 246 KB
Newer Older
1 2 3 4
/*
 * ListView tests
 *
 * Copyright 2006 Mike McCormack for CodeWeavers
5
 * Copyright 2007 George Gov
6
 * Copyright 2009-2014 Nikolay Sivov
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
26
#include <objbase.h>
27 28

#include "wine/test.h"
29
#include "v6util.h"
30 31
#include "msg.h"

32 33 34 35 36
static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
static BOOL (WINAPI *p_TrackMouseEvent)(TRACKMOUSEEVENT *);

37 38 39 40
enum seq_index {
    PARENT_SEQ_INDEX,
    PARENT_FULL_SEQ_INDEX,
    PARENT_CD_SEQ_INDEX,
41
    PARENT_ODSTATECHANGED_SEQ_INDEX,
42 43 44 45 46
    LISTVIEW_SEQ_INDEX,
    EDITBOX_SEQ_INDEX,
    COMBINED_SEQ_INDEX,
    NUM_MSG_SEQUENCES
};
47 48 49 50

#define LISTVIEW_ID 0
#define HEADER_ID   1

51 52 53
#define expect(expected,got) expect_(__LINE__, expected, got)
static inline void expect_(unsigned line, DWORD expected, DWORD got)
{
54
    ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got);
55 56 57 58 59 60
}

#define expect2(expected1, expected2, got1, got2) expect2_(__LINE__, expected1, expected2, got1, got2)
static inline void expect2_(unsigned line, DWORD expected1, DWORD expected2, DWORD got1, DWORD got2)
{
    ok_(__FILE__, line)(expected1 == got1 && expected2 == got2,
61
                        "expected (%ld,%ld), got (%ld,%ld)\n",
62 63
                        expected1, expected2, got1, got2);
}
64

65
static HWND hwndparent, hwndparentW;
66
/* prevents edit box creation, LVN_BEGINLABELEDIT return value */
67 68 69
static BOOL blockEdit;
/* return nonzero on NM_HOVER */
static BOOL g_block_hover;
70 71
/* notification data for LVN_ITEMCHANGED */
static NMLISTVIEW g_nmlistview;
72 73
/* notification data for LVN_ITEMCHANGING */
static NMLISTVIEW g_nmlistview_changing;
74 75
/* format reported to control:
   -1 falls to defproc, anything else returned */
76
static INT notifyFormat;
77 78
/* item data passed to LVN_GETDISPINFOA */
static LVITEMA g_itema;
79 80
/* alter notification code A->W */
static BOOL g_disp_A_to_W;
81
/* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
82
static NMLVDISPINFOA g_editbox_disp_info;
83 84
/* when this is set focus will be tested on LVN_DELETEITEM */
static BOOL g_focus_test_LVN_DELETEITEM;
85 86
/* Whether to send WM_KILLFOCUS to the edit control during LVN_ENDLABELEDIT */
static BOOL g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT;
87

88
static HWND subclass_editbox(HWND hwndListview);
89

90 91 92 93 94 95 96 97 98 99 100 101
static void init_functions(void)
{
    HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");

#define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
    X(ImageList_Create);
    X(ImageList_Destroy);
    X(ImageList_Add);
    X(_TrackMouseEvent);
#undef X
}

102 103
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];

104 105 106 107 108 109 110 111
static const struct message create_ownerdrawfixed_parent_seq[] = {
    { WM_NOTIFYFORMAT, sent },
    { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
    { WM_MEASUREITEM, sent },
    { WM_PARENTNOTIFY, sent },
    { 0 }
};

112 113 114 115
static const struct message redraw_listview_seq[] = {
    { WM_PAINT,      sent|id,            0, 0, LISTVIEW_ID },
    { WM_PAINT,      sent|id,            0, 0, HEADER_ID },
    { WM_NCPAINT,    sent|id|defwinproc, 0, 0, HEADER_ID },
116
    { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
117 118
    { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
    { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_ID },
119
    { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
120 121 122
    { 0 }
};

123
static const struct message listview_icon_spacing_seq[] = {
124 125 126
    { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
    { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
    { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    { 0 }
};

static const struct message listview_color_seq[] = {
    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(0,0,0) },
    { LVM_GETBKCOLOR,     sent },
    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(0,0,0) },
    { LVM_GETTEXTCOLOR,   sent },
    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
    { LVM_GETTEXTBKCOLOR, sent },

    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(100,50,200) },
    { LVM_GETBKCOLOR,     sent },
    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(100,50,200) },
    { LVM_GETTEXTCOLOR,   sent },
    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
    { LVM_GETTEXTBKCOLOR, sent },

    { LVM_SETBKCOLOR,     sent|lparam, 0, CLR_NONE },
    { LVM_GETBKCOLOR,     sent },
    { LVM_SETTEXTCOLOR,   sent|lparam, 0, CLR_NONE },
    { LVM_GETTEXTCOLOR,   sent },
    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
    { LVM_GETTEXTBKCOLOR, sent },

    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(255,255,255) },
    { LVM_GETBKCOLOR,     sent },
    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(255,255,255) },
    { LVM_GETTEXTCOLOR,   sent },
    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
    { LVM_GETTEXTBKCOLOR, sent },
    { 0 }
};

static const struct message listview_item_count_seq[] = {
    { LVM_GETITEMCOUNT,   sent },
163 164 165
    { LVM_INSERTITEMA,    sent },
    { LVM_INSERTITEMA,    sent },
    { LVM_INSERTITEMA,    sent },
166 167
    { LVM_GETITEMCOUNT,   sent },
    { LVM_DELETEITEM,     sent|wparam, 2 },
168 169
    { WM_NCPAINT,         sent|optional },
    { WM_ERASEBKGND,      sent|optional },
170 171 172
    { LVM_GETITEMCOUNT,   sent },
    { LVM_DELETEALLITEMS, sent },
    { LVM_GETITEMCOUNT,   sent },
173 174
    { LVM_INSERTITEMA,    sent },
    { LVM_INSERTITEMA,    sent },
175
    { LVM_GETITEMCOUNT,   sent },
176
    { LVM_INSERTITEMA,    sent },
177 178 179 180 181
    { LVM_GETITEMCOUNT,   sent },
    { 0 }
};

static const struct message listview_itempos_seq[] = {
182 183 184
    { LVM_INSERTITEMA,     sent },
    { LVM_INSERTITEMA,     sent },
    { LVM_INSERTITEMA,     sent },
185
    { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
186 187
    { WM_NCPAINT,          sent|optional },
    { WM_ERASEBKGND,       sent|optional },
188 189 190 191 192 193 194 195
    { LVM_GETITEMPOSITION, sent|wparam,        1 },
    { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
    { LVM_GETITEMPOSITION, sent|wparam,        2 },
    { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
    { LVM_GETITEMPOSITION, sent|wparam,        0 },
    { 0 }
};

196 197 198 199 200 201
static const struct message listview_ownerdata_switchto_seq[] = {
    { WM_STYLECHANGING,    sent },
    { WM_STYLECHANGED,     sent },
    { 0 }
};

202 203 204
static const struct message listview_getorderarray_seq[] = {
    { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
    { HDM_GETORDERARRAY,       sent|id|wparam, 2, 0, HEADER_ID },
205 206
    { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
    { HDM_GETORDERARRAY,       sent|id|wparam, 0, 0, HEADER_ID },
207 208 209
    { 0 }
};

210 211 212 213 214 215 216 217
static const struct message listview_setorderarray_seq[] = {
    { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
    { HDM_SETORDERARRAY,       sent|id|wparam, 2, 0, HEADER_ID },
    { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
    { HDM_SETORDERARRAY,       sent|id|wparam, 0, 0, HEADER_ID },
    { 0 }
};

218 219 220 221
static const struct message empty_seq[] = {
    { 0 }
};

222 223 224 225 226 227
static const struct message parent_focus_change_ownerdata_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
    { 0 }
};

228 229 230 231 232
static const struct message forward_erasebkgnd_parent_seq[] = {
    { WM_ERASEBKGND, sent },
    { 0 }
};

233
static const struct message ownerdata_select_focus_parent_seq[] = {
234 235
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
236
    { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
237 238 239
    { 0 }
};

240 241 242 243 244 245 246 247
static const struct message ownerdata_setstate_all_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_defocus_all_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
248
    { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
249 250 251 252 253 254
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_deselect_all_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
255 256 257 258
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

259 260
static const struct message ownerdata_multiselect_select_0_to_1_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
261
    { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
    { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_0_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_0_modkey_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_move_0_to_1_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_0_to_2_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_3_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_3_modkey_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_3_to_2_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
    { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_move_3_to_2_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { 0 }
};

static const struct message ownerdata_multiselect_select_3_to_1_odstatechanged_seq[] = {
    { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
    { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
330 331 332
    { 0 }
};

333
static const struct message change_all_parent_seq[] = {
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },

    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },

    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },

    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },

    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
    { 0 }
};

351 352 353 354 355 356 357 358 359
static const struct message changing_all_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { 0 }
};

360 361 362 363 364 365
static const struct message textcallback_set_again_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED  },
    { 0 }
};

366 367 368 369 370
static const struct message single_getdispinfo_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
    { 0 }
};

371 372 373 374 375 376 377 378 379 380 381
static const struct message getitemposition_seq1[] = {
    { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
    { 0 }
};

static const struct message getitemposition_seq2[] = {
    { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
    { 0 }
};

382 383 384 385 386 387 388 389 390 391 392 393
static const struct message getsubitemrect_seq[] = {
    { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
    { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
    { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
    { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
    { 0 }
};

394 395
static const struct message editbox_create_pos[] = {
    /* sequence sent after LVN_BEGINLABELEDIT */
396
    /* next two are 4.7x specific */
397
    { WM_WINDOWPOSCHANGING, sent },
398 399 400
    { WM_WINDOWPOSCHANGED, sent|optional },

    { WM_WINDOWPOSCHANGING, sent|optional },
401 402 403 404
    { WM_NCCALCSIZE, sent },
    { WM_WINDOWPOSCHANGED, sent },
    { WM_MOVE, sent|defwinproc },
    { WM_SIZE, sent|defwinproc },
405 406 407
    /* the rest is todo, skipped in 4.7x */
    { WM_WINDOWPOSCHANGING, sent|optional },
    { WM_WINDOWPOSCHANGED, sent|optional },
408 409 410
    { 0 }
};

411 412 413 414 415 416
static const struct message scroll_parent_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
    { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
    { 0 }
};

417 418 419 420 421
static const struct message setredraw_seq[] = {
    { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
    { 0 }
};

422 423 424 425 426
static const struct message lvs_ex_transparentbkgnd_seq[] = {
    { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
    { 0 }
};

427
static const struct message edit_end_nochange[] = {
428
    { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
429 430 431 432 433
    { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },     /* todo */
    { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
    { 0 }
};

434 435 436 437 438 439
static const struct message hover_parent[] = {
    { WM_GETDLGCODE, sent }, /* todo_wine */
    { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
    { 0 }
};

440 441 442 443 444 445 446 447 448 449 450 451
static const struct message listview_destroy[] = {
    { 0x0090, sent|optional }, /* Vista */
    { WM_PARENTNOTIFY, sent },
    { WM_SHOWWINDOW, sent },
    { WM_WINDOWPOSCHANGING, sent },
    { WM_WINDOWPOSCHANGED, sent|optional },
    { WM_DESTROY, sent },
    { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
    { WM_NCDESTROY, sent },
    { 0 }
};

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
static const struct message listview_ownerdata_destroy[] = {
    { 0x0090, sent|optional }, /* Vista */
    { WM_PARENTNOTIFY, sent },
    { WM_SHOWWINDOW, sent },
    { WM_WINDOWPOSCHANGING, sent },
    { WM_WINDOWPOSCHANGED, sent|optional },
    { WM_DESTROY, sent },
    { WM_NCDESTROY, sent },
    { 0 }
};

static const struct message listview_ownerdata_deleteall[] = {
    { LVM_DELETEALLITEMS, sent },
    { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
    { 0 }
};

469 470 471 472 473 474 475
static const struct message listview_header_changed_seq[] = {
    { LVM_SETCOLUMNA, sent },
    { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
    { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
    { 0 }
};

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
static const struct message parent_header_click_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
    { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
    { 0 }
};

static const struct message parent_header_divider_dclick_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
    { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
    { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
    { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
    { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
    { 0 }
};

491 492 493 494 495 496 497 498 499 500 501
static const struct message listview_set_imagelist[] = {
    { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
    { 0 }
};

static const struct message listview_header_set_imagelist[] = {
    { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
    { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
    { 0 }
};

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
static const struct message parent_report_cd_seq[] = {
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
    { 0 }
};

static const struct message parent_list_cd_seq[] = {
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
    { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
    { 0 }
};

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
static const struct message listview_end_label_edit[] = {
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ENDLABELEDITA },
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ITEMCHANGING},
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY,  sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
    { WM_NOTIFY,  sent|id, 0, 0, NM_SETFOCUS },
    { 0 }
};

static const struct message listview_end_label_edit_kill_focus[] = {
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ENDLABELEDITA },
    { WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ITEMCHANGING },
    { WM_NOTIFY,  sent|id, 0, 0, LVN_ITEMCHANGED },
    { WM_NOTIFY,  sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
    { WM_NOTIFY,  sent|id, 0, 0, NM_SETFOCUS },
    { 0 }
};

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
static void hold_key(int vk)
{
    BYTE kstate[256];
    BOOL res;

    res = GetKeyboardState(kstate);
    ok(res, "GetKeyboardState failed.\n");
    kstate[vk] |= 0x80;
    res = SetKeyboardState(kstate);
    ok(res, "SetKeyboardState failed.\n");
}

static void release_key(int vk)
{
    BYTE kstate[256];
    BOOL res;

    res = GetKeyboardState(kstate);
    ok(res, "GetKeyboardState failed.\n");
    kstate[vk] &= ~0x80;
    res = SetKeyboardState(kstate);
    ok(res, "SetKeyboardState failed.\n");
}

565 566
static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
567
    static LONG defwndproc_counter = 0;
568 569 570
    LRESULT ret;
    struct message msg;

571 572 573 574 575
    msg.message = message;
    msg.flags = sent|wparam|lparam;
    if (defwndproc_counter) msg.flags |= defwinproc;
    msg.wParam = wParam;
    msg.lParam = lParam;
576 577 578 579 580 581 582 583 584 585 586
    if (message == WM_NOTIFY && lParam)
    {
        NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;

        msg.id = nmlv->hdr.code;
        if (msg.id == LVN_ITEMCHANGING || msg.id == LVN_ITEMCHANGED)
        {
            msg.wParam = nmlv->iItem;
            msg.lParam = nmlv->uChanged;
        }
    }
587
    if (message == WM_COMMAND) msg.id = HIWORD(wParam);
588

589 590 591
    /* log system messages, except for painting */
    if (message < WM_USER &&
        message != WM_PAINT &&
592 593 594 595 596 597 598 599
        message != WM_ERASEBKGND &&
        message != WM_NCPAINT &&
        message != WM_NCHITTEST &&
        message != WM_GETTEXT &&
        message != WM_GETICON &&
        message != WM_DEVICECHANGE)
    {
        add_message(sequences, PARENT_SEQ_INDEX, &msg);
600
        add_message(sequences, COMBINED_SEQ_INDEX, &msg);
601
    }
602 603 604 605
    /* log change messages for single and multiple items changing in ownerdata listviews */
    if (message == WM_NOTIFY && (msg.id == LVN_ITEMCHANGED || msg.id == LVN_ODSTATECHANGED))
        add_message(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, &msg);

606
    add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
607

608
    switch (message)
609
    {
610 611 612 613
      case WM_NOTIFY:
      {
          switch (((NMHDR*)lParam)->code)
          {
614
          case LVN_BEGINLABELEDITA:
615 616 617
          {
              HWND edit = NULL;

618 619
              /* subclass edit box */
              if (!blockEdit)
620
                  edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
621

622 623 624
              if (edit)
              {
                  INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
625
                  ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
626 627
                      "text limit %d, expected 259\n", len);
              }
628

629 630
              return blockEdit;
          }
631
          case LVN_ENDLABELEDITA:
632
              {
633 634
              HWND edit;

635
              /* always accept new item text */
636
              NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
637 638 639 640 641
              g_editbox_disp_info = *di;

              /* edit control still available from this notification */
              edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
              ok(IsWindow(edit), "expected valid edit control handle\n");
642
              ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
643

644 645 646
              if (g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT)
                  SendMessageA(edit, WM_KILLFOCUS, 0, 0);

647
              return TRUE;
648
              }
649 650 651 652 653 654
          case LVN_ITEMCHANGING:
              {
                  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
                  g_nmlistview_changing = *nmlv;
              }
              break;
655 656 657
          case LVN_ITEMCHANGED:
              {
                  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
658
                  g_nmlistview = *nmlv;
659 660
              }
              break;
661 662 663 664
          case LVN_GETDISPINFOA:
              {
                  NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
                  g_itema = dispinfo->item;
665 666 667 668

                  if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
                  {
                      dispinfo->hdr.code = LVN_GETDISPINFOW;
669
                      lstrcpyW((WCHAR *)dispinfo->item.pszText, L"TEST");
670
                  }
671 672 673 674 675 676 677

                  /* test control buffer size for text, 10 used to mask cases when control
                     is using caller buffer to process LVM_GETITEM for example */
                  if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
                      ok(dispinfo->item.cchTextMax == 260 ||
                         broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
                      "buffer size %d\n", dispinfo->item.cchTextMax);
678 679
              }
              break;
680 681 682 683 684 685 686 687 688 689
          case LVN_DELETEITEM:
              if (g_focus_test_LVN_DELETEITEM)
              {
                  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
                  UINT state;

                  state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
                  ok(state == 0, "got state %x\n", state);
              }
              break;
690 691 692
          case NM_HOVER:
              if (g_block_hover) return 1;
              break;
693 694 695 696 697 698 699 700 701
          }
          break;
      }
      case WM_NOTIFYFORMAT:
      {
          /* force to return format */
          if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
          break;
      }
702
    }
703

704
    defwndproc_counter++;
705 706 707 708
    if (IsWindowUnicode(hwnd))
        ret = DefWindowProcW(hwnd, message, wParam, lParam);
    else
        ret = DefWindowProcA(hwnd, message, wParam, lParam);
709 710 711 712 713
    defwndproc_counter--;

    return ret;
}

714
static BOOL register_parent_wnd_class(BOOL Unicode)
715
{
716 717 718 719 720 721 722 723 724 725 726
    WNDCLASSA clsA;
    WNDCLASSW clsW;

    if (Unicode)
    {
        clsW.style = 0;
        clsW.lpfnWndProc = parent_wnd_proc;
        clsW.cbClsExtra = 0;
        clsW.cbWndExtra = 0;
        clsW.hInstance = GetModuleHandleW(NULL);
        clsW.hIcon = 0;
727
        clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
728 729
        clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
        clsW.lpszMenuName = NULL;
730
        clsW.lpszClassName = L"Listview test parentW";
731 732 733 734 735 736 737 738 739
    }
    else
    {
        clsA.style = 0;
        clsA.lpfnWndProc = parent_wnd_proc;
        clsA.cbClsExtra = 0;
        clsA.cbWndExtra = 0;
        clsA.hInstance = GetModuleHandleA(NULL);
        clsA.hIcon = 0;
740
        clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
741 742 743 744 745 746
        clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
        clsA.lpszMenuName = NULL;
        clsA.lpszClassName = "Listview test parent class";
    }

    return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
747 748
}

749
static HWND create_parent_window(BOOL Unicode)
750
{
751
    HWND hwnd;
752 753

    if (!register_parent_wnd_class(Unicode))
754 755
        return NULL;

756
    blockEdit = FALSE;
757 758 759
    notifyFormat = -1;

    if (Unicode)
760
        hwnd = CreateWindowExW(0, L"Listview test parentW", L"testparentnameW",
761 762 763 764 765
                               WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
                               WS_MAXIMIZEBOX | WS_VISIBLE,
                               0, 0, 100, 100,
                               GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
    else
766
        hwnd = CreateWindowExA(0, "Listview test parent class",
767 768 769 770 771
                               "Listview test parent window",
                               WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
                               WS_MAXIMIZEBOX | WS_VISIBLE,
                               0, 0, 100, 100,
                               GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
772 773
    SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
    return hwnd;
774 775 776 777
}

static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
778
    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
779
    static LONG defwndproc_counter = 0;
780 781 782 783 784 785 786 787 788 789
    LRESULT ret;
    struct message msg;

    msg.message = message;
    msg.flags = sent|wparam|lparam;
    if (defwndproc_counter) msg.flags |= defwinproc;
    msg.wParam = wParam;
    msg.lParam = lParam;
    msg.id = LISTVIEW_ID;
    add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
790
    add_message(sequences, COMBINED_SEQ_INDEX, &msg);
791 792

    defwndproc_counter++;
793
    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
794 795 796 797
    defwndproc_counter--;
    return ret;
}

798
static HWND create_listview_control(DWORD style)
799
{
800
    WNDPROC oldproc;
801 802 803 804
    HWND hwnd;
    RECT rect;

    GetClientRect(hwndparent, &rect);
805
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
806
                           WS_CHILD | WS_BORDER | WS_VISIBLE | style,
807 808
                           0, 0, rect.right, rect.bottom,
                           hwndparent, NULL, GetModuleHandleA(NULL), NULL);
809
    ok(hwnd != NULL, "gle=%ld\n", GetLastError());
810

811
    if (!hwnd) return NULL;
812

813 814 815
    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
                                        (LONG_PTR)listview_subclass_proc);
    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
816 817 818 819

    return hwnd;
}

820 821 822
/* unicode listview window with specified parent */
static HWND create_listview_controlW(DWORD style, HWND parent)
{
823
    WNDPROC oldproc;
824 825 826 827
    HWND hwnd;
    RECT rect;

    GetClientRect(parent, &rect);
828
    hwnd = CreateWindowExW(0, WC_LISTVIEWW, L"foo",
829
                           WS_CHILD | WS_BORDER | WS_VISIBLE | style,
830 831
                           0, 0, rect.right, rect.bottom,
                           parent, NULL, GetModuleHandleW(NULL), NULL);
832
    ok(hwnd != NULL, "gle=%ld\n", GetLastError());
833

834
    if (!hwnd) return NULL;
835

836 837 838
    oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
                                        (LONG_PTR)listview_subclass_proc);
    SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
839 840 841 842

    return hwnd;
}

843

844 845
static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
846
    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
847
    static LONG defwndproc_counter = 0;
848
    struct message msg = { 0 };
849 850 851 852 853 854 855 856 857 858 859
    LRESULT ret;

    msg.message = message;
    msg.flags = sent|wparam|lparam;
    if (defwndproc_counter) msg.flags |= defwinproc;
    msg.wParam = wParam;
    msg.lParam = lParam;
    msg.id = HEADER_ID;
    add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);

    defwndproc_counter++;
860
    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
861 862 863 864 865 866
    defwndproc_counter--;
    return ret;
}

static HWND subclass_header(HWND hwndListview)
{
867
    WNDPROC oldproc;
868 869
    HWND hwnd;

870
    hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
871 872 873
    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
                                         (LONG_PTR)header_subclass_proc);
    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
874 875 876

    return hwnd;
}
877

878 879
static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
880
    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
881
    static LONG defwndproc_counter = 0;
882
    struct message msg = { 0 };
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
    LRESULT ret;

    msg.message = message;
    msg.flags = sent|wparam|lparam;
    if (defwndproc_counter) msg.flags |= defwinproc;
    msg.wParam = wParam;
    msg.lParam = lParam;

    /* all we need is sizing */
    if (message == WM_WINDOWPOSCHANGING ||
        message == WM_NCCALCSIZE ||
        message == WM_WINDOWPOSCHANGED ||
        message == WM_MOVE ||
        message == WM_SIZE)
    {
        add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
    }

    defwndproc_counter++;
902
    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
903 904 905 906 907 908
    defwndproc_counter--;
    return ret;
}

static HWND subclass_editbox(HWND hwndListview)
{
909
    WNDPROC oldproc;
910 911
    HWND hwnd;

912
    hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
913 914 915
    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
                                         (LONG_PTR)editbox_subclass_proc);
    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
916 917 918 919

    return hwnd;
}

920
/* Performs a single LVM_HITTEST test */
921 922
static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
                              BOOL todo_item, BOOL todo_flags, int line)
923 924
{
    LVHITTESTINFO lpht;
925
    INT ret;
926 927 928 929 930

    lpht.pt.x = x;
    lpht.pt.y = y;
    lpht.iSubItem = 10;

931
    ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
932

933
    todo_wine_if(todo_item)
934
    {
935
        ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
936 937 938 939 940 941 942
        ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
        ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
    }

    if (todo_flags)
    {
        todo_wine
943
            ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
944
    }
945 946 947
    else if (broken_flags)
        ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
                            "Expected flags %x, got %x\n", flags, lpht.flags);
948
    else
949
        ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
950 951
}

952 953
#define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)

954
/* Performs a single LVM_SUBITEMHITTEST test */
955 956
static void 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)
957 958
{
    LVHITTESTINFO lpht;
959
    INT ret;
960 961 962 963

    lpht.pt.x = x;
    lpht.pt.y = y;

964
    ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
965

966
    todo_wine_if(todo_item)
967
    {
968
        ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
969 970 971
        ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
    }

972
    todo_wine_if(todo_subitem)
973 974
        ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);

975
    todo_wine_if(todo_flags)
976
        ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
977 978
}

979 980
#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__)

981
static void test_images(void)
982
{
983
    HWND hwnd;
984
    INT r;
985
    LVITEMA item;
986 987 988
    HIMAGELIST himl;
    HBITMAP hbmp;
    RECT r1, r2;
989
    static CHAR hello[] = "hello";
990

991
    himl = pImageList_Create(40, 40, 0, 4, 4);
992 993 994 995 996
    ok(himl != NULL, "failed to create imagelist\n");

    hbmp = CreateBitmap(40, 40, 1, 1, NULL);
    ok(hbmp != NULL, "failed to create bitmap\n");

997
    r = pImageList_Add(himl, hbmp, 0);
998 999
    ok(r == 0, "should be zero\n");

1000
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_OWNERDRAWFIXED,
1001 1002 1003
                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");

1004
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
1005 1006
                    LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);

1007 1008
    ok(r == 0, "should return zero\n");

1009
    r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
1010 1011
    ok(r == 0, "should return zero\n");

1012
    r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
1013 1014
    ok(r != 0, "got 0\n");

1015 1016
    /* returns dimensions */

1017
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1018 1019 1020 1021 1022 1023
    ok(r == 0, "should be zero items\n");

    item.mask = LVIF_IMAGE | LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 1;
    item.iImage = 0;
1024
    item.pszText = 0;
1025
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1026 1027 1028
    ok(r == -1, "should fail\n");

    item.iSubItem = 0;
1029
    item.pszText = hello;
1030
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1031 1032
    ok(r == 0, "should not fail\n");

1033
    SetRect(&r1, LVIR_ICON, 0, 0, 0);
1034
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
1035
    expect(1, r);
1036

1037
    r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1038 1039 1040
    ok(r == TRUE, "should not fail\n");

    item.iSubItem = 0;
1041
    item.pszText = hello;
1042
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1043 1044
    ok(r == 0, "should not fail\n");

1045
    SetRect(&r2, LVIR_ICON, 0, 0, 0);
1046
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
1047
    expect(1, r);
1048

1049
    ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
1050 1051

    DestroyWindow(hwnd);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082

    /* I_IMAGECALLBACK set for item, try to get image with invalid subitem. */
    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "Failed to create listview.\n");

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_IMAGE;
    item.iImage = I_IMAGECALLBACK;
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(!r, "Failed to insert item.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_IMAGE;
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(r, "Failed to get item.\n");

    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, "get image dispinfo 1", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_IMAGE;
    item.iSubItem = 1;
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(r, "Failed to get item.\n");

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get image dispinfo 2", FALSE);

    DestroyWindow(hwnd);
1083
}
1084 1085 1086

static void test_checkboxes(void)
{
1087
    HWND hwnd;
1088 1089
    LVITEMA item;
    DWORD r;
1090 1091 1092
    static CHAR text[]  = "Text",
                text2[] = "Text2",
                text3[] = "Text3";
1093

1094
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1095 1096 1097 1098 1099 1100 1101 1102 1103
                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");

    /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
    item.mask = LVIF_TEXT | LVIF_STATE;
    item.stateMask = 0xffff;
    item.state = 0xfccc;
    item.iItem = 0;
    item.iSubItem = 0;
1104
    item.pszText = text;
1105
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1106
    expect(0, r);
1107 1108 1109 1110

    item.iItem = 0;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1111
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1112
    expect(1, r);
1113 1114 1115 1116 1117 1118 1119 1120
    ok(item.state == 0xfccc, "state %x\n", item.state);

    /* Don't set LVIF_STATE */
    item.mask = LVIF_TEXT;
    item.stateMask = 0xffff;
    item.state = 0xfccc;
    item.iItem = 1;
    item.iSubItem = 0;
1121
    item.pszText = text;
1122
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1123
    expect(1, r);
1124 1125 1126 1127

    item.iItem = 1;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1128
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1129
    expect(1, r);
1130 1131
    ok(item.state == 0, "state %x\n", item.state);

1132
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1133
    expect(0, r);
1134

1135 1136 1137 1138
    /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
    item.iItem = 0;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1139
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1140
    expect(1, r);
1141

1142
    /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1143 1144 1145
    item.iItem = 2;
    item.mask = LVIF_TEXT;
    item.state = 0;
1146
    item.pszText = text2;
1147
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1148
    expect(2, r);
1149 1150 1151 1152

    item.iItem = 2;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1153
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1154
    expect(1, r);
1155 1156
    ok(item.state == 0x1000, "state %x\n", item.state);

1157
    /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1158 1159 1160 1161
    item.iItem = 3;
    item.mask = LVIF_TEXT | LVIF_STATE;
    item.stateMask = 0xffff;
    item.state = 0x2aaa;
1162
    item.pszText = text3;
1163
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1164
    expect(3, r);
1165 1166 1167 1168

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1169
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1170
    expect(1, r);
1171 1172 1173 1174 1175 1176 1177
    ok(item.state == 0x1aaa, "state %x\n", item.state);

    /* Set an item's state to checked */
    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xf000;
    item.state = 0x2000;
1178
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1179
    expect(1, r);
1180 1181 1182 1183

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1184
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1185
    expect(1, r);
1186 1187
    ok(item.state == 0x2aaa, "state %x\n", item.state);

1188 1189 1190 1191 1192 1193 1194
    /* Check that only the bits we asked for are returned,
     * and that all the others are set to zero
     */
    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xf000;
    item.state = 0xffff;
1195
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1196
    expect(1, r);
1197 1198
    ok(item.state == 0x2000, "state %x\n", item.state);

1199
    /* Set the style again and check that doesn't change an item's state */
1200
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1201
    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1202

1203 1204 1205
    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1206
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1207
    expect(1, r);
1208 1209 1210
    ok(item.state == 0x2aaa, "state %x\n", item.state);

    /* Unsetting the checkbox extended style doesn't change an item's state */
1211
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1212
    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1213 1214 1215 1216

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1217
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1218
    expect(1, r);
1219 1220 1221
    ok(item.state == 0x2aaa, "state %x\n", item.state);

    /* Now setting the style again will change an item's state */
1222
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1223
    expect(0, r);
1224

1225 1226 1227
    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1228
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1229
    expect(1, r);
1230 1231
    ok(item.state == 0x1aaa, "state %x\n", item.state);

1232 1233 1234 1235 1236 1237 1238
    /* Toggle checkbox tests (bug 9934) */
    memset (&item, 0xcc, sizeof(item));
    item.mask = LVIF_STATE;
    item.iItem = 3;
    item.iSubItem = 0;
    item.state = LVIS_FOCUSED;
    item.stateMask = LVIS_FOCUSED;
1239
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1240 1241 1242 1243 1244
    expect(1, r);

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1245
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1246
    expect(1, r);
1247 1248
    ok(item.state == 0x1aab, "state %x\n", item.state);

1249
    r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1250
    expect(0, r);
1251
    r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1252 1253 1254 1255 1256
    expect(0, r);

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1257
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1258
    expect(1, r);
1259
    ok(item.state == 0x2aab, "state %x\n", item.state);
1260

1261
    r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1262
    expect(0, r);
1263
    r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1264 1265 1266 1267 1268
    expect(0, r);

    item.iItem = 3;
    item.mask = LVIF_STATE;
    item.stateMask = 0xffff;
1269
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1270
    expect(1, r);
1271 1272
    ok(item.state == 0x1aab, "state %x\n", item.state);

1273 1274 1275
    DestroyWindow(hwnd);
}

1276 1277
static void insert_column(HWND hwnd, int idx)
{
1278
    LVCOLUMNA column;
1279
    INT rc;
1280

1281
    memset(&column, 0xcc, sizeof(column));
1282 1283 1284
    column.mask = LVCF_SUBITEM;
    column.iSubItem = idx;

1285
    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1286 1287 1288 1289 1290 1291 1292 1293
    expect(idx, rc);
}

static void insert_item(HWND hwnd, int idx)
{
    static CHAR text[] = "foo";

    LVITEMA item;
1294
    INT rc;
1295

1296
    memset(&item, 0xcc, sizeof (item));
1297 1298 1299 1300 1301
    item.mask = LVIF_TEXT;
    item.iItem = idx;
    item.iSubItem = 0;
    item.pszText = text;

1302
    rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1303 1304 1305
    expect(idx, rc);
}

1306 1307 1308
static void test_items(void)
{
    const LPARAM lparamTest = 0x42;
1309 1310
    static CHAR text[] = "Text";
    char buffA[5];
1311
    HWND hwnd;
1312 1313 1314
    LVITEMA item;
    DWORD r;

1315
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1316 1317 1318 1319 1320 1321 1322 1323
                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");

    /*
     * Test setting/getting item params
     */

    /* Set up two columns */
1324 1325
    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
1326

1327 1328 1329 1330 1331 1332 1333 1334
    /* LVIS_SELECTED with zero stateMask */
    /* set */
    memset (&item, 0, sizeof (item));
    item.mask = LVIF_STATE;
    item.state = LVIS_SELECTED;
    item.stateMask = 0;
    item.iItem = 0;
    item.iSubItem = 0;
1335
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1336
    expect(0, r);
1337 1338 1339 1340 1341 1342 1343
    /* get */
    memset (&item, 0xcc, sizeof (item));
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    item.state = 0;
    item.iItem = 0;
    item.iSubItem = 0;
1344
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1345
    expect(1, r);
1346
    ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1347
    r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1348
    ok(r, "got %ld\n", r);
1349 1350 1351 1352 1353 1354 1355 1356 1357

    /* LVIS_SELECTED with zero stateMask */
    /* set */
    memset (&item, 0, sizeof (item));
    item.mask = LVIF_STATE;
    item.state = LVIS_FOCUSED;
    item.stateMask = 0;
    item.iItem = 0;
    item.iSubItem = 0;
1358
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1359
    expect(0, r);
1360 1361 1362 1363 1364 1365 1366
    /* get */
    memset (&item, 0xcc, sizeof (item));
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_FOCUSED;
    item.state = 0;
    item.iItem = 0;
    item.iSubItem = 0;
1367
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1368
    expect(1, r);
1369
    ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1370
    r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1371
    ok(r, "got %ld\n", r);
1372 1373 1374 1375 1376 1377 1378 1379 1380

    /* LVIS_CUT with LVIS_FOCUSED stateMask */
    /* set */
    memset (&item, 0, sizeof (item));
    item.mask = LVIF_STATE;
    item.state = LVIS_CUT;
    item.stateMask = LVIS_FOCUSED;
    item.iItem = 0;
    item.iSubItem = 0;
1381
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1382
    expect(0, r);
1383 1384 1385 1386 1387 1388 1389
    /* get */
    memset (&item, 0xcc, sizeof (item));
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_CUT;
    item.state = 0;
    item.iItem = 0;
    item.iSubItem = 0;
1390
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1391
    expect(1, r);
1392
    ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1393
    r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1394
    ok(r, "got %ld\n", r);
1395

1396
    /* Insert an item with just a param */
1397
    memset (&item, 0xcc, sizeof (item));
1398 1399 1400 1401
    item.mask = LVIF_PARAM;
    item.iItem = 0;
    item.iSubItem = 0;
    item.lParam = lparamTest;
1402
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1403
    expect(0, r);
1404 1405

    /* Test getting of the param */
1406
    memset (&item, 0xcc, sizeof (item));
1407 1408 1409
    item.mask = LVIF_PARAM;
    item.iItem = 0;
    item.iSubItem = 0;
1410
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1411
    expect(1, r);
1412
    ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1413 1414

    /* Set up a subitem */
1415
    memset (&item, 0xcc, sizeof (item));
1416 1417 1418 1419
    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 1;
    item.pszText = text;
1420
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1421
    expect(1, r);
1422

1423 1424 1425 1426 1427
    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 1;
    item.pszText = buffA;
    item.cchTextMax = sizeof(buffA);
1428
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1429
    expect(1, r);
1430 1431 1432 1433 1434 1435 1436 1437
    ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);

    /* set up with extra flag */
    /* 1. reset subitem text */
    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 1;
    item.pszText = NULL;
1438
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1439
    expect(1, r);
1440 1441 1442 1443 1444 1445 1446

    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 1;
    item.pszText = buffA;
    buffA[0] = 'a';
    item.cchTextMax = sizeof(buffA);
1447
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1448
    expect(1, r);
1449 1450 1451 1452 1453 1454 1455
    ok(item.pszText[0] == 0, "got %p\n", item.pszText);

    /* 2. set new text with extra flag specified */
    item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
    item.iItem = 0;
    item.iSubItem = 1;
    item.pszText = text;
1456
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1457
    ok(r == 1 || broken(r == 0) /* NT4 */, "ret %ld\n", r);
1458 1459 1460 1461 1462 1463 1464 1465 1466

    if (r == 1)
    {
        item.mask = LVIF_TEXT;
        item.iItem = 0;
        item.iSubItem = 1;
        item.pszText = buffA;
        buffA[0] = 'a';
        item.cchTextMax = sizeof(buffA);
1467
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1468
        expect(1, r);
1469 1470 1471
        ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
    }

1472
    /* Query param from subitem: returns main item param */
1473
    memset (&item, 0xcc, sizeof (item));
1474 1475 1476
    item.mask = LVIF_PARAM;
    item.iItem = 0;
    item.iSubItem = 1;
1477
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1478
    expect(1, r);
1479
    ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1480 1481

    /* Set up param on first subitem: no effect */
1482
    memset (&item, 0xcc, sizeof (item));
1483 1484 1485 1486
    item.mask = LVIF_PARAM;
    item.iItem = 0;
    item.iSubItem = 1;
    item.lParam = lparamTest+1;
1487
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1488
    expect(0, r);
1489 1490

    /* Query param from subitem again: should still return main item param */
1491
    memset (&item, 0xcc, sizeof (item));
1492 1493 1494
    item.mask = LVIF_PARAM;
    item.iItem = 0;
    item.iSubItem = 1;
1495
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1496
    expect(1, r);
1497
    ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1498

1499
    /**** Some tests of state highlighting ****/
1500
    memset (&item, 0xcc, sizeof (item));
1501 1502 1503 1504 1505
    item.mask = LVIF_STATE;
    item.iItem = 0;
    item.iSubItem = 0;
    item.state = LVIS_SELECTED;
    item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1506
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1507
    expect(1, r);
1508 1509
    item.iSubItem = 1;
    item.state = LVIS_DROPHILITED;
1510
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1511
    expect(1, r);
1512

1513
    memset (&item, 0xcc, sizeof (item));
1514 1515 1516 1517
    item.mask = LVIF_STATE;
    item.iItem = 0;
    item.iSubItem = 0;
    item.stateMask = -1;
1518
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1519
    expect(1, r);
1520 1521
    ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
    item.iSubItem = 1;
1522
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1523
    expect(1, r);
1524 1525
    todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);

1526 1527 1528 1529 1530
    /* some notnull but meaningless masks */
    memset (&item, 0, sizeof(item));
    item.mask = LVIF_NORECOMPUTE;
    item.iItem = 0;
    item.iSubItem = 0;
1531
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1532
    expect(1, r);
1533 1534 1535 1536
    memset (&item, 0, sizeof(item));
    item.mask = LVIF_DI_SETITEM;
    item.iItem = 0;
    item.iSubItem = 0;
1537
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1538
    expect(1, r);
1539

1540
    /* set text to callback value already having it */
1541
    r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1542 1543 1544
    expect(TRUE, r);
    memset (&item, 0, sizeof (item));
    item.mask  = LVIF_TEXT;
1545
    item.pszText = LPSTR_TEXTCALLBACKA;
1546
    item.iItem = 0;
1547
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1548
    expect(0, r);
1549 1550 1551 1552
    memset (&item, 0, sizeof (item));

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

1553 1554
    item.pszText = LPSTR_TEXTCALLBACKA;
    r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1555 1556 1557
    expect(TRUE, r);

    ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1558
                "check callback text comparison rule", FALSE);
1559

1560 1561 1562
    DestroyWindow(hwnd);
}

1563 1564
static void test_columns(void)
{
1565
    HWND hwnd, header;
1566 1567
    LVCOLUMNA column;
    LVITEMA item;
1568
    INT order[2];
1569 1570
    CHAR buff[5];
    DWORD rc;
1571

1572
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_LIST,
1573 1574 1575 1576 1577 1578 1579
                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(header == NULL, "got %p\n", header);

    rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1580
    ok(rc == 0, "got %ld\n", rc);
1581 1582 1583 1584 1585 1586

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(header == NULL, "got %p\n", header);

    DestroyWindow(hwnd);

1587
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1588 1589 1590
                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");

1591
    rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1592
    ok(!rc, "got %ld\n", rc);
1593 1594

    rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1595
    ok(!rc, "got %ld\n", rc);
1596

1597
    /* Add a column with no mask */
1598
    memset(&column, 0xcc, sizeof(column));
1599
    column.mask = 0;
1600
    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1601
    ok(rc == 0, "Inserting column with no mask failed with %ld\n", rc);
1602 1603

    /* Check its width */
1604
    rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1605
    ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %ld\n", rc);
1606 1607

    DestroyWindow(hwnd);
1608 1609

    /* LVM_GETCOLUMNORDERARRAY */
1610
    hwnd = create_listview_control(LVS_REPORT);
1611
    subclass_header(hwnd);
1612 1613 1614 1615

    memset(&column, 0, sizeof(column));
    column.mask = LVCF_WIDTH;
    column.cx = 100;
1616
    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1617
    expect(0, rc);
1618 1619

    column.cx = 200;
1620
    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1621
    expect(1, rc);
1622 1623 1624

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

1625
    rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1626
    expect(1, rc);
1627 1628 1629
    ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
    ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);

1630 1631 1632
    rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
    expect(0, rc);

1633
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1634

1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
    /* LVM_SETCOLUMNORDERARRAY */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    order[0] = 0;
    order[1] = 1;
    rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
    expect(1, rc);

    rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
    expect(0, rc);

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);

1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
    /* after column added subitem is considered as present */
    insert_item(hwnd, 0);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    item.pszText = buff;
    item.cchTextMax = sizeof(buff);
    item.iItem = 0;
    item.iSubItem = 1;
    item.mask = LVIF_TEXT;
    memset(&g_itema, 0, sizeof(g_itema));
    rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1660
    expect(1, rc);
1661 1662 1663 1664 1665
    ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);

    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
        "get subitem text after column added", FALSE);

1666
    DestroyWindow(hwnd);
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679

    /* Columns are not created right away. */
    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "Failed to create a listview window.\n");

    insert_item(hwnd, 0);

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(IsWindow(header), "Expected header handle.\n");
    rc = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
    ok(!rc, "Unexpected column count.\n");

    DestroyWindow(hwnd);
1680
}
1681

1682 1683 1684 1685 1686 1687
/* test setting imagelist between WM_NCCREATE and WM_CREATE */
static WNDPROC listviewWndProc;
static HIMAGELIST test_create_imagelist;

static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
1688 1689
    LRESULT ret;

1690
    if (uMsg == WM_CREATE)
1691
    {
1692
        CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1693 1694
        lpcs->style |= LVS_REPORT;
    }
1695 1696
    ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
    if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1697
    return ret;
1698 1699
}

1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
/* Header creation is delayed in classic implementation. */
#define TEST_NO_HEADER(a) test_header_presence_(a, FALSE, __LINE__)
#define TEST_HEADER_EXPECTED(a) test_header_presence_(a, TRUE, __LINE__)
#define TEST_NO_HEADER2(a, b) test_header_presence_(a, b, __LINE__)
static void test_header_presence_(HWND hwnd, BOOL present, int line)
{
    HWND header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);

    if (present)
    {
        ok_(__FILE__, line)(IsWindow(header), "Header should have been created.\n");
        if (header) /* FIXME: remove when todo's are fixed */
            ok_(__FILE__, line)(header == GetDlgItem(hwnd, 0), "Dialog item expected.\n");
    }
    else
    {
        ok_(__FILE__, line)(!IsWindow(header), "Header shouldn't be created.\n");
        ok_(__FILE__, line)(NULL == GetDlgItem(hwnd, 0), "NULL dialog item expected.\n");
    }
}

static void test_create(BOOL is_version_6)
1722
{
1723
    char buff[16];
1724
    HWND hList;
1725
    HWND hHeader;
1726 1727 1728
    LONG_PTR ret;
    LONG r;
    LVCOLUMNA col;
1729
    RECT rect;
1730
    WNDCLASSEXA cls;
1731
    DWORD style;
1732 1733
    ATOM class;

1734
    cls.cbSize = sizeof(WNDCLASSEXA);
1735 1736
    r = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
    ok(r, "Failed to get class info.\n");
1737 1738 1739
    listviewWndProc = cls.lpfnWndProc;
    cls.lpfnWndProc = create_test_wndproc;
    cls.lpszClassName = "MyListView32";
1740 1741
    class = RegisterClassExA(&cls);
    ok(class, "Failed to register class.\n");
1742

1743
    test_create_imagelist = pImageList_Create(16, 16, 0, 5, 10);
1744 1745 1746
    hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
    ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
    hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1747
    ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1748 1749 1750 1751
    ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
    DestroyWindow(hList);

    /* header isn't created on LVS_ICON and LVS_LIST styles */
1752
    hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1753 1754
    TEST_NO_HEADER(hList);

1755 1756 1757 1758
    /* insert column */
    memset(&col, 0, sizeof(LVCOLUMNA));
    col.mask = LVCF_WIDTH;
    col.cx = 100;
1759
    r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1760
    expect(0, r);
1761
    TEST_HEADER_EXPECTED(hList);
1762 1763
    hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
    style = GetWindowLongA(hHeader, GWL_STYLE);
1764
    ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1765 1766
    DestroyWindow(hList);

1767
    hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1768
                           GetModuleHandleA(NULL), 0);
1769
    TEST_NO_HEADER(hList);
1770 1771 1772 1773
    /* insert column */
    memset(&col, 0, sizeof(LVCOLUMNA));
    col.mask = LVCF_WIDTH;
    col.cx = 100;
1774
    r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1775
    expect(0, r);
1776
    TEST_HEADER_EXPECTED(hList);
1777 1778 1779
    DestroyWindow(hList);

    /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1780
    hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1781 1782
                           GetModuleHandleA(NULL), 0);
    ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1783
    ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1784
    TEST_HEADER_EXPECTED(hList);
1785
    ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1786
    ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1787
    TEST_HEADER_EXPECTED(hList);
1788 1789 1790
    DestroyWindow(hList);

    /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1791
    hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1792 1793 1794
                           GetModuleHandleA(NULL), 0);
    ret = SetWindowLongPtrA(hList, GWL_STYLE,
                           (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1795
    ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1796 1797
    TEST_HEADER_EXPECTED(hList);
    ret = SetWindowLongPtrA(hList, GWL_STYLE, (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1798
    ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1799
    TEST_HEADER_EXPECTED(hList);
1800 1801 1802
    DestroyWindow(hList);

    /* LVS_REPORT without WS_VISIBLE */
1803
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1804 1805
                          GetModuleHandleA(NULL), 0);
    hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1806
    todo_wine_if(is_version_6)
1807 1808
    TEST_NO_HEADER2(hList, is_version_6);

1809 1810 1811 1812
    /* insert column */
    memset(&col, 0, sizeof(LVCOLUMNA));
    col.mask = LVCF_WIDTH;
    col.cx = 100;
1813
    r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1814
    expect(0, r);
1815
    TEST_HEADER_EXPECTED(hList);
1816
    DestroyWindow(hList);
1817 1818

    /* LVS_REPORT without WS_VISIBLE, try to show it */
1819
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1820
                          GetModuleHandleA(NULL), 0);
1821
    todo_wine_if(is_version_6)
1822 1823
    TEST_NO_HEADER2(hList, is_version_6);

1824
    ShowWindow(hList, SW_SHOW);
1825
    TEST_HEADER_EXPECTED(hList);
1826
    DestroyWindow(hList);
1827 1828

    /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1829
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1830
                          0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1831
    TEST_HEADER_EXPECTED(hList);
1832
    hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1833
    /* HDS_DRAGDROP set by default */
1834
    ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1835
    DestroyWindow(hList);
1836 1837

    /* setting LVS_EX_HEADERDRAGDROP creates header */
1838
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1839
                          GetModuleHandleA(NULL), 0);
1840
    todo_wine_if(is_version_6)
1841 1842
    TEST_NO_HEADER2(hList, is_version_6);

1843
    SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1844
    TEST_HEADER_EXPECTED(hList);
1845
    DestroyWindow(hList);
1846

1847
    /* setting LVS_EX_GRIDLINES creates header */
1848
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1849
                          GetModuleHandleA(NULL), 0);
1850
    todo_wine_if(is_version_6)
1851 1852
    TEST_NO_HEADER2(hList, is_version_6);

1853
    SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1854
    TEST_HEADER_EXPECTED(hList);
1855 1856
    DestroyWindow(hList);

1857
    /* setting LVS_EX_FULLROWSELECT creates header */
1858
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1859
                          GetModuleHandleA(NULL), 0);
1860
    todo_wine_if(is_version_6)
1861
    TEST_NO_HEADER2(hList, is_version_6);
1862
    SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1863
    TEST_HEADER_EXPECTED(hList);
1864 1865
    DestroyWindow(hList);

1866
    /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1867
    hList = create_listview_control(LVS_ICON);
1868 1869
    SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
    r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1870 1871 1872
    ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
    DestroyWindow(hList);

1873
    /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1874
    hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1875
                          GetModuleHandleA(NULL), 0);
1876
    todo_wine_if(is_version_6)
1877
    TEST_NO_HEADER2(hList, is_version_6);
1878

1879
    SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1880
    r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1881
    ok(r == 1, "Unexpected ret value %ld.\n", r);
1882
    /* right value contains garbage, probably because header columns are not set up */
1883
    ok(rect.bottom >= 0, "Unexpected rectangle.\n");
1884

1885
    todo_wine_if(is_version_6)
1886
    TEST_NO_HEADER2(hList, is_version_6);
1887
    DestroyWindow(hList);
1888 1889 1890

    /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
1891
    hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1892
    ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1893
                "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1894
    DestroyWindow(hList);
1895 1896 1897 1898 1899 1900 1901 1902 1903 1904

    /* Test that window text is preserved. */
    hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
        0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
    ok(hList != NULL, "Failed to create ListView window.\n");
    *buff = 0;
    GetWindowTextA(hList, buff, sizeof(buff));
    ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
    DestroyWindow(hList);

1905
    hList = CreateWindowExW(0, WC_LISTVIEWW, L"test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1906 1907 1908 1909 1910 1911
        0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
    ok(hList != NULL, "Failed to create ListView window.\n");
    *buff = 0;
    GetWindowTextA(hList, buff, sizeof(buff));
    ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
    DestroyWindow(hList);
1912 1913 1914

    r = UnregisterClassA("MyListView32", NULL);
    ok(r, "Failed to unregister test class.\n");
1915 1916
}

1917 1918
static void test_redraw(void)
{
1919
    HWND hwnd;
1920 1921
    HDC hdc;
    BOOL res;
1922
    DWORD r;
1923
    RECT rect;
1924

1925
    hwnd = create_listview_control(LVS_REPORT);
1926
    subclass_header(hwnd);
1927 1928 1929 1930 1931

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
1932
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1933 1934 1935

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

1936
    /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1937
    /* 1. Without backbuffer */
1938
    res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1939 1940 1941 1942 1943
    expect(TRUE, res);

    hdc = GetWindowDC(hwndparent);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
1944
    r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1945
    ok(r == 1, "Expected not zero result\n");
1946 1947 1948
    ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
                "forward WM_ERASEBKGND on CLR_NONE", FALSE);

1949
    res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1950 1951 1952 1953
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1954
    expect(1, r);
1955 1956 1957 1958 1959 1960
    ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
                "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);

    /* 2. With backbuffer */
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
                                                     LVS_EX_DOUBLEBUFFER);
1961
    res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1962 1963 1964 1965
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1966
    expect(1, r);
1967
    ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1968
                "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1969

1970
    res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1971 1972 1973
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
1974
    r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1975
    todo_wine expect(1, r);
1976 1977 1978 1979 1980
    ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
                "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);

    ReleaseDC(hwndparent, hdc);

1981 1982 1983 1984 1985 1986 1987
    /* test setting the window style to what it already was */
    UpdateWindow(hwnd);
    SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE));
    GetUpdateRect(hwnd, &rect, FALSE);
    ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
       "Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));

1988 1989 1990
    DestroyWindow(hwnd);
}

1991
static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1992 1993 1994
{
    COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);

1995 1996
    if(message == WM_NOTIFY) {
        NMHDR *nmhdr = (NMHDR*)lParam;
1997
        if(nmhdr->code == NM_CUSTOMDRAW) {
1998
            NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1999 2000
            BOOL showsel_always = !!(GetWindowLongA(nmlvcd->nmcd.hdr.hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS);
            BOOL is_selected = !!(nmlvcd->nmcd.uItemState & CDIS_SELECTED);
2001 2002 2003 2004 2005 2006 2007 2008 2009
            struct message msg;

            msg.message = message;
            msg.flags = sent|wparam|lparam|custdraw;
            msg.wParam = wParam;
            msg.lParam = lParam;
            msg.id = nmhdr->code;
            msg.stage = nmlvcd->nmcd.dwDrawStage;
            add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
2010

2011 2012 2013
            switch(nmlvcd->nmcd.dwDrawStage) {
            case CDDS_PREPAINT:
                SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
2014
                return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2015
            case CDDS_ITEMPREPAINT:
2016 2017
                clr = GetBkColor(nmlvcd->nmcd.hdc);
                todo_wine_if(nmlvcd->iSubItem)
2018
                    ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2019
                nmlvcd->clrTextBk = CLR_DEFAULT;
2020 2021
                nmlvcd->clrText = RGB(0, 255, 0);
                return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2022 2023
            case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
                clr = GetBkColor(nmlvcd->nmcd.hdc);
2024 2025
                ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background %#lx.\n", nmlvcd->clrTextBk);
                ok(nmlvcd->clrText == RGB(0, 255, 0), "Unexpected text color %#lx.\n", nmlvcd->clrText);
2026
                if (showsel_always && is_selected && nmlvcd->iSubItem)
2027
                    ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2028
                else
2029
                todo_wine_if(nmlvcd->iSubItem)
2030
                    ok(clr == c0ffee, "clr=%.8lx\n", clr);
2031 2032 2033
                return CDRF_NOTIFYPOSTPAINT;
            case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
                clr = GetBkColor(nmlvcd->nmcd.hdc);
2034
                if (showsel_always && is_selected)
2035
                    ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2036 2037 2038
                else
                {
                todo_wine
2039
                    ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2040 2041
                }

2042 2043
                ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background color %#lx.\n", nmlvcd->clrTextBk);
                ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%lx\n", nmlvcd->clrText);
2044 2045 2046 2047 2048 2049
                return CDRF_DODEFAULT;
            }
            return CDRF_DODEFAULT;
        }
    }

2050
    return DefWindowProcA(hwnd, message, wParam, lParam);
2051 2052 2053 2054 2055 2056
}

static void test_customdraw(void)
{
    HWND hwnd;
    WNDPROC oldwndproc;
2057
    LVITEMA item;
2058

2059
    hwnd = create_listview_control(LVS_REPORT);
2060 2061 2062 2063 2064

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
    insert_item(hwnd, 0);

2065
    oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
2066
                                           (LONG_PTR)cd_wndproc);
2067 2068 2069 2070

    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);

2071 2072 2073 2074 2075
    /* message tests */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
2076

2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
    /* Check colors when item is selected. */
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    item.state = LVIS_SELECTED;
    SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
            "parent customdraw, item selected, LVS_REPORT, selection", FALSE);

    SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) | LVS_SHOWSELALWAYS);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
            "parent customdraw, item selected, LVS_SHOWSELALWAYS, LVS_REPORT", FALSE);

2096
    DestroyWindow(hwnd);
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110

    hwnd = create_listview_control(LVS_LIST);

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
    insert_item(hwnd, 0);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);

    SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
    DestroyWindow(hwnd);
2111 2112
}

2113 2114 2115 2116 2117 2118
static void test_icon_spacing(void)
{
    /* LVM_SETICONSPACING */
    /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */

    HWND hwnd;
2119
    WORD w, h;
2120
    INT r;
2121

2122
    hwnd = create_listview_control(LVS_ICON);
2123
    ok(hwnd != NULL, "failed to create a listview window\n");
2124

2125
    r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
2126 2127
    expect(NFR_ANSI, r);

2128
    /* reset the icon spacing to defaults */
2129
    SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2130 2131

    /* now we can request what the defaults are */
2132
    r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2133
    w = LOWORD(r);
James Hawkins's avatar
James Hawkins committed
2134
    h = HIWORD(r);
2135

2136 2137
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

2138
    r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
2139 2140
    ok(r == MAKELONG(w, h) ||
       broken(r == MAKELONG(w, w)), /* win98 */
2141
       "Expected %ld, got %d\n", MAKELONG(w, h), r);
2142

2143
    r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
2144 2145
    expect(MAKELONG(20,30), r);

2146
    r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
2147
    expect(MAKELONG(25,35), r);
2148 2149 2150 2151 2152 2153 2154 2155 2156

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
}

static void test_color(void)
{
2157
    RECT rect;
2158 2159 2160 2161 2162 2163 2164
    HWND hwnd;
    DWORD r;
    int i;

    COLORREF color;
    COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};

2165
    hwnd = create_listview_control(LVS_REPORT);
2166
    ok(hwnd != NULL, "failed to create a listview window\n");
2167 2168 2169 2170 2171 2172 2173

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    for (i = 0; i < 4; i++)
    {
        color = colors[i];

2174
        r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
2175
        expect(TRUE, r);
2176
        r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
2177 2178
        expect(color, r);

2179
        r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
2180
        expect (TRUE, r);
2181
        r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
2182 2183
        expect(color, r);

2184
        r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
2185
        expect(TRUE, r);
2186
        r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
2187 2188 2189 2190 2191
        expect(color, r);
    }

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
2192 2193 2194 2195

    /* invalidation test done separately to avoid a message chain mess */
    r = ValidateRect(hwnd, NULL);
    expect(TRUE, r);
2196
    r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2197 2198 2199 2200 2201
    expect(TRUE, r);

    rect.right = rect.bottom = 1;
    r = GetUpdateRect(hwnd, &rect, TRUE);
    todo_wine expect(FALSE, r);
2202
    ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2203 2204 2205

    r = ValidateRect(hwnd, NULL);
    expect(TRUE, r);
2206
    r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2207 2208 2209 2210 2211
    expect(TRUE, r);

    rect.right = rect.bottom = 1;
    r = GetUpdateRect(hwnd, &rect, TRUE);
    todo_wine expect(FALSE, r);
2212
    ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2213 2214 2215

    r = ValidateRect(hwnd, NULL);
    expect(TRUE, r);
2216
    r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2217 2218 2219 2220 2221 2222 2223
    expect(TRUE, r);

    rect.right = rect.bottom = 1;
    r = GetUpdateRect(hwnd, &rect, TRUE);
    todo_wine expect(FALSE, r);
    ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");

2224 2225 2226 2227 2228 2229 2230 2231 2232
    DestroyWindow(hwnd);
}

static void test_item_count(void)
{
    /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */

    HWND hwnd;
    DWORD r;
2233 2234 2235 2236 2237
    HDC hdc;
    HFONT hOldFont;
    TEXTMETRICA tm;
    RECT rect;
    INT height;
2238

2239 2240 2241
    LVITEMA item0;
    LVITEMA item1;
    LVITEMA item2;
2242 2243 2244 2245
    static CHAR item0text[] = "item0";
    static CHAR item1text[] = "item1";
    static CHAR item2text[] = "item2";

2246
    hwnd = create_listview_control(LVS_REPORT);
2247
    ok(hwnd != NULL, "failed to create a listview window\n");
2248

2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
    /* resize in dpiaware manner to fit all 3 items added */
    hdc = GetDC(0);
    hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
    GetTextMetricsA(hdc, &tm);
    /* 2 extra pixels for bounds and header border */
    height = tm.tmHeight + 2;
    SelectObject(hdc, hOldFont);
    ReleaseDC(0, hdc);

    GetWindowRect(hwnd, &rect);
    /* 3 items + 1 header + 1 to be sure */
    MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);

2262 2263
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

2264
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2265 2266 2267 2268 2269 2270 2271
    expect(0, r);

    /* [item0] */
    item0.mask = LVIF_TEXT;
    item0.iItem = 0;
    item0.iSubItem = 0;
    item0.pszText = item0text;
2272
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2273 2274 2275 2276 2277 2278 2279
    expect(0, r);

    /* [item0, item1] */
    item1.mask = LVIF_TEXT;
    item1.iItem = 1;
    item1.iSubItem = 0;
    item1.pszText = item1text;
2280
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2281 2282 2283 2284 2285 2286 2287
    expect(1, r);

    /* [item0, item1, item2] */
    item2.mask = LVIF_TEXT;
    item2.iItem = 2;
    item2.iSubItem = 0;
    item2.pszText = item2text;
2288
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2289 2290
    expect(2, r);

2291
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2292 2293 2294
    expect(3, r);

    /* [item0, item1] */
2295
    r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2296 2297
    expect(TRUE, r);

2298
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2299 2300 2301
    expect(2, r);

    /* [] */
2302
    r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2303 2304
    expect(TRUE, r);

2305
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2306 2307 2308
    expect(0, r);

    /* [item0] */
2309
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2310 2311 2312
    expect(0, r);

    /* [item0, item1] */
2313
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2314 2315
    expect(1, r);

2316
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2317 2318 2319
    expect(2, r);

    /* [item0, item1, item2] */
2320
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2321 2322
    expect(2, r);

2323
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339
    expect(3, r);

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
}

static void test_item_position(void)
{
    /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */

    HWND hwnd;
    DWORD r;
    POINT position;

2340 2341 2342
    LVITEMA item0;
    LVITEMA item1;
    LVITEMA item2;
2343 2344 2345 2346
    static CHAR item0text[] = "item0";
    static CHAR item1text[] = "item1";
    static CHAR item2text[] = "item2";

2347
    hwnd = create_listview_control(LVS_ICON);
2348
    ok(hwnd != NULL, "failed to create a listview window\n");
2349 2350 2351 2352 2353 2354 2355 2356

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    /* [item0] */
    item0.mask = LVIF_TEXT;
    item0.iItem = 0;
    item0.iSubItem = 0;
    item0.pszText = item0text;
2357
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2358 2359 2360 2361 2362 2363 2364
    expect(0, r);

    /* [item0, item1] */
    item1.mask = LVIF_TEXT;
    item1.iItem = 1;
    item1.iSubItem = 0;
    item1.pszText = item1text;
2365
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2366 2367 2368 2369 2370 2371 2372
    expect(1, r);

    /* [item0, item1, item2] */
    item2.mask = LVIF_TEXT;
    item2.iItem = 2;
    item2.iSubItem = 0;
    item2.pszText = item2text;
2373
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2374 2375
    expect(2, r);

2376
    r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2377
    expect(TRUE, r);
2378
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2379 2380 2381
    expect(TRUE, r);
    expect2(10, 5, position.x, position.y);

2382
    r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2383
    expect(TRUE, r);
2384
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2385 2386 2387
    expect(TRUE, r);
    expect2(0, 0, position.x, position.y);

2388
    r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2389
    expect(TRUE, r);
2390
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2391 2392 2393 2394 2395 2396 2397 2398 2399
    expect(TRUE, r);
    expect2(20, 20, position.x, position.y);

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
}

2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
static void test_getorigin(void)
{
    /* LVM_GETORIGIN */

    HWND hwnd;
    DWORD r;
    POINT position;

    position.x = position.y = 0;

2410
    hwnd = create_listview_control(LVS_ICON);
2411 2412
    ok(hwnd != NULL, "failed to create a listview window\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
2413

2414
    r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2415 2416 2417 2418
    expect(TRUE, r);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);

2419
    hwnd = create_listview_control(LVS_SMALLICON);
2420 2421
    ok(hwnd != NULL, "failed to create a listview window\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
2422

2423
    r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2424 2425 2426 2427
    expect(TRUE, r);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);

2428
    hwnd = create_listview_control(LVS_LIST);
2429 2430
    ok(hwnd != NULL, "failed to create a listview window\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
2431

2432
    r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2433 2434 2435 2436
    expect(FALSE, r);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);

2437
    hwnd = create_listview_control(LVS_REPORT);
2438 2439
    ok(hwnd != NULL, "failed to create a listview window\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
2440

2441
    r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2442 2443 2444 2445 2446
    expect(FALSE, r);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
}

2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458
static void test_multiselect(void)
{
    typedef struct t_select_task
    {
	const char *descr;
        int initPos;
        int loopVK;
        int count;
	int result;
    } select_task;

    HWND hwnd;
2459
    INT r;
2460
    int i, j;
2461
    static const int items=5;
2462
    DWORD item_count;
2463
    select_task task;
2464
    LONG_PTR style;
2465
    LVITEMA item;
2466 2467 2468 2469 2470 2471 2472 2473

    static struct t_select_task task_list[] = {
        { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
        { "using VK_UP", -1, VK_UP, -1, -1 },
        { "using VK_END", 0, VK_END, 1, -1 },
        { "using VK_HOME", -1, VK_HOME, 1, -1 }
    };

2474
    hwnd = create_listview_control(LVS_REPORT);
2475

2476 2477
    for (i = 0; i < items; i++)
        insert_item(hwnd, 0);
2478

2479
    item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2480
    expect(items, item_count);
2481

2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
    ok(r == -1, "got %d\n", r);

    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
    ok(r == -1, "got %d\n", r);

    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
    ok(r == 0, "got %d\n", r);

    /* out of range index */
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
    ok(r == 0, "got %d\n", r);

    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(r == 0, "got %d\n", r);

    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
    ok(r == 0, "got %d\n", r);

    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(r == 0, "got %d\n", r);

2504
    for (i = 0; i < ARRAY_SIZE(task_list); i++) {
2505
        DWORD selected_count;
2506
        LVITEMA item;
2507 2508 2509 2510

        task = task_list[i];

	/* deselect all items */
2511 2512
        item.state = 0;
        item.stateMask = LVIS_SELECTED;
2513 2514
        r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
        ok(r, "got %d\n", r);
2515
	SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2516 2517

	/* set initial position */
2518 2519
        r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
        ok(r, "got %d\n", r);
2520 2521 2522

        item.state = LVIS_SELECTED;
        item.stateMask = LVIS_SELECTED;
2523 2524
        r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
        ok(r, "got %d\n", r);
2525

2526
	selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2527
	ok(selected_count == 1, "expected 1, got %ld\n", selected_count);
2528

2529
        hold_key(VK_SHIFT);
2530 2531

	for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2532
	    r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2533
	    expect(0,r);
2534
	    r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2535 2536 2537
	    expect(0,r);
	}

2538
	selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2539

2540
	ok((task.result == -1 ? item_count : task.result) == selected_count,
2541
            "Failed multiple selection %s. There should be %ld selected items (is %ld)\n",
2542
            task.descr, item_count, selected_count);
2543

2544
        release_key(VK_SHIFT);
2545 2546
    }
    DestroyWindow(hwnd);
2547 2548

    /* make multiple selection, then switch to LVS_SINGLESEL */
2549
    hwnd = create_listview_control(LVS_REPORT);
2550 2551 2552
    for (i=0;i<items;i++) {
	    insert_item(hwnd, 0);
    }
2553
    item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2554
    expect(items,item_count);
2555

2556
    /* try with NULL pointer */
2557
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2558 2559
    expect(FALSE, r);

2560
    /* select all, check notifications */
2561 2562
    item.state = 0;
    item.stateMask = LVIS_SELECTED;
2563 2564
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    ok(r, "got %d\n", r);
2565 2566 2567 2568 2569 2570 2571 2572

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, r);

2573
    ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2574 2575
                "select all notification", FALSE);

2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592
    /* select all again (all selected already) */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));

    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, r);

    ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
    ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
    ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);

    ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
                "select all notification 2", FALSE);

2593
    /* deselect all items */
2594 2595
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

2596 2597
    item.state = 0;
    item.stateMask = LVIS_SELECTED;
2598 2599
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    ok(r, "got %d\n", r);
2600

2601 2602 2603 2604 2605 2606 2607 2608
    ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
                "deselect all notification", FALSE);

    /* deselect all items again */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.state = 0;
    item.stateMask = LVIS_SELECTED;
    SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2609
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627

    /* any non-zero state value does the same */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));

    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_CUT;
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, r);

    ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
    ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
    ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);

    ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
                "set state all notification 3", FALSE);

2628 2629
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
    ok(r, "got %d\n", r);
2630
    for (i = 0; i < 3; i++) {
2631 2632
        item.state = LVIS_SELECTED;
        item.stateMask = LVIS_SELECTED;
2633 2634
        r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
        ok(r, "got %d\n", r);
2635 2636
    }

2637
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2638
    expect(3, r);
2639
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
    expect(-1, r);

    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
    /* check that style is accepted */
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");

    for (i=0;i<3;i++) {
2650
        r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2651 2652
        ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
    }
2653
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2654
    expect(3, r);
2655 2656
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(r == -1, "got %d\n", r);
2657 2658

    /* select one more */
2659 2660
    item.state = LVIS_SELECTED;
    item.stateMask = LVIS_SELECTED;
2661 2662
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
    ok(r, "got %d\n", r);
2663 2664

    for (i=0;i<3;i++) {
2665
        r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2666 2667
        ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
    }
2668 2669

    r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2670 2671
    ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);

2672
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2673
    expect(1, r);
2674
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2675 2676
    expect(-1, r);

2677 2678 2679
    /* try to select all on LVS_SINGLESEL */
    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_SELECTED;
2680
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2681
    expect(TRUE, r);
2682 2683
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
    ok(r == -1, "got %d\n", r);
2684 2685 2686

    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
2687
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2688 2689
    expect(FALSE, r);

2690
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2691
    expect(0, r);
2692
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2693 2694 2695 2696 2697
    expect(-1, r);

    /* try to deselect all on LVS_SINGLESEL */
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
2698
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2699 2700 2701 2702
    expect(TRUE, r);

    item.stateMask = LVIS_SELECTED;
    item.state     = 0;
2703
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2704
    expect(TRUE, r);
2705
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2706 2707
    expect(0, r);

2708 2709 2710 2711
    /* 1. selection mark is update when new focused item is set */
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);

2712
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2713 2714 2715 2716
    expect(-1, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
2717
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2718 2719
    expect(TRUE, r);

2720
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2721 2722 2723 2724 2725
    expect(0, r);

    /* it's not updated if already set */
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
2726
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2727 2728
    expect(TRUE, r);

2729
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2730 2731
    expect(0, r);

2732
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2733 2734 2735 2736
    expect(0, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
2737
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2738 2739
    expect(TRUE, r);

2740
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2741 2742 2743 2744 2745
    expect(-1, r);

    /* need to reset focused item first */
    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
2746
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2747 2748 2749 2750
    expect(TRUE, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
2751
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2752 2753
    expect(TRUE, r);

2754
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2755 2756 2757 2758
    expect(2, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
2759
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2760 2761
    expect(TRUE, r);

2762
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2763 2764 2765 2766 2767 2768
    expect(2, r);

    /* 2. same tests, with LVM_SETITEM */
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);

2769
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2770 2771 2772 2773 2774 2775
    expect(2, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    item.mask      = LVIF_STATE;
    item.iItem = item.iSubItem = 0;
2776
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2777 2778
    expect(TRUE, r);

2779
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2780 2781 2782 2783 2784 2785 2786 2787
    expect(0, r);

    /* it's not updated if already set */
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    item.mask      = LVIF_STATE;
    item.iItem     = 1;
    item.iSubItem  = 0;
2788
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2789 2790
    expect(TRUE, r);

2791
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2792 2793
    expect(0, r);

2794
    r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2795 2796 2797 2798 2799 2800 2801
    expect(0, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    item.mask      = LVIF_STATE;
    item.iItem     = 1;
    item.iSubItem  = 0;
2802
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2803 2804
    expect(TRUE, r);

2805
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2806 2807 2808 2809 2810
    expect(-1, r);

    /* need to reset focused item first */
    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
2811
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2812 2813 2814 2815 2816 2817 2818
    expect(TRUE, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    item.mask      = LVIF_STATE;
    item.iItem     = 2;
    item.iSubItem  = 0;
2819
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2820 2821
    expect(TRUE, r);

2822
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2823 2824 2825 2826
    expect(2, r);

    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
2827
    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2828 2829
    expect(TRUE, r);

2830
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2831 2832
    expect(2, r);

2833
    DestroyWindow(hwnd);
2834 2835
}

2836 2837 2838 2839
static void test_subitem_rect(void)
{
    HWND hwnd;
    DWORD r;
2840
    LVCOLUMNA col;
2841
    RECT rect, rect2;
2842
    INT arr[3];
2843 2844

    /* test LVM_GETSUBITEMRECT for header */
2845
    hwnd = create_listview_control(LVS_REPORT);
2846 2847
    ok(hwnd != NULL, "failed to create a listview window\n");
    /* add some columns */
2848
    memset(&col, 0, sizeof(LVCOLUMNA));
2849 2850
    col.mask = LVCF_WIDTH;
    col.cx = 100;
2851
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2852 2853
    expect(0, r);
    col.cx = 150;
2854
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2855 2856
    expect(1, r);
    col.cx = 200;
2857
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2858 2859
    expect(2, r);
    /* item = -1 means header, subitem index is 1 based */
2860
    SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2861
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2862 2863
    expect(0, r);

2864
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2865
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2866
    expect(1, r);
2867

2868 2869 2870
    expect(100, rect.left);
    expect(250, rect.right);
    expect(3, rect.top);
2871

2872
    SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2873
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2874
    expect(1, r);
2875

2876 2877 2878 2879
    expect(250, rect.left);
    expect(450, rect.right);
    expect(3, rect.top);

2880 2881 2882
    /* item LVS_REPORT padding isn't applied to subitems */
    insert_item(hwnd, 0);

2883
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2884
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2885
    expect(1, r);
2886 2887 2888
    expect(100, rect.left);
    expect(250, rect.right);

2889
    SetRect(&rect, LVIR_ICON, 1, 0, 0);
2890
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2891
    expect(1, r);
2892
    /* no icon attached - zero width rectangle, with no left padding */
2893 2894 2895
    expect(100, rect.left);
    expect(100, rect.right);

2896
    SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2897
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2898
    expect(1, r);
2899
    /* same as full LVIR_BOUNDS */
2900 2901 2902
    expect(100, rect.left);
    expect(250, rect.right);

2903
    r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2904
    ok(r, "got %ld\n", r);
2905

2906
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2907
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2908
    expect(1, r);
2909 2910 2911
    expect(90, rect.left);
    expect(240, rect.right);

2912
    SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2913

2914 2915 2916 2917
    /* test header interaction */
    subclass_header(hwnd);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

2918
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2919
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2920 2921
    expect(1, r);

2922
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2923
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2924 2925
    expect(1, r);

2926
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2927
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2928 2929
    expect(1, r);

2930
    SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2931
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2932 2933 2934 2935
    expect(1, r);

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);

2936
    DestroyWindow(hwnd);
2937

2938 2939 2940
    /* test subitem rects after re-arranging columns */
    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");
2941
    memset(&col, 0, sizeof(LVCOLUMNA));
2942 2943 2944
    col.mask = LVCF_WIDTH;

    col.cx = 100;
2945
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2946 2947 2948
    expect(0, r);

    col.cx = 200;
2949
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2950 2951 2952
    expect(1, r);

    col.cx = 300;
2953
    r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2954 2955 2956
    expect(2, r);

    insert_item(hwnd, 0);
2957 2958 2959
    insert_item(hwnd, 1);

    /* wrong item is refused for main item */
2960
    SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2961
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2962
    expect(FALSE, r);
2963 2964

    /* for subitems rectangle is calculated even if there's no item added */
2965
    SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2966
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2967
    expect(TRUE, r);
2968

2969
    SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2970
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2971
    expect(TRUE, r);
2972 2973 2974 2975
    expect(rect.right, rect2.right);
    expect(rect.left, rect2.left);
    expect(rect.bottom, rect2.top);
    ok(rect2.bottom > rect2.top, "expected not zero height\n");
2976 2977

    arr[0] = 1; arr[1] = 0; arr[2] = 2;
2978
    r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2979 2980
    expect(TRUE, r);

2981
    SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2982
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2983
    expect(TRUE, r);
2984 2985 2986
    expect(0, rect.left);
    expect(600, rect.right);

2987
    SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2988
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2989
    expect(TRUE, r);
2990 2991 2992
    expect(0, rect.left);
    expect(200, rect.right);

2993
    SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2994
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2995
    expect(TRUE, r);
2996 2997 2998 2999 3000 3001 3002
    expect(0, rect2.left);
    expect(200, rect2.right);
    /* items are of the same height */
    ok(rect2.top > 0, "expected positive item height\n");
    expect(rect.bottom, rect2.top);
    expect(rect.bottom * 2 - rect.top, rect2.bottom);

3003
    SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
3004
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
3005
    expect(TRUE, r);
3006 3007 3008 3009 3010
    expect(300, rect.left);
    expect(600, rect.right);

    DestroyWindow(hwnd);

3011
    /* try it for non LVS_REPORT style */
3012
    hwnd = CreateWindowA(WC_LISTVIEWA, "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
3013
                         GetModuleHandleA(NULL), 0);
3014
    SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
3015
    r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
3016
    expect(0, r);
3017 3018 3019 3020 3021 3022
    /* rect is unchanged */
    expect(0, rect.left);
    expect(-10, rect.right);
    expect(1, rect.top);
    expect(-10, rect.bottom);
    DestroyWindow(hwnd);
3023 3024
}

3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035
/* comparison callback for test_sorting */
static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
{
    if (first == second) return 0;
    return (first > second ? 1 : -1);
}

static void test_sorting(void)
{
    HWND hwnd;
    LVITEMA item = {0};
3036
    INT r;
3037
    LONG_PTR style;
3038
    static CHAR names[][5] = {"A", "B", "C", "D", "0"};
3039
    CHAR buff[10];
3040

3041
    hwnd = create_listview_control(LVS_REPORT);
3042 3043 3044 3045 3046 3047 3048 3049
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* insert some items */
    item.mask = LVIF_PARAM | LVIF_STATE;
    item.state = LVIS_SELECTED;
    item.iItem = 0;
    item.iSubItem = 0;
    item.lParam = 3;
3050
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3051 3052 3053 3054 3055 3056
    expect(0, r);

    item.mask = LVIF_PARAM;
    item.iItem = 1;
    item.iSubItem = 0;
    item.lParam = 2;
3057
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3058 3059 3060 3061 3062 3063 3064
    expect(1, r);

    item.mask = LVIF_STATE | LVIF_PARAM;
    item.state = LVIS_SELECTED;
    item.iItem = 2;
    item.iSubItem = 0;
    item.lParam = 4;
3065
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3066 3067
    expect(2, r);

3068
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3069 3070
    expect(-1, r);

3071
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3072 3073
    expect(2, r);

3074
    r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
3075 3076
    expect(TRUE, r);

3077
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3078
    expect(2, r);
3079
    r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3080
    expect(-1, r);
3081
    r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
3082
    expect(0, r);
3083
    r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
3084
    expect(LVIS_SELECTED, r);
3085
    r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
3086 3087 3088
    expect(LVIS_SELECTED, r);

    DestroyWindow(hwnd);
3089 3090

    /* switch to LVS_SORTASCENDING when some items added */
3091
    hwnd = create_listview_control(LVS_REPORT);
3092 3093 3094 3095 3096 3097
    ok(hwnd != NULL, "failed to create a listview window\n");

    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 0;
    item.pszText = names[1];
3098
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3099 3100 3101 3102 3103 3104
    expect(0, r);

    item.mask = LVIF_TEXT;
    item.iItem = 1;
    item.iSubItem = 0;
    item.pszText = names[2];
3105
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3106 3107 3108 3109 3110 3111
    expect(1, r);

    item.mask = LVIF_TEXT;
    item.iItem = 2;
    item.iSubItem = 0;
    item.pszText = names[0];
3112
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124
    expect(2, r);

    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");

    /* no sorting performed when switched to LVS_SORTASCENDING */
    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.pszText = buff;
    item.cchTextMax = sizeof(buff);
3125
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3126
    expect(TRUE, r);
3127
    ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3128 3129

    item.iItem = 1;
3130
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3131
    expect(TRUE, r);
3132
    ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3133 3134

    item.iItem = 2;
3135
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3136
    expect(TRUE, r);
3137
    ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3138 3139 3140 3141 3142 3143

    /* adding new item doesn't resort list */
    item.mask = LVIF_TEXT;
    item.iItem = 3;
    item.iSubItem = 0;
    item.pszText = names[3];
3144
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3145 3146 3147 3148 3149 3150
    expect(3, r);

    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.pszText = buff;
    item.cchTextMax = sizeof(buff);
3151
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3152
    expect(TRUE, r);
3153
    ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3154 3155

    item.iItem = 1;
3156
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3157
    expect(TRUE, r);
3158
    ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3159 3160

    item.iItem = 2;
3161
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3162
    expect(TRUE, r);
3163
    ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3164 3165

    item.iItem = 3;
3166
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3167
    expect(TRUE, r);
3168
    ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3169

3170 3171 3172 3173 3174
    /* corner case - item should be placed at first position */
    item.mask = LVIF_TEXT;
    item.iItem = 4;
    item.iSubItem = 0;
    item.pszText = names[4];
3175
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3176 3177 3178 3179 3180
    expect(0, r);

    item.iItem = 0;
    item.pszText = buff;
    item.cchTextMax = sizeof(buff);
3181
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3182
    expect(TRUE, r);
3183
    ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
3184 3185 3186 3187

    item.iItem = 1;
    item.pszText = buff;
    item.cchTextMax = sizeof(buff);
3188
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3189
    expect(TRUE, r);
3190
    ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3191 3192

    item.iItem = 2;
3193
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3194
    expect(TRUE, r);
3195
    ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3196 3197

    item.iItem = 3;
3198
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3199
    expect(TRUE, r);
3200
    ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3201 3202

    item.iItem = 4;
3203
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3204
    expect(TRUE, r);
3205
    ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3206

3207
    DestroyWindow(hwnd);
3208 3209
}

3210 3211
static void test_ownerdata(void)
{
3212 3213
    static char test_str[] = "test";

3214 3215
    HWND hwnd;
    LONG_PTR style, ret;
3216 3217
    DWORD res;
    LVITEMA item;
3218

3219 3220 3221 3222 3223
    /* Setting LVS_OWNERDATA after creation leads to crash on older versions < 5.80 */
    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3224

3225
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
3226

3227 3228 3229 3230
    ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
    ok(ret == style, "Expected set GWL_STYLE to succeed\n");
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
            "try to switch to LVS_OWNERDATA seq", FALSE);
3231

3232 3233 3234
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
    DestroyWindow(hwnd);
3235 3236

    /* try to set LVS_OWNERDATA after creation just having it */
3237
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
    ok(ret == style, "Expected set GWL_STYLE to succeed\n");
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
                "try to switch to LVS_OWNERDATA seq", FALSE);
    DestroyWindow(hwnd);

3250 3251 3252 3253
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3254

3255
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
3256

3257 3258 3259 3260 3261 3262 3263
    ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
    ok(ret == style, "Expected set GWL_STYLE to succeed\n");
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
            "try to switch to LVS_OWNERDATA seq", FALSE);
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
    DestroyWindow(hwnd);
3264 3265

    /* try select an item */
3266
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3267 3268
    ok(hwnd != NULL, "failed to create a listview window\n");
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3269
    expect(1, res);
3270 3271 3272 3273 3274 3275 3276 3277 3278
    res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(0, res);
    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);
    res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(1, res);
3279 3280 3281 3282
    res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
    expect(1, res);
    DestroyWindow(hwnd);

3283
    /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3284
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3285 3286
    ok(hwnd != NULL, "failed to create a listview window\n");
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3287
    expect(1, res);
3288 3289 3290 3291 3292 3293 3294
    res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
    expect(1, res);
    memset(&item, 0, sizeof(item));
    item.mask = LVIF_STATE;
    item.iItem = 0;
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
3295
    res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3296
    expect(FALSE, res);
3297 3298
    memset(&item, 0, sizeof(item));
    item.pszText = test_str;
3299
    res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3300
    expect(FALSE, res);
3301
    DestroyWindow(hwnd);
3302 3303

    /* check notifications after focused/selected changed */
3304
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3305
    ok(hwnd != NULL, "failed to create a listview window\n");
3306
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3307
    expect(1, res);
3308 3309 3310 3311 3312 3313 3314 3315 3316

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);

3317
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3318 3319 3320 3321 3322 3323 3324 3325 3326 3327
                "ownerdata select notification", TRUE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);

3328
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3329
                "ownerdata focus notification", TRUE);
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340

    /* select all, check notifications */
    item.stateMask = LVIS_SELECTED;
    item.state     = 0;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
3341

3342
    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3343 3344
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3345 3346 3347 3348 3349 3350 3351
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3352 3353

    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3354
                "ownerdata select all notification", FALSE);
3355 3356 3357 3358 3359

    /* select all again, note that all items are selected already */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
3360 3361

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3362 3363
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3364 3365 3366 3367 3368 3369 3370 3371
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3372
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3373 3374
                "ownerdata select all notification", FALSE);

3375 3376 3377 3378
    /* deselect all */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_SELECTED;
    item.state     = 0;
3379 3380

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3381 3382
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3383 3384 3385 3386 3387 3388 3389 3390
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3391 3392
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
                "ownerdata deselect all notification", TRUE);
3393

3394 3395 3396 3397 3398 3399 3400 3401
    /* nothing selected, deselect all again */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_SELECTED;
    item.state     = 0;

    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);

3402
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3403

3404 3405 3406 3407 3408 3409 3410 3411
    /* select one, then deselect all */
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_SELECTED;
    item.state     = 0;
3412 3413

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3414 3415
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3416 3417 3418 3419 3420 3421 3422 3423
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3424
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3425
                "ownerdata select all notification", TRUE);
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438

    /* remove focused, try to focus all */
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);
    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
    item.stateMask = LVIS_FOCUSED;
    res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
    expect(0, res);
3439

3440 3441 3442 3443
    /* setting all to focused returns failure value */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
3444

3445
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3446
    expect(FALSE, res);
3447

3448
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3449
                "ownerdata focus all notification", FALSE);
3450

3451 3452 3453
    /* focus single item, remove all */
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
3454
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3455 3456 3457 3458
    expect(TRUE, res);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_FOCUSED;
    item.state     = 0;
3459 3460

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3461 3462
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3463 3464 3465 3466 3467 3468 3469 3470
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3471 3472
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
                "ownerdata remove focus all notification", TRUE);
3473

3474 3475 3476 3477
    /* set all cut */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_CUT;
    item.state     = LVIS_CUT;
3478 3479

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3480 3481
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3482 3483 3484 3485 3486 3487 3488 3489
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3490
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3491 3492
                "ownerdata cut all notification", FALSE);

3493 3494 3495 3496
    /* all marked cut, try again */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    item.stateMask = LVIS_CUT;
    item.state     = LVIS_CUT;
3497 3498

    memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3499 3500
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
    expect(TRUE, res);
3501 3502 3503 3504 3505 3506 3507 3508
    ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
    ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
    ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
    ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
    ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
    ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
    ok(g_nmlistview.lParam == 0, "got wrong lparam\n");

3509
    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3510
                "ownerdata cut all notification #2", FALSE);
3511

3512
    DestroyWindow(hwnd);
3513 3514 3515

    /* check notifications on LVM_GETITEM */
    /* zero callback mask */
3516
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3517 3518
    ok(hwnd != NULL, "failed to create a listview window\n");
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3519
    expect(1, res);
3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_SELECTED;
    item.mask      = LVIF_STATE;
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    expect(TRUE, res);

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "ownerdata getitem selected state 1", FALSE);

    /* non zero callback mask but not we asking for */
    res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_SELECTED;
    item.mask      = LVIF_STATE;
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    expect(TRUE, res);

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "ownerdata getitem selected state 2", FALSE);

    /* LVIS_OVERLAYMASK callback mask, asking for index */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_OVERLAYMASK;
    item.mask      = LVIF_STATE;
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    expect(TRUE, res);

    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
                "ownerdata getitem selected state 2", FALSE);

    DestroyWindow(hwnd);
3560 3561

    /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3562
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3563 3564 3565 3566 3567 3568 3569 3570 3571
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
    ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
    DestroyWindow(hwnd);
    /* apparently it's allowed to switch these style on after creation */
3572
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3573 3574 3575 3576 3577 3578 3579 3580
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
    DestroyWindow(hwnd);

3581
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3582 3583 3584 3585 3586 3587 3588
    ok(hwnd != NULL, "failed to create a listview window\n");
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
    DestroyWindow(hwnd);
3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610

    /* The focused item is updated after the invalidation */
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
    expect(TRUE, res);

    memset(&item, 0, sizeof(item));
    item.stateMask = LVIS_FOCUSED;
    item.state     = LVIS_FOCUSED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
    expect(TRUE, res);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "ownerdata setitemcount", FALSE);

    res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    expect(-1, res);
    DestroyWindow(hwnd);
3611 3612
}

3613 3614 3615 3616 3617
static void test_ownerdata_multiselect(void)
{
    HWND hwnd;
    DWORD res;
    LVITEMA item;
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663
    unsigned int i;
    char buf[256];

    static const struct
    {
        BOOL hold_shift;
        BOOL hold_control;
        UINT press_key;
        UINT selected_count;
        const char *context;
        const struct message *expected;
        BOOL todo;
    }
    key_tests[] =
    {
        /* First down then up */
        { TRUE,  FALSE, VK_DOWN, 2, "select multiple via SHIFT+DOWN",
          ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
        { TRUE,  FALSE, VK_UP,   1, "select one item via SHIFT+UP",
          ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
        { TRUE,  TRUE,  VK_DOWN, 2, "select multiple via SHIFT+CONTROL+DOWN",
          ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
        { TRUE,  TRUE,  VK_UP,   1, "select one item via SHIFT+CONTROL+UP",
          ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
        { FALSE, TRUE,  VK_DOWN, 1, "keep selection but move cursor via CONTROL+DOWN",
          ownerdata_multiselect_move_0_to_1_odstatechanged_seq, FALSE },
        { TRUE,  TRUE,  VK_DOWN, 3, "select multiple after skip via SHIFT+CONTROL+DOWN",
          ownerdata_multiselect_select_0_to_2_odstatechanged_seq, FALSE },
        { FALSE, FALSE, VK_DOWN, 1, "deselect all, select item 3 via DOWN",
          ownerdata_multiselect_select_3_odstatechanged_seq, FALSE },
        /* First up then down */
        { TRUE,  FALSE, VK_UP,   2, "select multiple via SHIFT+UP",
          ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
        { TRUE,  FALSE, VK_DOWN, 1, "select one item via SHIFT+DOWN",
          ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
        { TRUE,  TRUE,  VK_UP,   2, "select multiple via SHIFT+CONTROL+UP",
          ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
        { TRUE,  TRUE,  VK_DOWN, 1, "select one item via SHIFT+CONTROL+DOWN",
          ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
        { FALSE, TRUE,  VK_UP,   1, "keep selection but move cursor via CONTROL+UP",
          ownerdata_multiselect_move_3_to_2_odstatechanged_seq, FALSE },
        { TRUE,  TRUE,  VK_UP,   3, "select multiple after skip via SHIFT+CONTROL+UP",
          ownerdata_multiselect_select_3_to_1_odstatechanged_seq, FALSE },
        { FALSE, FALSE, VK_UP,   1, "deselect all, select item 0 via UP",
          ownerdata_multiselect_select_0_odstatechanged_seq, FALSE },
    };
3664 3665 3666 3667 3668 3669 3670 3671

    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");
    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
    expect(1, res);
    res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(0, res);

3672
    /* Select and focus the first row */
3673 3674 3675 3676 3677 3678 3679 3680 3681 3682
    memset(&item, 0, sizeof(item));
    item.state = LVIS_SELECTED | LVIS_FOCUSED;
    item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    expect(TRUE, res);
    res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(1, res);
    res = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
    expect(0, res);

3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708
    /* Select/deselect rows using UP/DOWN and SHIFT/CONTROL keys */
    for (i = 0; i < ARRAY_SIZE(key_tests); i++)
    {
        flush_sequences(sequences, NUM_MSG_SEQUENCES);

        if (key_tests[i].hold_shift)
            hold_key(VK_SHIFT);
        if (key_tests[i].hold_control)
            hold_key(VK_CONTROL);

        res = SendMessageA(hwnd, WM_KEYDOWN, key_tests[i].press_key, 0);
        expect(0, res);
        sprintf(buf, "ownerdata multiselect: %s", key_tests[i].context);
        ok_sequence(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, key_tests[i].expected,
                    buf, key_tests[i].todo);
        res = SendMessageA(hwnd, WM_KEYUP, key_tests[i].press_key, 0);
        expect(0, res);

        res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
        expect(key_tests[i].selected_count, res);

        if (key_tests[i].hold_shift)
            release_key(VK_SHIFT);
        if (key_tests[i].hold_control)
            release_key(VK_CONTROL);
    }
3709 3710 3711 3712

    DestroyWindow(hwnd);
}

3713 3714 3715 3716 3717 3718 3719 3720 3721
static void test_norecompute(void)
{
    static CHAR testA[] = "test";
    CHAR buff[10];
    LVITEMA item;
    HWND hwnd;
    DWORD res;

    /* self containing control */
3722
    hwnd = create_listview_control(LVS_REPORT);
3723 3724 3725 3726 3727 3728 3729
    ok(hwnd != NULL, "failed to create a listview window\n");
    memset(&item, 0, sizeof(item));
    item.mask = LVIF_TEXT | LVIF_STATE;
    item.iItem = 0;
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    item.pszText   = testA;
3730
    res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3731 3732 3733 3734 3735
    expect(0, res);
    /* retrieve with LVIF_NORECOMPUTE */
    item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
    item.iItem = 0;
    item.pszText    = buff;
3736
    item.cchTextMax = ARRAY_SIZE(buff);
3737
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3738
    expect(TRUE, res);
3739
    ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3740 3741 3742

    item.mask = LVIF_TEXT;
    item.iItem = 1;
3743 3744
    item.pszText = LPSTR_TEXTCALLBACKA;
    res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3745 3746 3747 3748 3749
    expect(1, res);

    item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
    item.iItem = 1;
    item.pszText    = buff;
3750
    item.cchTextMax = ARRAY_SIZE(buff);
3751 3752

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
3753
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3754
    expect(TRUE, res);
3755 3756
    ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
       LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3757
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3758 3759 3760 3761

    DestroyWindow(hwnd);

    /* LVS_OWNERDATA */
3762
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3763 3764 3765 3766 3767 3768
    ok(hwnd != NULL, "failed to create a listview window\n");

    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    item.state     = LVIS_SELECTED;
    item.iItem = 0;
3769
    res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3770 3771 3772 3773 3774
    expect(0, res);

    item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
    item.iItem = 0;
    item.pszText    = buff;
3775
    item.cchTextMax = ARRAY_SIZE(buff);
3776
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
3777
    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3778
    expect(TRUE, res);
3779 3780
    ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
       LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3781
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3782 3783 3784 3785

    DestroyWindow(hwnd);
}

3786 3787 3788 3789 3790
static void test_nosortheader(void)
{
    HWND hwnd, header;
    LONG_PTR style;

3791
    hwnd = create_listview_control(LVS_REPORT);
3792 3793 3794 3795 3796
    ok(hwnd != NULL, "failed to create a listview window\n");

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(IsWindow(header), "header expected\n");

3797
    style = GetWindowLongPtrA(header, GWL_STYLE);
3798 3799
    ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");

3800 3801
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3802
    /* HDS_BUTTONS retained */
3803
    style = GetWindowLongPtrA(header, GWL_STYLE);
3804 3805 3806 3807 3808
    ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");

    DestroyWindow(hwnd);

    /* create with LVS_NOSORTHEADER */
3809
    hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3810 3811 3812 3813 3814
    ok(hwnd != NULL, "failed to create a listview window\n");

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(IsWindow(header), "header expected\n");

3815
    style = GetWindowLongPtrA(header, GWL_STYLE);
3816 3817
    ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");

3818 3819
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3820
    /* not changed here */
3821
    style = GetWindowLongPtrA(header, GWL_STYLE);
3822 3823 3824 3825 3826
    ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");

    DestroyWindow(hwnd);
}

3827 3828 3829 3830 3831
static void test_setredraw(void)
{
    HWND hwnd;
    DWORD_PTR style;
    DWORD ret;
3832
    HDC hdc;
3833
    RECT rect;
3834

3835
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3836 3837 3838 3839 3840 3841
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
       ListView seems to handle it internally without DefWinProc */

    /* default value first */
3842
    ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3843 3844
    expect(0, ret);
    /* disable */
3845
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3846
    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3847
    ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3848
    expect(0, ret);
3849
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3850
    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3851
    ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3852 3853
    expect(0, ret);

3854
    /* check update rect after redrawing */
3855
    ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3856 3857 3858 3859 3860 3861 3862 3863
    expect(0, ret);
    InvalidateRect(hwnd, NULL, FALSE);
    RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
    rect.right = rect.bottom = 1;
    GetUpdateRect(hwnd, &rect, FALSE);
    expect(0, rect.right);
    expect(0, rect.bottom);

3864 3865
    /* WM_ERASEBKGND */
    hdc = GetWindowDC(hwndparent);
3866
    ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3867
    expect(TRUE, ret);
3868
    ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3869
    expect(0, ret);
3870
    ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3871
    expect(TRUE, ret);
3872
    ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3873 3874 3875 3876
    expect(0, ret);
    ReleaseDC(hwndparent, hdc);

    /* check notification messages to show that repainting is disabled */
3877
    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3878
    expect(TRUE, ret);
3879
    ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3880 3881 3882 3883 3884 3885
    expect(0, ret);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3886
                "redraw after WM_SETREDRAW (FALSE)", FALSE);
3887

3888
    ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3889 3890 3891 3892 3893
    expect(TRUE, ret);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3894
                "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3895 3896 3897 3898

    /* message isn't forwarded to header */
    subclass_header(hwnd);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
3899
    ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3900 3901 3902
    expect(0, ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
                "WM_SETREDRAW: not forwarded to header", FALSE);
3903 3904 3905 3906

    DestroyWindow(hwnd);
}

3907 3908 3909 3910 3911 3912 3913 3914
static void test_hittest(void)
{
    HWND hwnd;
    DWORD r;
    RECT bounds;
    LVITEMA item;
    static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
    POINT pos;
3915
    INT x, y, i;
3916
    WORD vert;
3917 3918 3919
    HIMAGELIST himl, himl2;
    HBITMAP hbmp;

3920
    hwnd = create_listview_control(LVS_REPORT);
3921 3922 3923 3924 3925 3926 3927 3928 3929 3930
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* LVS_REPORT with a single subitem (2 columns) */
    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
    insert_item(hwnd, 0);

    item.iSubItem = 0;
    /* the only purpose of that line is to be as long as a half item rect */
    item.pszText  = text;
3931
    r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3932 3933
    expect(TRUE, r);

3934
    r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3935
    expect(TRUE, r);
3936
    r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3937 3938
    expect(TRUE, r);

3939
    SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3940
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3941
    expect(1, r);
3942 3943
    ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
    ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3944
    r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3945 3946
    vert = HIWORD(r);
    ok(bounds.bottom - bounds.top == vert,
3947
        "Vertical spacing inconsistent (%ld != %d)\n", bounds.bottom - bounds.top, vert);
3948
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3949 3950 3951
    expect(TRUE, r);

    /* LVS_EX_FULLROWSELECT not set, no icons attached */
3952 3953 3954 3955 3956 3957 3958

    /* outside columns by x position - valid is [0, 199] */
    x = -1;
    y = pos.y + (bounds.bottom - bounds.top) / 2;
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);

3959 3960
    x = pos.x + 50; /* column half width */
    y = pos.y + (bounds.bottom - bounds.top) / 2;
3961 3962
    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3963 3964
    x = pos.x + 150; /* outside column */
    y = pos.y + (bounds.bottom - bounds.top) / 2;
3965 3966
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3967
    y = (bounds.bottom - bounds.top) / 2;
3968 3969
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3970 3971 3972
    /* outside possible client rectangle (to right) */
    x = pos.x + 500;
    y = pos.y + (bounds.bottom - bounds.top) / 2;
3973 3974
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3975
    y = (bounds.bottom - bounds.top) / 2;
3976 3977
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3978 3979
    /* subitem returned with -1 item too */
    x = pos.x + 150;
3980
    y = bounds.top - vert;
3981
    test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3982 3983 3984 3985 3986 3987 3988 3989 3990 3991
    test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
    /* return values appear to underflow with negative indices */
    i = -2;
    y = y - vert;
    while (i > -10) {
        test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
        test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
        y = y - vert;
        i--;
    }
3992 3993 3994 3995
    /* parent client area is 100x100 by default */
    MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
    x = pos.x + 150; /* outside column */
    y = pos.y + (bounds.bottom - bounds.top) / 2;
3996 3997
    test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3998
    y = (bounds.bottom - bounds.top) / 2;
3999 4000
    test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4001
    /* the same with LVS_EX_FULLROWSELECT */
4002
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
4003 4004
    x = pos.x + 150; /* outside column */
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4005 4006
    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4007
    y = (bounds.bottom - bounds.top) / 2;
4008
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4009 4010 4011
    MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
    x = pos.x + 150; /* outside column */
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4012 4013
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4014
    y = (bounds.bottom - bounds.top) / 2;
4015 4016
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4017 4018 4019
    /* outside possible client rectangle (to right) */
    x = pos.x + 500;
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4020 4021
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4022
    y = (bounds.bottom - bounds.top) / 2;
4023 4024
    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4025
    /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
4026
    himl = pImageList_Create(16, 16, 0, 4, 4);
4027 4028 4029
    ok(himl != NULL, "failed to create imagelist\n");
    hbmp = CreateBitmap(16, 16, 1, 1, NULL);
    ok(hbmp != NULL, "failed to create bitmap\n");
4030
    r = pImageList_Add(himl, hbmp, 0);
4031
    ok(r == 0, "should be zero\n");
4032 4033
    hbmp = CreateBitmap(16, 16, 1, 1, NULL);
    ok(hbmp != NULL, "failed to create bitmap\n");
4034
    r = pImageList_Add(himl, hbmp, 0);
4035
    ok(r == 1, "should be one\n");
4036

4037
    r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4038
    expect(0, r);
4039 4040 4041 4042 4043

    item.mask = LVIF_IMAGE;
    item.iImage = 0;
    item.iItem = 0;
    item.iSubItem = 0;
4044
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4045 4046
    expect(TRUE, r);
    /* on state icon */
4047 4048
    x = pos.x + 8;
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4049 4050
    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4051
    y = (bounds.bottom - bounds.top) / 2;
4052
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4053 4054 4055 4056 4057 4058 4059

    /* state icons indices are 1 based, check with valid index */
    item.mask = LVIF_STATE;
    item.state = INDEXTOSTATEIMAGEMASK(1);
    item.stateMask = LVIS_STATEIMAGEMASK;
    item.iItem = 0;
    item.iSubItem = 0;
4060
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4061 4062 4063
    expect(TRUE, r);
    /* on state icon */
    x = pos.x + 8;
4064
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4065 4066
    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4067
    y = (bounds.bottom - bounds.top) / 2;
4068
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4069

4070
    himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4071 4072
    ok(himl2 == himl, "should return handle\n");

4073
    r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4074
    expect(0, r);
4075
    /* on item icon */
4076
    x = pos.x + 8;
4077
    y = pos.y + (bounds.bottom - bounds.top) / 2;
4078 4079
    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4080
    y = (bounds.bottom - bounds.top) / 2;
4081
    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4082 4083 4084 4085

    DestroyWindow(hwnd);
}

4086 4087 4088 4089 4090 4091 4092
static void test_getviewrect(void)
{
    HWND hwnd;
    DWORD r;
    RECT rect;
    LVITEMA item;

4093
    hwnd = create_listview_control(LVS_REPORT);
4094 4095 4096
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* empty */
4097
    r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4098 4099 4100 4101 4102 4103 4104 4105
    expect(TRUE, r);

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);

    memset(&item, 0, sizeof(item));
    item.iItem = 0;
    item.iSubItem = 0;
4106
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4107
    ok(!r, "got %ld\n", r);
4108

4109
    r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4110
    expect(TRUE, r);
4111
    r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
4112 4113
    expect(TRUE, r);

4114
    SetRect(&rect, -1, -1, -1, -1);
4115
    r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4116 4117 4118 4119 4120 4121 4122
    expect(TRUE, r);
    /* left is set to (2e31-1) - XP SP2 */
    expect(0, rect.right);
    expect(0, rect.top);
    expect(0, rect.bottom);

    /* switch to LVS_ICON */
4123
    SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
4124

4125
    SetRect(&rect, -1, -1, -1, -1);
4126
    r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4127 4128 4129
    expect(TRUE, r);
    expect(0, rect.left);
    expect(0, rect.top);
4130
    /* precise value differs for 2k, XP and Vista */
4131 4132
    ok(rect.bottom > 0, "Expected positive bottom value, got %ld\n", rect.bottom);
    ok(rect.right  > 0, "Expected positive right value, got %ld\n", rect.right);
4133 4134 4135 4136

    DestroyWindow(hwnd);
}

4137 4138 4139 4140 4141 4142 4143
static void test_getitemposition(void)
{
    HWND hwnd, header;
    DWORD r;
    POINT pt;
    RECT rect;

4144
    hwnd = create_listview_control(LVS_REPORT);
4145 4146 4147 4148 4149 4150 4151 4152 4153
    ok(hwnd != NULL, "failed to create a listview window\n");
    header = subclass_header(hwnd);

    /* LVS_REPORT, single item, no columns added */
    insert_item(hwnd, 0);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    pt.x = pt.y = -1;
4154
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4155 4156 4157 4158 4159 4160 4161 4162 4163
    expect(TRUE, r);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);

    /* LVS_REPORT, single item, single column */
    insert_column(hwnd, 0);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    pt.x = pt.y = -1;
4164
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4165 4166 4167
    expect(TRUE, r);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);

4168
    SetRectEmpty(&rect);
4169
    r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
4170
    ok(r, "got %ld\n", r);
4171
    /* some padding? */
4172
    expect(2, pt.x);
4173 4174 4175 4176 4177 4178
    /* offset by header height */
    expect(rect.bottom - rect.top, pt.y);

    DestroyWindow(hwnd);
}

4179 4180 4181
static void test_getitemrect(void)
{
    HWND hwnd;
4182
    HIMAGELIST himl, himl_ret;
4183
    HBITMAP hbm;
4184 4185 4186 4187 4188 4189 4190
    RECT rect;
    DWORD r;
    LVITEMA item;
    LVCOLUMNA col;
    INT order[2];
    POINT pt;

4191
    /* rectangle isn't empty for empty text items */
4192
    hwnd = create_listview_control(LVS_LIST);
4193 4194 4195
    memset(&item, 0, sizeof(item));
    item.mask = 0;
    item.iItem = 0;
4196
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4197 4198
    expect(0, r);
    rect.left = LVIR_LABEL;
4199
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4200
    expect(TRUE, r);
4201 4202
    expect(0, rect.left);
    expect(0, rect.top);
4203
    /* estimate it as width / height ratio */
4204
    todo_wine
4205
    ok((rect.right / rect.bottom) >= 5, "got right %ld, bottom %ld\n", rect.right, rect.bottom);
4206 4207
    DestroyWindow(hwnd);

4208
    hwnd = create_listview_control(LVS_REPORT);
4209 4210 4211 4212 4213 4214
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* empty item */
    memset(&item, 0, sizeof(item));
    item.iItem = 0;
    item.iSubItem = 0;
4215
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4216 4217
    expect(0, r);

4218
    SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4219
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4220 4221
    expect(TRUE, r);

4222
    /* zero width rectangle with no padding */
4223
    expect(0, rect.left);
4224
    expect(0, rect.right);
4225 4226 4227 4228 4229 4230

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);

    col.mask = LVCF_WIDTH;
    col.cx   = 50;
4231
    r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
4232 4233 4234 4235
    expect(TRUE, r);

    col.mask = LVCF_WIDTH;
    col.cx   = 100;
4236
    r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
4237 4238
    expect(TRUE, r);

4239
    SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4240
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4241 4242 4243 4244
    expect(TRUE, r);

    /* still no left padding */
    expect(0, rect.left);
4245
    expect(150, rect.right);
4246

4247
    SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4248
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4249 4250
    expect(TRUE, r);
    /* padding */
4251 4252
    expect(2, rect.left);

4253
    SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4254
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4255 4256 4257 4258 4259 4260
    expect(TRUE, r);
    /* padding, column width */
    expect(2, rect.left);
    expect(50, rect.right);

    /* no icons attached */
4261
    SetRect(&rect, LVIR_ICON, -1, -1, -1);
4262
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4263 4264 4265 4266
    expect(TRUE, r);
    /* padding */
    expect(2, rect.left);
    expect(2, rect.right);
4267 4268 4269

    /* change order */
    order[0] = 1; order[1] = 0;
4270
    r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4271 4272
    expect(TRUE, r);
    pt.x = -1;
4273
    r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4274 4275
    expect(TRUE, r);
    /* 1 indexed column width + padding */
4276
    expect(102, pt.x);
4277
    /* rect is at zero too */
4278
    SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4279
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4280
    expect(TRUE, r);
4281
    expect(0, rect.left);
4282
    /* just width sum */
4283
    expect(150, rect.right);
4284

4285
    SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4286
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4287 4288
    expect(TRUE, r);
    /* column width + padding */
4289
    expect(102, rect.left);
4290

4291 4292
    /* back to initial order */
    order[0] = 0; order[1] = 1;
4293
    r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4294 4295 4296
    expect(TRUE, r);

    /* state icons */
4297
    himl = pImageList_Create(16, 16, 0, 2, 2);
4298 4299 4300
    ok(himl != NULL, "failed to create imagelist\n");
    hbm = CreateBitmap(16, 16, 1, 1, NULL);
    ok(hbm != NULL, "failed to create bitmap\n");
4301
    r = pImageList_Add(himl, hbm, 0);
4302
    expect(0, r);
4303 4304
    hbm = CreateBitmap(16, 16, 1, 1, NULL);
    ok(hbm != NULL, "failed to create bitmap\n");
4305
    r = pImageList_Add(himl, hbm, 0);
4306
    expect(1, r);
4307

4308
    r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4309
    expect(0, r);
4310 4311 4312 4313 4314 4315

    item.mask = LVIF_STATE;
    item.state = INDEXTOSTATEIMAGEMASK(1);
    item.stateMask = LVIS_STATEIMAGEMASK;
    item.iItem = 0;
    item.iSubItem = 0;
4316
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4317 4318 4319
    expect(TRUE, r);

    /* icon bounds */
4320
    SetRect(&rect, LVIR_ICON, -1, -1, -1);
4321
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4322 4323 4324 4325 4326
    expect(TRUE, r);
    /* padding + stateicon width */
    expect(18, rect.left);
    expect(18, rect.right);
    /* label bounds */
4327
    SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4328
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4329 4330 4331 4332 4333
    expect(TRUE, r);
    /* padding + stateicon width -> column width */
    expect(18, rect.left);
    expect(50, rect.right);

4334
    himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4335
    ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4336

4337
    r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4338
    expect(0, r);
4339 4340 4341 4342 4343 4344 4345

    item.mask = LVIF_STATE | LVIF_IMAGE;
    item.iImage = 1;
    item.state = 0;
    item.stateMask = ~0;
    item.iItem = 0;
    item.iSubItem = 0;
4346
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4347 4348 4349
    expect(TRUE, r);

    /* icon bounds */
4350
    SetRect(&rect, LVIR_ICON, -1, -1, -1);
4351
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4352 4353 4354 4355 4356
    expect(TRUE, r);
    /* padding, icon width */
    expect(2, rect.left);
    expect(18, rect.right);
    /* label bounds */
4357
    SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4358
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4359 4360 4361 4362 4363 4364
    expect(TRUE, r);
    /* padding + icon width -> column width */
    expect(18, rect.left);
    expect(50, rect.right);

    /* select bounds */
4365
    SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4366
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4367 4368 4369
    expect(TRUE, r);
    /* padding, column width */
    expect(2, rect.left);
4370
    expect(50, rect.right);
4371 4372 4373 4374 4375 4376

    /* try with indentation */
    item.mask = LVIF_INDENT;
    item.iIndent = 1;
    item.iItem = 0;
    item.iSubItem = 0;
4377
    r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4378 4379 4380
    expect(TRUE, r);

    /* bounds */
4381
    SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4382
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4383 4384 4385 4386 4387 4388
    expect(TRUE, r);
    /* padding + 1 icon width, column width */
    expect(0, rect.left);
    expect(150, rect.right);

    /* select bounds */
4389
    SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4390
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4391 4392 4393
    expect(TRUE, r);
    /* padding + 1 icon width, column width */
    expect(2 + 16, rect.left);
4394
    expect(50, rect.right);
4395 4396

    /* label bounds */
4397
    SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4398
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4399 4400 4401 4402 4403 4404
    expect(TRUE, r);
    /* padding + 2 icon widths, column width */
    expect(2 + 16*2, rect.left);
    expect(50, rect.right);

    /* icon bounds */
4405
    SetRect(&rect, LVIR_ICON, -1, -1, -1);
4406
    r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4407 4408 4409 4410 4411
    expect(TRUE, r);
    /* padding + 1 icon width indentation, icon width */
    expect(2 + 16, rect.left);
    expect(34, rect.right);

4412 4413 4414
    DestroyWindow(hwnd);
}

4415 4416
static void test_editbox(void)
{
4417 4418
    static CHAR testitemA[]  = "testitem";
    static CHAR testitem1A[] = "testitem_quitelongname";
4419
    static CHAR testitem2A[] = "testITEM_quitelongname";
4420 4421
    static CHAR buffer[25];
    HWND hwnd, hwndedit, hwndedit2, header;
4422
    LVITEMA item;
4423
    INT r;
4424

4425
    hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4426 4427 4428 4429 4430 4431 4432 4433 4434
    ok(hwnd != NULL, "failed to create a listview window\n");

    insert_column(hwnd, 0);

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_TEXT;
    item.pszText = testitemA;
    item.iItem = 0;
    item.iSubItem = 0;
4435
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4436 4437
    expect(0, r);

4438 4439
    /* test notifications without edit created */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4440
    r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4441 4442 4443 4444
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
    /* same thing but with valid window */
4445
    hwndedit = CreateWindowA(WC_EDITA, "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4446 4447
                10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4448
    r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4449 4450 4451 4452 4453
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
    DestroyWindow(hwndedit);

4454 4455
    /* setting focus is necessary */
    SetFocus(hwnd);
4456
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4457 4458
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");

4459 4460 4461 4462 4463 4464
    /* test children Z-order after Edit box created */
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(IsWindow(header), "Expected header to be created\n");
    ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
    ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));

4465
    /* modify initial string */
4466
    r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4467
    expect(TRUE, r);
4468 4469 4470 4471 4472 4473

    /* edit window is resized and repositioned,
       check again for Z-order - it should be preserved */
    ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
    ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));

4474 4475 4476 4477 4478 4479
    /* return focus to listview */
    SetFocus(hwnd);

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_TEXT;
    item.pszText = buffer;
4480
    item.cchTextMax = sizeof(buffer);
4481 4482
    item.iItem = 0;
    item.iSubItem = 0;
4483
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4484 4485 4486 4487
    expect(TRUE, r);

    ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");

4488 4489
    /* send LVM_EDITLABEL on already created edit */
    SetFocus(hwnd);
4490
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4491 4492 4493
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    /* focus will be set to edit */
    ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4494
    hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4495 4496
    ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");

4497 4498
    /* creating label disabled when control isn't focused */
    SetFocus(0);
4499
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4500
    todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4501

4502 4503 4504 4505 4506
    /* check EN_KILLFOCUS handling */
    memset(&item, 0, sizeof(item));
    item.pszText = testitemA;
    item.iItem = 0;
    item.iSubItem = 0;
4507
    r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4508 4509 4510
    expect(TRUE, r);

    SetFocus(hwnd);
4511
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4512 4513
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    /* modify edit and notify control that it lost focus */
4514
    r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4515
    expect(TRUE, r);
4516
    g_editbox_disp_info.item.pszText = NULL;
4517
    r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4518
    expect(0, r);
4519 4520
    ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");

4521 4522
    memset(&item, 0, sizeof(item));
    item.pszText = buffer;
4523
    item.cchTextMax = sizeof(buffer);
4524 4525
    item.iItem = 0;
    item.iSubItem = 0;
4526 4527
    r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
    expect(lstrlenA(item.pszText), r);
4528
    ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4529
    ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4530 4531 4532

    /* change item name to differ in casing only */
    SetFocus(hwnd);
4533
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4534 4535
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    /* modify edit and notify control that it lost focus */
4536
    r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4537 4538
    expect(TRUE, r);
    g_editbox_disp_info.item.pszText = NULL;
4539
    r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4540 4541 4542 4543 4544 4545 4546 4547
    expect(0, r);
    ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);

    memset(&item, 0, sizeof(item));
    item.pszText = buffer;
    item.cchTextMax = sizeof(buffer);
    item.iItem = 0;
    item.iSubItem = 0;
4548 4549
    r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
    expect(lstrlenA(item.pszText), r);
4550 4551 4552
    ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
    ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");

4553
    /* end edit without saving */
4554
    SetFocus(hwnd);
4555
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4556
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4557
    r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4558
    expect(0, r);
4559 4560 4561 4562
    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
                "edit box - end edit, no change, escape", TRUE);
    /* end edit with saving */
    SetFocus(hwnd);
4563
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4564
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4565
    r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4566 4567 4568 4569
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
                "edit box - end edit, no change, return", TRUE);

4570 4571
    memset(&item, 0, sizeof(item));
    item.pszText = buffer;
4572
    item.cchTextMax = sizeof(buffer);
4573 4574
    item.iItem = 0;
    item.iSubItem = 0;
4575 4576
    r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
    expect(lstrlenA(item.pszText), r);
4577
    ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4578

4579
    /* LVM_EDITLABEL with -1 destroys current edit */
4580
    hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4581 4582
    ok(hwndedit == NULL, "Expected Edit window not to be created\n");
    /* no edit present */
4583
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4584
    ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4585
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4586 4587 4588
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    /* edit present */
    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4589
    hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4590 4591 4592 4593
    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
    ok(GetFocus() == hwnd, "Expected List to be focused\n");
    /* check another negative value */
4594
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4595 4596
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4597
    hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4598 4599 4600
    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
    ok(GetFocus() == hwnd, "Expected List to be focused\n");
4601
    /* and value greater than max item index */
4602
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4603 4604
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4605 4606
    r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
    hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4607 4608 4609 4610
    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
    ok(GetFocus() == hwnd, "Expected List to be focused\n");

4611 4612 4613 4614
    /* messaging tests */
    SetFocus(hwnd);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    blockEdit = FALSE;
4615
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4616 4617 4618
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    /* testing only sizing messages */
    ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4619
                "edit box create - sizing", FALSE);
4620

4621
    /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4622
    SetFocus(hwnd);
4623
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4624 4625
    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4626
    r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4627 4628 4629 4630
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
                "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);

4631 4632 4633
    DestroyWindow(hwnd);
}

4634 4635
static void test_notifyformat(void)
{
4636
    HWND hwnd, header;
4637 4638
    DWORD r;

4639
    hwnd = create_listview_control(LVS_REPORT);
4640 4641 4642 4643
    ok(hwnd != NULL, "failed to create a listview window\n");

    /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
       CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4644
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4645
    expect(0, r);
4646
    SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4647
    /* set */
4648
    r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4649
    expect(0, r);
4650
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4651
    ok(r == 1, "Unexpected return value %ld.\n", r);
4652 4653 4654 4655
    r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
    expect(1, r);
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(0, r);
4656 4657 4658 4659 4660

    DestroyWindow(hwnd);

    /* test failure in parent WM_NOTIFYFORMAT  */
    notifyFormat = 0;
4661
    hwnd = create_listview_control(LVS_REPORT);
4662
    ok(hwnd != NULL, "failed to create a listview window\n");
4663
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4664
    ok(IsWindow(header), "expected header to be created\n");
4665
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4666
    expect(0, r);
4667
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4668
    ok( r == 1, "Expected 1, got %ld\n", r );
4669
    r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4670 4671 4672
    ok(r != 0, "Expected valid format\n");

    notifyFormat = NFR_UNICODE;
4673
    r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4674
    expect(NFR_UNICODE, r);
4675
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4676
    expect(1, r);
4677
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4678
    ok( r == 1, "Expected 1, got %ld\n", r );
4679 4680

    notifyFormat = NFR_ANSI;
4681
    r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4682
    expect(NFR_ANSI, r);
4683
    r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4684
    expect(0, r);
4685
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4686
    ok( r == 1, "Expected 1, got %ld\n", r );
4687 4688 4689 4690 4691 4692 4693 4694

    DestroyWindow(hwnd);

    hwndparentW = create_parent_window(TRUE);
    ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
    if (!IsWindow(hwndparentW))  return;

    notifyFormat = -1;
4695
    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4696
    ok(hwnd != NULL, "failed to create a listview window\n");
4697
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4698
    ok(IsWindow(header), "expected header to be created\n");
4699 4700
    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(1, r);
4701
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4702
    expect(1, r);
4703
    DestroyWindow(hwnd);
4704
    /* receiving error code defaulting to ansi */
4705
    notifyFormat = 0;
4706
    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4707
    ok(hwnd != NULL, "failed to create a listview window\n");
4708
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4709
    ok(IsWindow(header), "expected header to be created\n");
4710 4711
    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(0, r);
4712
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4713
    expect(1, r);
4714
    DestroyWindow(hwnd);
4715
    /* receiving ansi code from unicode window, use it */
4716
    notifyFormat = NFR_ANSI;
4717
    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4718
    ok(hwnd != NULL, "failed to create a listview window\n");
4719
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4720
    ok(IsWindow(header), "expected header to be created\n");
4721 4722
    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(0, r);
4723
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4724
    expect(1, r);
4725 4726 4727
    DestroyWindow(hwnd);
    /* unicode listview with ansi parent window */
    notifyFormat = -1;
4728
    hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4729
    ok(hwnd != NULL, "failed to create a listview window\n");
4730
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4731
    ok(IsWindow(header), "expected header to be created\n");
4732 4733
    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(0, r);
4734
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4735
    expect(1, r);
4736 4737 4738
    DestroyWindow(hwnd);
    /* unicode listview with ansi parent window, return error code */
    notifyFormat = 0;
4739
    hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4740
    ok(hwnd != NULL, "failed to create a listview window\n");
4741
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4742
    ok(IsWindow(header), "expected header to be created\n");
4743 4744
    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
    expect(0, r);
4745
    r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4746
    expect(1, r);
4747 4748 4749 4750 4751
    DestroyWindow(hwnd);

    DestroyWindow(hwndparentW);
}

4752 4753 4754 4755 4756 4757
static void test_indentation(void)
{
    HWND hwnd;
    LVITEMA item;
    DWORD r;

4758
    hwnd = create_listview_control(LVS_REPORT);
4759 4760 4761 4762 4763 4764
    ok(hwnd != NULL, "failed to create a listview window\n");

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_INDENT;
    item.iItem = 0;
    item.iIndent = I_INDENTCALLBACK;
4765
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4766 4767 4768 4769 4770 4771
    expect(0, r);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    item.iItem = 0;
    item.mask = LVIF_INDENT;
4772
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4773 4774 4775
    expect(TRUE, r);

    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4776
                "get indent dispinfo", FALSE);
4777

4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788
    /* Ask for iIndent with invalid subitem. */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_INDENT;
    item.iSubItem = 1;
    r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(r, "Failed to get item.\n");

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get indent dispinfo 2", FALSE);

4789 4790 4791
    DestroyWindow(hwnd);
}

4792 4793 4794 4795 4796 4797 4798
static void test_get_set_view(void)
{
    HWND hwnd;
    DWORD ret;
    DWORD_PTR style;

    /* test style->view mapping */
4799
    hwnd = create_listview_control(LVS_REPORT);
4800 4801
    ok(hwnd != NULL, "failed to create a listview window\n");

4802
    ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4803 4804
    expect(LV_VIEW_DETAILS, ret);

4805
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4806
    /* LVS_ICON == 0 */
4807 4808
    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
    ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4809 4810
    expect(LV_VIEW_ICON, ret);

4811 4812 4813
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
    ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4814 4815
    expect(LV_VIEW_SMALLICON, ret);

4816 4817 4818
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
    ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4819 4820 4821
    expect(LV_VIEW_LIST, ret);

    /* switching view doesn't touch window style */
4822
    ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4823
    expect(1, ret);
4824
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4825
    ok(style & LVS_LIST, "Expected style to be preserved\n");
4826
    ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4827
    expect(1, ret);
4828
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4829
    ok(style & LVS_LIST, "Expected style to be preserved\n");
4830
    ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4831
    expect(1, ret);
4832
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4833 4834
    ok(style & LVS_LIST, "Expected style to be preserved\n");

4835 4836 4837 4838 4839 4840
    /* now change window style to see if view is remapped */
    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
    ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
    expect(LV_VIEW_SMALLICON, ret);

4841 4842 4843
    DestroyWindow(hwnd);
}

4844 4845 4846 4847 4848 4849 4850 4851 4852
static void test_canceleditlabel(void)
{
    HWND hwnd, hwndedit;
    DWORD ret;
    CHAR buff[10];
    LVITEMA itema;
    static CHAR test[] = "test";
    static const CHAR test1[] = "test1";

4853
    hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4854 4855 4856 4857 4858
    ok(hwnd != NULL, "failed to create a listview window\n");

    insert_item(hwnd, 0);

    /* try without edit created */
4859
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
4860
    ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4861
    expect(TRUE, ret);
4862 4863
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "cancel edit label without edit", FALSE);
4864 4865 4866

    /* cancel without data change */
    SetFocus(hwnd);
4867
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4868
    ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4869
    ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4870 4871 4872 4873 4874 4875
    expect(TRUE, ret);
    ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");

    /* cancel after data change */
    memset(&itema, 0, sizeof(itema));
    itema.pszText = test;
4876
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4877 4878
    expect(TRUE, ret);
    SetFocus(hwnd);
4879
    hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4880
    ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4881
    ret = SetWindowTextA(hwndedit, test1);
4882
    expect(1, ret);
4883
    ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4884 4885 4886 4887
    expect(TRUE, ret);
    ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
    memset(&itema, 0, sizeof(itema));
    itema.pszText = buff;
4888
    itema.cchTextMax = ARRAY_SIZE(buff);
4889
    ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4890 4891 4892 4893 4894 4895
    expect(5, ret);
    ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");

    DestroyWindow(hwnd);
}

4896 4897 4898
static void test_mapidindex(void)
{
    HWND hwnd;
4899
    INT ret;
4900

4901
    /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4902
    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4903 4904
    ok(hwnd != NULL, "failed to create a listview window\n");
    insert_item(hwnd, 0);
4905
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4906 4907 4908
    expect(-1, ret);
    DestroyWindow(hwnd);

4909
    hwnd = create_listview_control(LVS_REPORT);
4910 4911
    ok(hwnd != NULL, "failed to create a listview window\n");

4912
    /* LVM_MAPINDEXTOID with invalid index */
4913
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4914 4915
    expect(-1, ret);

4916 4917 4918
    insert_item(hwnd, 0);
    insert_item(hwnd, 1);

4919
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4920
    expect(-1, ret);
4921
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4922 4923
    expect(-1, ret);

4924
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4925
    expect(0, ret);
4926
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4927
    expect(1, ret);
4928
    /* remove 0 indexed item, id retained */
4929 4930
    SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4931
    expect(1, ret);
4932 4933
    /* new id starts from previous value */
    insert_item(hwnd, 1);
4934
    ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4935 4936 4937
    expect(2, ret);

    /* get index by id */
4938
    ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4939
    expect(-1, ret);
4940
    ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4941
    expect(-1, ret);
4942
    ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4943
    expect(0, ret);
4944
    ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4945
    expect(1, ret);
4946 4947 4948 4949

    DestroyWindow(hwnd);
}

4950 4951 4952 4953 4954
static void test_getitemspacing(void)
{
    HWND hwnd;
    DWORD ret;
    INT cx, cy;
4955
    HIMAGELIST himl40, himl80;
4956 4957 4958 4959 4960

    cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
    cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);

    /* LVS_ICON */
4961
    hwnd = create_listview_control(LVS_ICON);
4962
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4963 4964
    expect(cx, LOWORD(ret));
    expect(cy, HIWORD(ret));
4965

4966
    /* now try with icons */
4967
    himl40 = pImageList_Create(40, 40, 0, 4, 4);
4968
    ok(himl40 != NULL, "failed to create imagelist\n");
4969
    himl80 = pImageList_Create(80, 80, 0, 4, 4);
4970
    ok(himl80 != NULL, "failed to create imagelist\n");
4971
    ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4972 4973
    expect(0, ret);

4974
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4975 4976 4977
    /* spacing + icon size returned */
    expect(cx + 40, LOWORD(ret));
    expect(cy + 40, HIWORD(ret));
4978
    /* try changing icon size */
4979
    SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4980

4981
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4982 4983 4984 4985 4986
    /* spacing + icon size returned */
    expect(cx + 80, LOWORD(ret));
    expect(cy + 80, HIWORD(ret));

    /* set own icon spacing */
4987
    ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4988 4989 4990
    expect(cx + 80, LOWORD(ret));
    expect(cy + 80, HIWORD(ret));

4991
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4992 4993 4994 4995 4996
    /* set size returned */
    expect(100, LOWORD(ret));
    expect(100, HIWORD(ret));

    /* now change image list - icon spacing should be unaffected */
4997
    SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4998

4999
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5000 5001 5002 5003 5004
    /* set size returned */
    expect(100, LOWORD(ret));
    expect(100, HIWORD(ret));

    /* spacing = 0 - keep previous value */
5005
    ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
5006 5007 5008
    expect(100, LOWORD(ret));
    expect(100, HIWORD(ret));

5009
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5010 5011 5012
    expect(100, LOWORD(ret));

    expect(0xFFFF, HIWORD(ret));
5013 5014 5015 5016

    if (sizeof(void*) == 8)
    {
        /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
5017
        ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
5018 5019 5020
        expect(100, LOWORD(ret));
        expect(0xFFFF, HIWORD(ret));

5021
        ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5022 5023 5024 5025 5026
        expect(0xFFFF, LOWORD(ret));
        expect(0xFFFF, HIWORD(ret));
    }
    else
    {
5027
        ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5028 5029 5030
        expect(100, LOWORD(ret));
        expect(0xFFFF, HIWORD(ret));
    }
5031
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5032 5033 5034 5035
    /* spacing + icon size returned */
    expect(cx + 40, LOWORD(ret));
    expect(cy + 40, HIWORD(ret));

5036
    SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5037
    pImageList_Destroy(himl80);
5038 5039
    DestroyWindow(hwnd);
    /* LVS_SMALLICON */
5040
    hwnd = create_listview_control(LVS_SMALLICON);
5041
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5042 5043
    expect(cx, LOWORD(ret));
    expect(cy, HIWORD(ret));
5044

5045
    /* spacing does not depend on selected view type */
5046
    ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
5047 5048
    expect(0, ret);

5049
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5050 5051 5052 5053
    /* spacing + icon size returned */
    expect(cx + 40, LOWORD(ret));
    expect(cy + 40, HIWORD(ret));

5054
    SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5055
    pImageList_Destroy(himl40);
5056 5057
    DestroyWindow(hwnd);
    /* LVS_REPORT */
5058
    hwnd = create_listview_control(LVS_REPORT);
5059
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5060 5061
    expect(cx, LOWORD(ret));
    expect(cy, HIWORD(ret));
5062

5063 5064
    DestroyWindow(hwnd);
    /* LVS_LIST */
5065
    hwnd = create_listview_control(LVS_LIST);
5066
    ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5067 5068
    expect(cx, LOWORD(ret));
    expect(cy, HIWORD(ret));
5069

5070 5071 5072
    DestroyWindow(hwnd);
}

5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102
static INT get_current_font_height(HWND listview)
{
    TEXTMETRICA tm;
    HFONT hfont;
    HWND hwnd;
    HDC hdc;

    hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
    if (!hwnd)
        hwnd = listview;

    hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
    if (!hfont) {
        hdc = GetDC(hwnd);
        GetTextMetricsA(hdc, &tm);
        ReleaseDC(hwnd, hdc);
    }
    else {
        HFONT oldfont;

        hdc = GetDC(0);
        oldfont = SelectObject(hdc, hfont);
        GetTextMetricsA(hdc, &tm);
        SelectObject(hdc, oldfont);
        ReleaseDC(0, hdc);
    }

    return tm.tmHeight;
}

5103 5104 5105
static void test_getcolumnwidth(void)
{
    HWND hwnd;
5106
    INT ret;
5107 5108
    DWORD_PTR style;
    LVCOLUMNA col;
5109
    LVITEMA itema;
5110
    INT height;
5111 5112

    /* default column width */
5113
    hwnd = create_listview_control(LVS_ICON);
5114
    ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5115
    expect(0, ret);
5116 5117 5118
    style = GetWindowLongA(hwnd, GWL_STYLE);
    SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
    ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5119
    todo_wine expect(8, ret);
5120 5121
    style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
    SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
5122
    col.mask = 0;
5123
    ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5124
    expect(0, ret);
5125
    ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5126 5127
    expect(10, ret);
    DestroyWindow(hwnd);
5128 5129

    /* default column width with item added */
5130
    hwnd = create_listview_control(LVS_LIST);
5131
    memset(&itema, 0, sizeof(itema));
5132 5133
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
    ok(!ret, "got %d\n", ret);
5134
    ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5135 5136
    height = get_current_font_height(hwnd);
    ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
5137
    DestroyWindow(hwnd);
5138 5139
}

5140 5141 5142 5143 5144
static void test_scrollnotify(void)
{
    HWND hwnd;
    DWORD ret;

5145
    hwnd = create_listview_control(LVS_REPORT);
5146 5147 5148 5149 5150 5151

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
    insert_item(hwnd, 0);

    /* make it scrollable - resize */
5152
    ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
5153
    expect(TRUE, ret);
5154
    ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
5155 5156 5157 5158
    expect(TRUE, ret);

    /* try with dummy call */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
5159
    ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
5160 5161 5162 5163 5164
    expect(TRUE, ret);
    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
                "scroll notify 1", TRUE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
5165
    ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
5166 5167 5168 5169 5170
    expect(TRUE, ret);
    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
                "scroll notify 2", TRUE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
5171
    ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
5172 5173 5174 5175 5176 5177 5178
    expect(TRUE, ret);
    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
                "scroll notify 3", TRUE);

    DestroyWindow(hwnd);
}

5179 5180 5181 5182 5183 5184
static void test_LVS_EX_TRANSPARENTBKGND(void)
{
    HWND hwnd;
    DWORD ret;
    HDC hdc;

5185
    hwnd = create_listview_control(LVS_REPORT);
5186

5187
    ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5188 5189
    expect(TRUE, ret);

5190
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5191 5192
                                                    LVS_EX_TRANSPARENTBKGND);

5193
    ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
5194 5195 5196 5197 5198 5199 5200 5201
    if (ret != CLR_NONE)
    {
        win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
        DestroyWindow(hwnd);
        return;
    }

    /* try to set some back color and check this style bit */
5202
    ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5203
    expect(TRUE, ret);
5204
    ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
5205 5206 5207
    ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");

    /* now test what this style actually does */
5208
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222
                                                    LVS_EX_TRANSPARENTBKGND);

    hdc = GetWindowDC(hwndparent);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
    ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
                "LVS_EX_TRANSPARENTBKGND parent", FALSE);

    ReleaseDC(hwndparent, hdc);

    DestroyWindow(hwnd);
}

5223
static void test_approximate_viewrect(void)
5224
{
5225 5226 5227 5228 5229
    static CHAR test[] = "abracadabra, a very long item label";
    DWORD item_width, item_height, header_height;
    static CHAR column_header[] = "Header";
    unsigned const column_width = 100;
    DWORD ret, item_count;
5230 5231
    HIMAGELIST himl;
    LVITEMA itema;
5232 5233 5234
    LVCOLUMNA col;
    HBITMAP hbmp;
    HWND hwnd;
5235

5236
    /* LVS_ICON */
5237
    hwnd = create_listview_control(LVS_ICON);
5238
    himl = pImageList_Create(40, 40, 0, 4, 4);
5239 5240 5241
    ok(himl != NULL, "failed to create imagelist\n");
    hbmp = CreateBitmap(40, 40, 1, 1, NULL);
    ok(hbmp != NULL, "failed to create bitmap\n");
5242
    ret = pImageList_Add(himl, hbmp, 0);
5243
    expect(0, ret);
5244
    ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
5245 5246 5247 5248 5249 5250
    expect(0, ret);

    itema.mask = LVIF_IMAGE;
    itema.iImage = 0;
    itema.iItem = 0;
    itema.iSubItem = 0;
5251
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5252 5253
    expect(0, ret);

5254
    ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
5255
    ok(ret != 0, "Unexpected return value %#lx.\n", ret);
5256

5257
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5258
    expect(MAKELONG(77,827), ret);
5259

5260
    ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5261 5262
    ok(ret != 0, "got 0\n");

5263
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5264
    expect(MAKELONG(102,302), ret);
5265

5266
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5267
    expect(MAKELONG(52,52), ret);
5268 5269

    itema.pszText = test;
5270
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5271
    expect(TRUE, ret);
5272
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5273
    expect(MAKELONG(52,52), ret);
5274

5275
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5276
    expect(MAKELONG(52,2), ret);
5277
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5278
    expect(MAKELONG(52,52), ret);
5279
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5280
    expect(MAKELONG(102,52), ret);
5281
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5282
    expect(MAKELONG(102,102), ret);
5283
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5284
    expect(MAKELONG(102,102), ret);
5285
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5286
    expect(MAKELONG(102,152), ret);
5287
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5288
    expect(MAKELONG(102,152), ret);
5289
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5290
    expect(MAKELONG(152,152), ret);
5291 5292

    DestroyWindow(hwnd);
5293 5294 5295 5296 5297 5298

    /* LVS_REPORT */
    hwnd = create_listview_control(LVS_REPORT);

    /* Empty control without columns */
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
5299
    todo_wine
5300 5301 5302 5303 5304
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5305
    todo_wine
5306 5307 5308 5309 5310 5311
    ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));

    header_height = HIWORD(ret);

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5312
    todo_wine
5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332
    ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));

    item_height = HIWORD(ret) - header_height;

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == header_height, "Unexpected height.\n");
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
    ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

    /* Insert column */
    col.mask = LVCF_TEXT | LVCF_WIDTH;
    col.pszText = column_header;
    col.cx = column_width;
    ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5333
    ok(ret == 0, "Unexpected return value %ld.\n", ret);
5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345

    /* Empty control with column */
    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
todo_wine {
    ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
}
    header_height = HIWORD(ret);
    item_width = LOWORD(ret);

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
    ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5346
    todo_wine
5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369
    ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));

    item_height = HIWORD(ret) - header_height;

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
    ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
    ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));

    ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
    ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
    ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

    for (item_count = 1; item_count <= 2; ++item_count)
    {
        itema.mask = LVIF_TEXT;
        itema.iItem = 0;
        itema.iSubItem = 0;
        itema.pszText = test;
        ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5370
        ok(ret == 0, "Unexpected return value %ld.\n", ret);
5371 5372 5373

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
        ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5374
        todo_wine
5375 5376 5377 5378 5379 5380
        ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));

        header_height = HIWORD(ret);
        item_width = LOWORD(ret);

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5381 5382
        ok(LOWORD(ret) == item_width, "Unexpected width %d, item %ld\n", LOWORD(ret), item_count - 1);
        ok(HIWORD(ret) > header_height, "Unexpected height %d. item %ld.\n", HIWORD(ret),  item_count - 1);
5383 5384 5385 5386 5387

        item_height = HIWORD(ret) - header_height;

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5388
        todo_wine
5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404
        ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
        ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
        ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
        ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5405
        todo_wine
5406 5407 5408 5409
        ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));

        ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
        ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5410
        todo_wine
5411 5412 5413 5414 5415
        ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
    }

    DestroyWindow(hwnd);

5416 5417
}

5418 5419 5420 5421 5422
static void test_finditem(void)
{
    LVFINDINFOA fi;
    static char f[5];
    HWND hwnd;
5423
    INT r;
5424

5425
    hwnd = create_listview_control(LVS_REPORT);
5426 5427 5428 5429 5430 5431 5432 5433
    insert_item(hwnd, 0);

    memset(&fi, 0, sizeof(fi));

    /* full string search, inserted text was "foo" */
    strcpy(f, "foo");
    fi.flags = LVFI_STRING;
    fi.psz = f;
5434
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5435
    expect(0, r);
5436 5437 5438 5439 5440 5441 5442 5443 5444

    fi.flags = LVFI_STRING | LVFI_PARTIAL;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(0, r);

    fi.flags = LVFI_PARTIAL;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(0, r);

5445 5446 5447 5448
    /* partial string search, inserted text was "foo" */
    strcpy(f, "fo");
    fi.flags = LVFI_STRING | LVFI_PARTIAL;
    fi.psz = f;
5449
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5450
    expect(0, r);
5451 5452 5453 5454 5455 5456 5457 5458 5459

    fi.flags = LVFI_STRING;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(-1, r);

    fi.flags = LVFI_PARTIAL;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(0, r);

5460 5461 5462 5463
    /* partial string search, part after start char */
    strcpy(f, "oo");
    fi.flags = LVFI_STRING | LVFI_PARTIAL;
    fi.psz = f;
5464
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5465 5466
    expect(-1, r);

5467 5468 5469 5470
    /* try with LVFI_SUBSTRING */
    strcpy(f, "fo");
    fi.flags = LVFI_SUBSTRING;
    fi.psz = f;
5471
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5472 5473 5474 5475
    expect(0, r);
    strcpy(f, "f");
    fi.flags = LVFI_SUBSTRING;
    fi.psz = f;
5476
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5477 5478 5479 5480
    expect(0, r);
    strcpy(f, "o");
    fi.flags = LVFI_SUBSTRING;
    fi.psz = f;
5481
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5482 5483
    expect(-1, r);

5484 5485 5486 5487 5488 5489
    strcpy(f, "o");
    fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
    fi.psz = f;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(-1, r);

5490 5491 5492
    strcpy(f, "f");
    fi.flags = LVFI_SUBSTRING | LVFI_STRING;
    fi.psz = f;
5493 5494 5495 5496
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    expect(0, r);

    fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5497
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5498 5499
    expect(0, r);

5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512
    /* Case sensitivity. */
    strcpy(f, "Foo");
    fi.flags = LVFI_STRING;
    fi.psz = f;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    ok(!r, "Unexpected item index %d.\n", r);

    strcpy(f, "F");
    fi.flags = LVFI_SUBSTRING;
    fi.psz = f;
    r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
    ok(!r, "Unexpected item index %d.\n", r);

5513 5514 5515
    DestroyWindow(hwnd);
}

5516 5517 5518 5519 5520
static void test_LVS_EX_HEADERINALLVIEWS(void)
{
    HWND hwnd, header;
    DWORD style;

5521
    hwnd = create_listview_control(LVS_ICON);
5522

5523
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5524 5525
                                                    LVS_EX_HEADERINALLVIEWS);

5526
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544
    if (!IsWindow(header))
    {
        win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
        DestroyWindow(hwnd);
        return;
    }

    /* LVS_NOCOLUMNHEADER works as before */
    style = GetWindowLongA(hwnd, GWL_STYLE);
    SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
    style = GetWindowLongA(header, GWL_STYLE);
    ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
    style = GetWindowLongA(hwnd, GWL_STYLE);
    SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
    style = GetWindowLongA(header, GWL_STYLE);
    ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");

    /* try to remove style */
5545 5546
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5547 5548 5549 5550 5551 5552 5553
    ok(IsWindow(header), "Expected header to be created\n");
    style = GetWindowLongA(header, GWL_STYLE);
    ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");

    DestroyWindow(hwnd);

    /* check other styles */
5554
    hwnd = create_listview_control(LVS_LIST);
5555
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5556
                                                    LVS_EX_HEADERINALLVIEWS);
5557
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5558 5559 5560
    ok(IsWindow(header), "Expected header to be created\n");
    DestroyWindow(hwnd);

5561
    hwnd = create_listview_control(LVS_SMALLICON);
5562
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5563
                                                    LVS_EX_HEADERINALLVIEWS);
5564
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5565 5566 5567
    ok(IsWindow(header), "Expected header to be created\n");
    DestroyWindow(hwnd);

5568
    hwnd = create_listview_control(LVS_REPORT);
5569
    SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5570
                                                    LVS_EX_HEADERINALLVIEWS);
5571
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5572 5573 5574 5575
    ok(IsWindow(header), "Expected header to be created\n");
    DestroyWindow(hwnd);
}

5576 5577
static void test_hover(void)
{
5578
    HWND hwnd, fg;
5579 5580
    DWORD r;

5581
    hwnd = create_listview_control(LVS_ICON);
5582 5583 5584 5585 5586 5587 5588 5589
    SetForegroundWindow(hwndparent);
    fg = GetForegroundWindow();
    if (fg != hwndparent)
    {
        skip("Window is not in the foreground. Skipping hover tests.\n");
        DestroyWindow(hwnd);
        return;
    }
5590 5591 5592

    /* test WM_MOUSEHOVER forwarding */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
5593
    r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5594 5595 5596 5597
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
    g_block_hover = TRUE;
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
5598
    r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5599 5600 5601 5602
    expect(0, r);
    ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
    g_block_hover = FALSE;

5603
    r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5604
    expect(HOVER_DEFAULT, r);
5605
    r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5606 5607
    expect(500, r);

5608 5609 5610
    DestroyWindow(hwnd);
}

5611 5612 5613
static void test_destroynotify(void)
{
    HWND hwnd;
5614
    BOOL ret;
5615 5616 5617 5618 5619 5620 5621

    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "failed to create listview window\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
    ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638

    /* same for ownerdata list */
    hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
    ok(hwnd != NULL, "failed to create listview window\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    DestroyWindow(hwnd);
    ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);

    hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
    ok(hwnd != NULL, "failed to create listview window\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
    ok(ret == TRUE, "got %d\n", ret);
    ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
    DestroyWindow(hwnd);
5639 5640
}

5641 5642
static void test_header_notification(void)
{
5643
    static char textA[] = "newtext";
5644 5645
    HWND list, header;
    HDITEMA item;
5646
    NMHEADERA nmh;
5647
    LVCOLUMNA col;
5648
    DWORD ret;
5649
    BOOL r;
5650 5651

    list = create_listview_control(LVS_REPORT);
5652
    ok(list != NULL, "failed to create listview window\n");
5653 5654 5655 5656

    memset(&col, 0, sizeof(col));
    col.mask = LVCF_WIDTH;
    col.cx = 100;
5657
    ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5658
    expect(0, ret);
5659

5660 5661 5662 5663 5664 5665 5666
    /* check list parent notification after header item changed,
       this test should be placed before header subclassing to avoid
       Listview -> Header messages to be logged */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    col.mask = LVCF_TEXT;
    col.pszText = textA;
5667
    r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5668
    expect(TRUE, r);
5669 5670 5671 5672 5673 5674

    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
                "header notify, listview", FALSE);
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);

5675 5676
    header = subclass_header(list);

5677
    ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5678
    expect(1, ret);
5679

5680 5681
    memset(&item, 0, sizeof(item));
    item.mask = HDI_WIDTH;
5682
    ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5683 5684
    expect(1, ret);
    expect(100, item.cxy);
5685 5686

    nmh.hdr.hwndFrom = header;
5687
    nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5688 5689 5690 5691 5692 5693
    nmh.hdr.code = HDN_ITEMCHANGEDA;
    nmh.iItem = 0;
    nmh.iButton = 0;
    item.mask = HDI_WIDTH;
    item.cxy = 50;
    nmh.pitem = &item;
5694
    ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5695
    expect(0, ret);
5696 5697 5698 5699

    DestroyWindow(list);
}

5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720
static void test_header_notification2(void)
{
    static char textA[] = "newtext";
    HWND list, header;
    HDITEMW itemW;
    NMHEADERW nmhdr;
    LVCOLUMNA col;
    DWORD ret;
    WCHAR buffer[100];
    struct message parent_header_notify_seq[] = {
        { WM_NOTIFY, sent|id, 0, 0, 0 },
        { 0 }
    };

    list = create_listview_control(LVS_REPORT);
    ok(list != NULL, "failed to create listview window\n");

    memset(&col, 0, sizeof(col));
    col.mask = LVCF_WIDTH | LVCF_TEXT;
    col.cx = 100;
    col.pszText = textA;
5721
    ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5722 5723
    expect(0, ret);

5724
    header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5725 5726 5727 5728
    ok(header != 0, "No header\n");
    memset(&itemW, 0, sizeof(itemW));
    itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
    itemW.pszText = buffer;
5729
    itemW.cchTextMax = ARRAY_SIZE(buffer);
5730 5731 5732 5733
    ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
    expect(1, ret);

    nmhdr.hdr.hwndFrom = header;
5734
    nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5735 5736 5737 5738 5739 5740 5741
    nmhdr.iItem = 0;
    nmhdr.iButton = 0;
    nmhdr.pitem = &itemW;

    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMCHANGINGW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5742
    ok(ret == 0, "got %ld\n", ret);
5743 5744 5745 5746 5747 5748 5749 5750
    parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
                "header notify, parent", TRUE);
    todo_wine
    ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMCHANGEDW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5751
    ok(ret == 0, "got %ld\n", ret);
5752 5753 5754 5755 5756 5757 5758 5759 5760 5761
    parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
                "header notify, parent", TRUE);
    todo_wine
    ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
    /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
    SetFocus(list);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMCLICKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5762
    ok(ret == 0, "got %ld\n", ret);
5763 5764 5765 5766 5767 5768
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
                "header notify, parent", FALSE);
    ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5769
    ok(ret == 0, "got %ld\n", ret);
5770 5771 5772 5773 5774 5775
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);
    ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5776
    ok(ret == 0, "got %ld\n", ret);
5777 5778 5779 5780 5781 5782
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
                "header notify, parent", TRUE);
    ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_BEGINTRACKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5783
    ok(ret == 0, "got %ld\n", ret);
5784 5785 5786 5787 5788 5789
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);
    ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ENDTRACKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5790
    ok(ret == 0, "got %ld\n", ret);
5791 5792
    parent_header_notify_seq[0].id = HDN_ENDTRACKA;
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5793
                "header notify, parent", FALSE);
5794 5795 5796 5797
    ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_TRACKW;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5798
    ok(ret == 0, "got %ld\n", ret);
5799 5800
    parent_header_notify_seq[0].id = HDN_TRACKA;
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5801
                "header notify, parent", FALSE);
5802 5803 5804 5805
    ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_BEGINDRAG;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5806
    ok(ret == 1, "got %ld\n", ret);
5807
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5808
                "header notify, parent", FALSE);
5809 5810 5811
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ENDDRAG;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5812
    ok(ret == 0, "got %ld\n", ret);
5813 5814 5815 5816 5817 5818
    parent_header_notify_seq[0].id = HDN_ENDDRAG;
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
                "header notify, parent", FALSE);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_FILTERCHANGE;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5819
    ok(ret == 0, "got %ld\n", ret);
5820 5821 5822 5823 5824 5825 5826 5827
    parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
    parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
                "header notify, parent", FALSE);
    parent_header_notify_seq[0].flags &= ~optional;
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5828
    ok(ret == 0, "got %ld\n", ret);
5829 5830 5831 5832 5833
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ENDFILTEREDIT;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5834
    ok(ret == 0, "got %ld\n", ret);
5835 5836 5837 5838 5839
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5840
    ok(ret == 0, "got %ld\n", ret);
5841 5842 5843 5844 5845
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
    nmhdr.hdr.code = HDN_ITEMKEYDOWN;
    ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5846
    ok(ret == 0, "got %ld\n", ret);
5847 5848 5849 5850 5851 5852 5853 5854
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
                "header notify, parent", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    DestroyWindow(list);
}

5855 5856 5857 5858 5859 5860 5861
static void test_createdragimage(void)
{
    HIMAGELIST himl;
    POINT pt;
    HWND list;

    list = create_listview_control(LVS_ICON);
5862
    ok(list != NULL, "failed to create listview window\n");
5863 5864 5865 5866 5867 5868 5869 5870 5871

    insert_item(list, 0);

    /* NULL point */
    himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
    ok(himl == NULL, "got %p\n", himl);

    himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
    ok(himl != NULL, "got %p\n", himl);
5872
    pImageList_Destroy(himl);
5873 5874 5875 5876

    DestroyWindow(list);
}

5877 5878 5879 5880 5881 5882
static void test_dispinfo(void)
{
    static const char testA[] = "TEST";
    WCHAR buff[10];
    LVITEMA item;
    HWND hwnd;
5883
    DWORD ret;
5884 5885

    hwnd = create_listview_control(LVS_ICON);
5886
    ok(hwnd != NULL, "failed to create listview window\n");
5887 5888 5889 5890 5891 5892

    insert_item(hwnd, 0);

    memset(&item, 0, sizeof(item));
    item.pszText = LPSTR_TEXTCALLBACKA;
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5893
    expect(1, ret);
5894 5895 5896

    g_disp_A_to_W = TRUE;
    item.pszText = (char*)buff;
5897
    item.cchTextMax = ARRAY_SIZE(buff);
5898
    ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5899
    ok(ret == sizeof(testA)-1, "got %ld, expected 4\n", ret);
5900 5901 5902 5903 5904 5905 5906 5907
    g_disp_A_to_W = FALSE;

    ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
        "got %s, expected %s\n", item.pszText, testA);

    DestroyWindow(hwnd);
}

5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920
static void test_LVM_SETITEMTEXT(void)
{
    static char testA[] = "TEST";
    LVITEMA item;
    HWND hwnd;
    DWORD ret;

    hwnd = create_listview_control(LVS_ICON);
    ok(hwnd != NULL, "failed to create listview window\n");

    insert_item(hwnd, 0);

    /* null item pointer */
5921
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5922 5923
    expect(FALSE, ret);

5924
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5925 5926 5927 5928 5929
    expect(FALSE, ret);

    /* index out of bounds */
    item.pszText = testA;
    item.cchTextMax = 0; /* ignored */
5930 5931
    item.iSubItem = 0;

5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943
    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
    expect(FALSE, ret);

    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
    expect(FALSE, ret);

    ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
    expect(TRUE, ret);

    DestroyWindow(hwnd);
}

5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980
static void test_LVM_REDRAWITEMS(void)
{
    HWND list;
    DWORD ret;

    list = create_listview_control(LVS_ICON);
    ok(list != NULL, "failed to create listview window\n");

    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
    expect(TRUE, ret);

    insert_item(list, 0);

    ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
    expect(TRUE, ret);

    ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
    expect(TRUE, ret);

    DestroyWindow(list);
}

5981 5982 5983 5984 5985 5986
static void test_imagelists(void)
{
    HWND hwnd, header;
    HIMAGELIST himl1, himl2, himl3;
    LRESULT ret;

5987 5988 5989
    himl1 = pImageList_Create(40, 40, 0, 4, 4);
    himl2 = pImageList_Create(40, 40, 0, 4, 4);
    himl3 = pImageList_Create(40, 40, 0, 4, 4);
5990 5991 5992 5993 5994 5995 5996 5997
    ok(himl1 != NULL, "Failed to create imagelist\n");
    ok(himl2 != NULL, "Failed to create imagelist\n");
    ok(himl3 != NULL, "Failed to create imagelist\n");

    hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
    header = subclass_header(hwnd);

    ok(header != NULL, "Expected header\n");
5998
    ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
                "set normal image list", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
                "set state image list", TRUE);

6015
    ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6016 6017 6018 6019 6020 6021 6022 6023 6024
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
                "set small image list", FALSE);

6025
    ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051
    ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
    DestroyWindow(hwnd);

    hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
                "set normal image list", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
                "set state image list", FALSE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
    ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
                "set small image list", FALSE);

6052
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6053 6054
    ok(header == NULL, "Expected no header, got %p\n", header);

6055
    SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
6056

6057
    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6058 6059
    ok(header != NULL, "Expected header, got NULL\n");

6060
    ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6061 6062 6063 6064 6065
    ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);

    DestroyWindow(hwnd);
}

6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120
static void test_deleteitem(void)
{
    LVITEMA item;
    UINT state;
    HWND hwnd;
    BOOL ret;

    hwnd = create_listview_control(LVS_REPORT);

    insert_item(hwnd, 0);
    insert_item(hwnd, 0);
    insert_item(hwnd, 0);
    insert_item(hwnd, 0);
    insert_item(hwnd, 0);

    g_focus_test_LVN_DELETEITEM = TRUE;

    /* delete focused item (not the last index) */
    item.stateMask = LVIS_FOCUSED;
    item.state = LVIS_FOCUSED;
    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
    ok(ret == TRUE, "got %d\n", ret);
    ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
    ok(ret == TRUE, "got %d\n", ret);
    /* next item gets focus */
    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

    /* focus last item and delete it */
    item.stateMask = LVIS_FOCUSED;
    item.state = LVIS_FOCUSED;
    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
    ok(ret == TRUE, "got %d\n", ret);
    ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
    ok(ret == TRUE, "got %d\n", ret);
    /* new last item gets focus */
    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

    /* focus first item and delete it */
    item.stateMask = LVIS_FOCUSED;
    item.state = LVIS_FOCUSED;
    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    ok(ret == TRUE, "got %d\n", ret);
    ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
    ok(ret == TRUE, "got %d\n", ret);
    /* new first item gets focus */
    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

    g_focus_test_LVN_DELETEITEM = FALSE;

    DestroyWindow(hwnd);
}

6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232
static const struct message parent_insert_focused0_seq[] = {
    { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
    { 0 }
};

static const struct message parent_insert_focused1_seq[] = {
    { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
    { 0 }
};

static const struct message parent_insert_item_seq[] = {
    { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
    { 0 }
};

static const struct message parent_insert_selected_seq[] = {
    { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGING },
    { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGED },
    { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
    { 0 }
};

#define LVIS_ALL (LVIS_FOCUSED | LVIS_SELECTED | LVIS_CUT | LVIS_DROPHILITED | LVIS_ACTIVATING)

static void test_LVM_INSERTITEM(void)
{
    static const struct
    {
        UINT mask, state, stateMask;
    } insert_item[] =
    {
        { LVIF_STATE, LVIS_FOCUSED, LVIS_FOCUSED },
        { LVIF_STATE, LVIS_FOCUSED, 0 },
        { LVIF_STATE, 0, LVIS_FOCUSED },

        { LVIF_STATE, LVIS_SELECTED, LVIS_SELECTED },
        { LVIF_STATE, LVIS_SELECTED, 0 },
        { LVIF_STATE, 0, LVIS_SELECTED },

        { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED },
        { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, 0 },
        { LVIF_STATE, 0, LVIS_FOCUSED | LVIS_SELECTED },

        { LVIF_STATE, LVIS_FOCUSED, LVIS_ALL },
        { LVIF_STATE, LVIS_SELECTED, LVIS_ALL },
        { LVIF_STATE, LVIS_CUT, LVIS_ALL },
        { LVIF_STATE, LVIS_DROPHILITED, LVIS_ALL },
        { LVIF_STATE, LVIS_ACTIVATING, LVIS_ALL },

        { LVIF_STATE, LVIS_ALL, LVIS_ALL },
        { LVIF_STATE, LVIS_ALL, 0 },
        { LVIF_STATE, 0, LVIS_ALL },

        { LVIF_STATE | LVIF_PARAM, 0, 0 },
        { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, LVIS_FOCUSED },
        { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, 0 },
        { LVIF_STATE | LVIF_PARAM, 0, LVIS_FOCUSED },

        { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, LVIS_SELECTED },
        { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, 0 },
        { LVIF_STATE | LVIF_PARAM, 0, LVIS_SELECTED },

        { LVIF_STATE, 0, 0 },
        { LVIF_PARAM, 0, 0 },

        { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
        { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
        { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
        { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },

        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },

        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, LVIS_ALL },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, 0 },
        { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_ALL },
    };
    LVITEMA item;
    UINT state;
    HWND hwnd;
    INT ret, i;
    char buf[256];

    for (i = 0; i < ARRAYSIZE(insert_item); i++)
    {
        hwnd = create_listview_control(LVS_REPORT);

        flush_sequences(sequences, NUM_MSG_SEQUENCES);

        item.mask = insert_item[i].mask;
        item.state = insert_item[i].state;
        item.stateMask = insert_item[i].stateMask;
        item.pszText = (LPSTR)"Hello World!";
        item.iImage = I_IMAGECALLBACK;
        item.iItem = 0;
        item.iSubItem = 0;
        item.lParam = 0xdeadbeef;
        ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
        ok(ret == 0, "%d: got %d\n", i, ret);

        if ((insert_item[i].mask & LVIF_STATE) && (insert_item[i].state & (LVIS_FOCUSED | LVIS_SELECTED)))
        {
            sprintf(buf, "%d: insert focused", i);
6233
            ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, buf, FALSE);
6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250
        }
        else
        {
            sprintf(buf, "%d: insert item", i);
            ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, buf, FALSE);
        }

        state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_ALL);
        if ((insert_item[i].mask & LVIF_STATE) && insert_item[i].state)
            ok(state == insert_item[i].state, "%d: expected %#x, got %#x\n", i, insert_item[i].state, state);
        else
            ok(state == 0, "%d: expected 0, got %#x\n", i, state);

        DestroyWindow(hwnd);
    }
}

6251 6252 6253 6254 6255 6256 6257 6258 6259
static void test_insertitem(void)
{
    LVITEMA item;
    UINT state;
    HWND hwnd;
    INT ret;

    hwnd = create_listview_control(LVS_REPORT);

6260 6261
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

6262 6263 6264 6265 6266 6267 6268 6269
    /* insert item 0 focused */
    item.mask = LVIF_STATE;
    item.state = LVIS_FOCUSED;
    item.stateMask = LVIS_FOCUSED;
    item.iItem = 0;
    item.iSubItem = 0;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 0, "got %d\n", ret);
6270
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, "insert focused 0", FALSE);
6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282

    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

    /* insert item 1, focus shift */
    item.mask = LVIF_STATE;
    item.state = LVIS_FOCUSED;
    item.stateMask = LVIS_FOCUSED;
    item.iItem = 1;
    item.iSubItem = 0;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 1, "got %d\n", ret);
6283
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused1_seq, "insert focused 1", FALSE);
6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295

    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

    /* insert item 2, no focus shift */
    item.mask = LVIF_STATE;
    item.state = 0;
    item.stateMask = LVIS_FOCUSED;
    item.iItem = 2;
    item.iSubItem = 0;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 2, "got %d\n", ret);
6296
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert focused 2", FALSE);
6297 6298 6299 6300

    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
    ok(state == LVIS_FOCUSED, "got %x\n", state);

6301 6302 6303 6304 6305 6306 6307 6308 6309
    /* insert item 3 */
    item.mask = LVIF_STATE | LVIF_PARAM;
    item.state = LVIS_SELECTED;
    item.stateMask = LVIS_SELECTED;
    item.iItem = 3;
    item.iSubItem = 0;
    item.lParam = 0xdeadbeef;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 3, "got %d\n", ret);
6310
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_selected_seq, "insert selected", FALSE);
6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333

    /* insert item 4 */
    item.mask = LVIF_PARAM;
    item.state = 0;
    item.stateMask = 0;
    item.iItem = 4;
    item.iSubItem = 0;
    item.lParam = 0xdeadbeef;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 4, "got %d\n", ret);
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert param", FALSE);

    /* insert item 5 */
    item.mask = LVIF_STATE;
    item.state = 0;
    item.stateMask = 0;
    item.iItem = 5;
    item.iSubItem = 0;
    item.lParam = 0xdeadbeef;
    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
    ok(ret == 5, "got %d\n", ret);
    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert state", FALSE);

6334 6335 6336
    DestroyWindow(hwnd);
}

6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360
static void test_header_proc(void)
{
    HWND hwnd, header, hdr;
    WNDPROC proc1, proc2;

    hwnd = create_listview_control(LVS_REPORT);

    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
    ok(header != NULL, "got %p\n", header);

    hdr = CreateWindowExA(0, WC_HEADERA, NULL,
			     WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
			     0, 0, 0, 0,
			     NULL, NULL, NULL, NULL);
    ok(hdr != NULL, "got %p\n", hdr);

    proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
    proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
    ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);

    DestroyWindow(hdr);
    DestroyWindow(hwnd);
}

6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375
static void flush_events(void)
{
    MSG msg;
    int diff = 200;
    int min_timeout = 100;
    DWORD time = GetTickCount() + diff;

    while (diff > 0)
    {
        if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
        while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
        diff = time - GetTickCount();
    }
}

6376 6377
static void test_oneclickactivate(void)
{
6378
    TRACKMOUSEEVENT track;
6379 6380 6381
    char item1[] = "item1";
    LVITEMA item;
    HWND hwnd, fg;
6382
    RECT rect;
6383
    INT r;
6384
    POINT orig_pos;
6385

6386
    hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
6387 6388 6389 6390 6391 6392
            10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
    ok(hwnd != NULL, "failed to create listview window\n");
    r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
    ok(r == 0, "should return zero\n");

    SetForegroundWindow(hwndparent);
6393
    flush_events();
6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409
    fg = GetForegroundWindow();
    if (fg != hwndparent)
    {
        skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
        DestroyWindow(hwnd);
        return;
    }

    item.mask = LVIF_TEXT;
    item.iItem = 0;
    item.iSubItem = 0;
    item.iImage = 0;
    item.pszText = item1;
    r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
    ok(r == 0, "should not fail\n");

6410
    GetWindowRect(hwnd, &rect);
6411
    GetCursorPos(&orig_pos);
6412 6413 6414 6415 6416 6417 6418
    SetCursorPos(rect.left+5, rect.top+5);
    flush_events();
    r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
    expect(0, r);

    track.cbSize = sizeof(track);
    track.dwFlags = TME_QUERY;
6419
    p_TrackMouseEvent(&track);
6420
    ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
6421
    ok(track.dwFlags == TME_LEAVE, "dwFlags = %lx\n", track.dwFlags);
6422

6423 6424 6425 6426 6427 6428 6429 6430
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(0, r);
    r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
    expect(0, r);
    r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
    expect(1, r);

    DestroyWindow(hwnd);
6431
    SetCursorPos(orig_pos.x, orig_pos.y);
6432 6433
}

6434 6435
static void test_callback_mask(void)
{
6436
    LVITEMA item;
6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449
    DWORD mask;
    HWND hwnd;
    BOOL ret;

    hwnd = create_listview_control(LVS_REPORT);

    ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
    ok(ret, "got %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
    ok(ret, "got %d\n", ret);

    mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6450
    ok(mask == ~0u, "got 0x%08lx\n", mask);
6451

6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489
    /* Ask for state, invalid subitem. */
    insert_item(hwnd, 0);

    ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
    ok(ret, "Failed to set callback mask.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    item.iSubItem = 1;
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(ret, "Failed to get item data.\n");

    memset(&item, 0, sizeof(item));
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(ret, "Failed to get item data.\n");

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, callback mask/invalid subitem 1", TRUE);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    memset(&item, 0, sizeof(item));
    memset(&g_itema, 0, sizeof(g_itema));
    item.iSubItem = 1;
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
    ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
    ok(ret, "Failed to get item data.\n");
    ok(g_itema.iSubItem == 1, "Unexpected LVN_DISPINFO subitem %d.\n", g_itema.iSubItem);
    ok(g_itema.stateMask == LVIS_FOCUSED, "Unexpected state mask %#x.\n", g_itema.stateMask);

    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
            "parent seq, callback mask/invalid subitem 2", FALSE);

6490
    DestroyWindow(hwnd);
6491 6492 6493 6494 6495

    /* LVS_OWNERDATA, mask LVIS_FOCUSED */
    hwnd = create_listview_control(LVS_REPORT | LVS_OWNERDATA);

    mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6496
    ok(mask == 0, "Unexpected callback mask %#lx.\n", mask);
6497 6498 6499 6500 6501

    ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
    ok(ret, "Failed to set callback mask, %d\n", ret);

    mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6502
    ok(mask == LVIS_FOCUSED, "Unexpected callback mask %#lx.\n", mask);
6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(ret == -1, "Unexpected selection mark, %d\n", ret);

    item.stateMask = LVIS_FOCUSED;
    item.state = LVIS_FOCUSED;
    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    ok(ret, "Failed to set item state.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6518
    todo_wine
6519 6520 6521
    ok(ret == 0, "Unexpected focused item, ret %d\n", ret);

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6522
    todo_wine
6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571
    ok(ret == 0, "Unexpected selection mark, %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == -1, "Unexpected focused item, ret %d\n", ret);

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(ret == -1, "Unexpected selection mark, %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == -1, "Unexpected focused item, ret %d\n", ret);

    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 1", FALSE);

    /* LVS_OWNDERDATA, empty mask */
    ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, 0, 0);
    ok(ret, "Failed to set callback mask, %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(ret == -1, "Unexpected selection mark, %d\n", ret);

    item.stateMask = LVIS_FOCUSED;
    item.state = LVIS_FOCUSED;
    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    ok(ret, "Failed to set item state.\n");

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
    ok(ret == 0, "Unexpected selection mark, %d\n", ret);

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == 0, "Unexpected focused item, ret %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == -1, "Unexpected focused item, ret %d\n", ret);

    ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6572
    todo_wine
6573 6574 6575 6576 6577 6578 6579 6580
    ok(ret == -1, "Unexpected selection mark, %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == -1, "Unexpected focused item, ret %d\n", ret);

6581
    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 2", FALSE);
6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604

    /* 2 items, focus on index 0, reduce to 1 item. */
    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 2, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
    ok(ret, "Failed to set item state.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == 0, "Unexpected focused item, ret %d\n", ret);

    ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
    ok(ret, "Failed to set item count.\n");

    ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
    ok(ret == 0, "Unexpected focused item, ret %d\n", ret);

    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_focus_change_ownerdata_seq,
        "parent seq, owner data/focus 3", TRUE);

    DestroyWindow(hwnd);
6605 6606
}

6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617
static void test_state_image(void)
{
    static const DWORD styles[] =
    {
        LVS_ICON,
        LVS_REPORT,
        LVS_SMALLICON,
        LVS_LIST,
    };
    int i;

6618
    for (i = 0; i < ARRAY_SIZE(styles); i++)
6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631
    {
        static char text[] = "Item";
        static char subtext[] = "Subitem";
        char buff[16];
        LVITEMA item;
        HWND hwnd;
        int r;

        hwnd = create_listview_control(styles[i]);

        insert_column(hwnd, 0);
        insert_column(hwnd, 1);

6632
        item.mask = LVIF_TEXT | LVIF_PARAM;
6633 6634 6635
        item.iItem = 0;
        item.iSubItem = 0;
        item.pszText = text;
6636
        item.lParam = 123456;
6637 6638 6639 6640
        r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
        ok(r == 0, "Failed to insert an item.\n");

        item.mask = LVIF_STATE;
6641 6642
        item.state = INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED;
        item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED | LVIS_FOCUSED;
6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654
        item.iItem = 0;
        item.iSubItem = 0;
        r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to set item state.\n");

        item.mask = LVIF_TEXT;
        item.iItem = 0;
        item.iSubItem = 1;
        item.pszText = subtext;
        r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to set subitem text.\n");

6655 6656
        item.mask = LVIF_STATE | LVIF_PARAM;
        item.stateMask = ~0u;
6657 6658 6659
        item.state = 0;
        item.iItem = 0;
        item.iSubItem = 0;
6660
        item.lParam = 0;
6661 6662
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get item state.\n");
6663 6664
        ok(item.state == (INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED),
            "Unexpected item state %#x.\n", item.state);
6665
        ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6666

6667 6668
        item.mask = 0;
        item.stateMask = ~0u;
6669 6670 6671 6672 6673
        item.state = INDEXTOSTATEIMAGEMASK(2);
        item.iItem = 0;
        item.iSubItem = 1;
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get subitem state.\n");
6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684
        ok(item.state == INDEXTOSTATEIMAGEMASK(2), "Unexpected state %#x.\n", item.state);

        item.mask = LVIF_STATE | LVIF_PARAM;
        item.stateMask = ~0u;
        item.state = INDEXTOSTATEIMAGEMASK(2);
        item.iItem = 0;
        item.iSubItem = 1;
        item.lParam = 0;
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get subitem state.\n");
        ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6685
        ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6686 6687 6688 6689 6690 6691 6692 6693

        item.mask = LVIF_STATE;
        item.stateMask = LVIS_FOCUSED;
        item.state = 0;
        item.iItem = 0;
        item.iSubItem = 1;
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get subitem state.\n");
6694 6695 6696
        ok(item.state == 0, "Unexpected state %#x.\n", item.state);

        item.mask = LVIF_STATE;
6697
        item.stateMask = ~0u;
6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717
        item.state = INDEXTOSTATEIMAGEMASK(2);
        item.iItem = 0;
        item.iSubItem = 2;
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get subitem state.\n");
        ok(item.state == 0, "Unexpected state %#x.\n", item.state);

        item.mask = LVIF_TEXT;
        item.iItem = 0;
        item.iSubItem = 1;
        item.pszText = buff;
        item.cchTextMax = sizeof(buff);
        r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
        ok(r, "Failed to get subitem text %d.\n", r);
        ok(!strcmp(buff, subtext), "Unexpected subitem text %s.\n", buff);

        DestroyWindow(hwnd);
    }
}

6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761
static void test_LVSCW_AUTOSIZE(void)
{
    int width, width2;
    HWND hwnd;
    BOOL ret;

    hwnd = create_listview_control(LVS_REPORT);
    ok(hwnd != NULL, "failed to create a listview window\n");

    insert_column(hwnd, 0);
    insert_column(hwnd, 1);
    insert_item(hwnd, 0);

    ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
    ok(ret, "Failed to set column width.\n");

    width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
    ok(width > 0, "Unexpected column width %d.\n", width);

    /* Turn on checkboxes. */
    ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
    ok(ret == 0, "Unexpected previous extended style.\n");

    ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
    ok(ret, "Failed to set column width.\n");

    width2 = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
    ok(width2 > 0, "Unexpected column width %d.\n", width2);
    ok(width2 > width, "Expected increased column width.\n");

    /* Turn off checkboxes. */
    ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
    ok(ret == LVS_EX_CHECKBOXES, "Unexpected previous extended style.\n");

    ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
    ok(ret, "Failed to set column width.\n");

    width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
    ok(width > 0, "Unexpected column width %d.\n", width2);
    ok(width2 > width, "Expected reduced column width.\n");

    DestroyWindow(hwnd);
}

6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812
static void test_LVN_ENDLABELEDIT(void)
{
    WCHAR text[] = {'l','a','l','a',0};
    HWND hwnd, hwndedit;
    LVITEMW item = {0};
    DWORD ret;

    hwnd = create_listview_control(LVS_REPORT | LVS_EDITLABELS);

    insert_column(hwnd, 0);

    item.mask = LVIF_TEXT;
    item.pszText = text;
    SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);

    /* Test normal editing */
    SetFocus(hwnd);
    hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
    ok(hwndedit != NULL, "Failed to get edit control.\n");

    ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test");
    ok(ret, "Failed to set edit text.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
    ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit, "Label edit", FALSE);

    /* Test editing with kill focus */
    SetFocus(hwnd);
    hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
    ok(hwndedit != NULL, "Failed to get edit control.\n");

    ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test2");
    ok(ret, "Failed to set edit text.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = TRUE;
    ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
    g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = FALSE;

    ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit_kill_focus,
            "Label edit, kill focus", FALSE);
    ok(GetFocus() == hwnd, "Unexpected focused window.\n");

    flush_sequences(sequences, NUM_MSG_SEQUENCES);

    DestroyWindow(hwnd);
}

6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882
static LRESULT CALLBACK create_item_height_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_CREATE)
        return 0;

    return CallWindowProcA(listviewWndProc, hwnd, msg, wParam, lParam);
}

static void test_LVM_GETCOUNTPERPAGE(void)
{
    static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
    unsigned int i, j;
    WNDCLASSEXA cls;
    ATOM class;
    HWND hwnd;
    BOOL ret;

    cls.cbSize = sizeof(WNDCLASSEXA);
    ret = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
    ok(ret, "Failed to get class info.\n");
    listviewWndProc = cls.lpfnWndProc;
    cls.lpfnWndProc = create_item_height_wndproc;
    cls.lpszClassName = "CountPerPageClass";
    class = RegisterClassExA(&cls);
    ok(class, "Failed to register class.\n");

    for (i = 0; i < ARRAY_SIZE(styles); i++)
    {
        static char text[] = "item text";
        LVITEMA item = { 0 };
        UINT count, count2;

        hwnd = create_listview_control(styles[i]);
        ok(hwnd != NULL, "Failed to create listview window.\n");

        count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
        if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
            ok(count > 0 || broken(styles[i] == LVS_LIST && count == 0), "%u: unexpected count %u.\n", i, count);
        else
            ok(count == 0, "%u: unexpected count %u.\n", i, count);

        for (j = 0; j < 10; j++)
        {
            item.mask = LVIF_TEXT;
            item.pszText = text;
            SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
        }

        count2 = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
        if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
            ok(count == count2, "%u: unexpected count %u.\n", i, count2);
        else
            ok(count2 == 10, "%u: unexpected count %u.\n", i, count2);

        DestroyWindow(hwnd);

        hwnd = CreateWindowA("CountPerPageClass", "Test", WS_VISIBLE | styles[i], 0, 0, 100, 100, NULL, NULL,
            GetModuleHandleA(NULL), 0);
        ok(hwnd != NULL, "Failed to create a window.\n");

        count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
        ok(count == 0, "%u: unexpected count %u.\n", i, count);

        DestroyWindow(hwnd);
    }

    ret = UnregisterClassA("CountPerPageClass", NULL);
    ok(ret, "Failed to unregister test class.\n");
}

6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962
static void test_item_state_change(void)
{
    static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
    LVITEMA item;
    HWND hwnd;
    DWORD res;
    int i;

    for (i = 0; i < ARRAY_SIZE(styles); i++)
    {
        hwnd = create_listview_control(styles[i]);

        insert_item(hwnd, 0);

        /* LVM_SETITEMSTATE with mask */
        memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
        memset(&item, 0, sizeof(item));
        item.mask = LVIF_STATE;
        item.stateMask = LVIS_SELECTED;
        item.state = LVIS_SELECTED;
        res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
        ok(res, "Failed to set item state.\n");

        ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
        ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
        ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
        ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
        ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
        ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);

        /* LVM_SETITEMSTATE 0 mask */
        memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
        memset(&item, 0, sizeof(item));
        item.stateMask = LVIS_SELECTED;
        item.state = 0;
        res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
        ok(res, "Failed to set item state.\n");

        ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
        ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
        ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
        ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
        ok(g_nmlistview.uOldState == LVIS_SELECTED, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
        ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);

        /* LVM_SETITEM changes state */
        memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
        memset(&item, 0, sizeof(item));
        item.stateMask = LVIS_SELECTED;
        item.state = LVIS_SELECTED;
        item.mask = LVIF_STATE;
        res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
        ok(res, "Failed to set item.\n");

        ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
        ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
        ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
        ok(g_nmlistview.uNewState == LVIS_SELECTED, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
        ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
        ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);

        /* LVM_SETITEM no state changes */
        memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
        memset(&item, 0, sizeof(item));
        item.lParam = 11;
        item.mask = LVIF_PARAM;
        res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
        ok(res, "Failed to set item.\n");

        ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
        ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
        ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
        ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
        ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
        ok(g_nmlistview.uChanged == LVIF_PARAM, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);

        DestroyWindow(hwnd);
    }
}

6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998
static void test_selected_column(void)
{
    static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
    int ret, i;
    HWND hwnd;

    for (i = 0; i < ARRAY_SIZE(styles); ++i)
    {
        hwnd = create_listview_control(styles[i]);

        /* Initial value */
        ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
        ok(ret == -1, "Unexpected column %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -100, 0);
        ok(ret == 1, "Unexpected return value %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
        ok(ret == -100, "Unexpected column %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, 100, 0);
        ok(ret == 1, "Unexpected return value %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
        ok(ret == 100, "Unexpected column %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -1, 0);
        ok(ret == 1, "Unexpected return value %d.\n", ret);

        ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
        ok(ret == -1, "Unexpected column %d.\n", ret);

        DestroyWindow(hwnd);
    }
}

6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029
static void test_LVM_GETNEXTITEMINDEX(void)
{
    LVITEMINDEX index;
    HWND hwnd;
    BOOL ret;

    hwnd = create_listview_control(LVS_REPORT);

    insert_item(hwnd, 0);
    insert_item(hwnd, 1);

    ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, 0, LVNI_ALL);
    ok(!ret, "Unexpected return value %d.\n", ret);

    index.iItem = -1;
    index.iGroup = 0;
    ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
    ok(ret, "Unexpected return value %d.\n", ret);
    ok(index.iItem == 0, "Unexpected item index %d.\n", index.iItem);

    ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
    ok(ret, "Unexpected return value %d.\n", ret);
    ok(index.iItem == 1, "Unexpected item index %d.\n", index.iItem);

    ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
    ok(!ret, "Unexpected return value %d.\n", ret);
    ok(index.iItem == -1, "Unexpected item index %d.\n", index.iItem);

    DestroyWindow(hwnd);
}

7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104
static void test_LVM_SETBKIMAGE(BOOL is_v6)
{
    LVBKIMAGEA image;
    HBITMAP hbmp;
    BITMAP bm;
    HWND hwnd;
    int ret;

    CoInitialize(NULL);

    hbmp = CreateBitmap(32, 32, 1, 1, NULL);
    hwnd = create_listview_control(LVS_REPORT);

    image.ulFlags = LVBKIF_SOURCE_NONE;
    image.hbm = 0;
    image.pszImage = NULL;
    image.cchImageMax = 0;
    image.xOffsetPercent = 0;
    image.yOffsetPercent = 0;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    ok(!ret, "got %d\n", ret);

    ret = GetObjectA(hbmp, sizeof(bm), &bm);
    ok(ret == sizeof(bm), "got %d\n", ret);

    image.ulFlags = LVBKIF_SOURCE_HBITMAP;
    image.hbm = hbmp;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    if (is_v6)
        ok(ret, "got %d\n", ret);
    else
        todo_wine ok(!ret, "got %d\n", ret);

    ret = GetObjectA(hbmp, sizeof(bm), &bm);
    ok(ret == sizeof(bm), "got %d\n", ret);

    image.ulFlags = LVBKIF_SOURCE_NONE;
    image.hbm = 0;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    ok(!ret, "got %d\n", ret);

    ret = GetObjectA(hbmp, sizeof(bm), &bm);
    ok(!ret, "got %d\n", ret);

    hbmp = CreateBitmap(32, 32, 1, 1, NULL);

    image.ulFlags = LVBKIF_SOURCE_HBITMAP;
    image.hbm = hbmp;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    if (is_v6)
        ok(ret, "got %d\n", ret);
    else
        todo_wine ok(!ret, "got %d\n", ret);

    ret = GetObjectA(hbmp, sizeof(bm), &bm);
    ok(ret == sizeof(bm), "got %d\n", ret);

    image.ulFlags = LVBKIF_SOURCE_HBITMAP;
    image.hbm = hbmp;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    ok(!ret, "got %d\n", ret);

    ret = GetObjectA(hbmp, sizeof(bm), &bm);
    ok(!ret, "got %d\n", ret);

    image.ulFlags = LVBKIF_SOURCE_NONE;
    image.hbm = 0;
    ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
    ok(!ret, "got %d\n", ret);

    DestroyWindow(hwnd);

    CoUninitialize();
}

7105 7106
START_TEST(listview)
{
7107
    ULONG_PTR ctx_cookie;
7108
    HANDLE hCtx;
7109

7110
    init_functions();
7111

7112 7113
    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);

7114
    hwndparent = create_parent_window(FALSE);
7115
    flush_sequences(sequences, NUM_MSG_SEQUENCES);
7116

7117
    test_header_notification();
7118
    test_header_notification2();
7119 7120
    test_images();
    test_checkboxes();
7121
    test_items();
7122
    test_create(FALSE);
7123
    test_redraw();
7124
    test_customdraw();
7125 7126 7127 7128
    test_icon_spacing();
    test_color();
    test_item_count();
    test_item_position();
7129
    test_columns();
7130
    test_getorigin();
7131
    test_multiselect();
7132
    test_getitemrect();
7133
    test_subitem_rect();
7134
    test_sorting();
7135
    test_ownerdata();
7136
    test_ownerdata_multiselect();
7137
    test_norecompute();
7138
    test_nosortheader();
7139
    test_setredraw();
7140
    test_hittest();
7141
    test_getviewrect();
7142
    test_getitemposition();
7143
    test_editbox();
7144
    test_notifyformat();
7145
    test_indentation();
7146
    test_getitemspacing();
7147
    test_getcolumnwidth();
7148 7149
    test_approximate_viewrect();
    test_finditem();
7150
    test_hover();
7151
    test_destroynotify();
7152
    test_createdragimage();
7153
    test_dispinfo();
7154
    test_LVM_SETITEMTEXT();
7155
    test_LVM_REDRAWITEMS();
7156
    test_imagelists();
7157
    test_deleteitem();
7158
    test_insertitem();
7159
    test_LVM_INSERTITEM();
7160
    test_header_proc();
7161
    test_oneclickactivate();
7162
    test_callback_mask();
7163
    test_state_image();
7164
    test_LVSCW_AUTOSIZE();
7165
    test_LVN_ENDLABELEDIT();
7166
    test_LVM_GETCOUNTPERPAGE();
7167
    test_item_state_change();
7168
    test_LVM_SETBKIMAGE(FALSE);
7169

7170
    if (!load_v6_module(&ctx_cookie, &hCtx))
7171 7172 7173 7174 7175
    {
        DestroyWindow(hwndparent);
        return;
    }

7176 7177
    init_functions();

7178 7179
    /* comctl32 version 6 tests start here */
    test_get_set_view();
7180
    test_canceleditlabel();
7181
    test_mapidindex();
7182
    test_scrollnotify();
7183
    test_LVS_EX_TRANSPARENTBKGND();
7184
    test_LVS_EX_HEADERINALLVIEWS();
7185
    test_deleteitem();
7186
    test_multiselect();
7187
    test_insertitem();
7188
    test_header_proc();
7189 7190 7191
    test_images();
    test_checkboxes();
    test_items();
7192
    test_create(TRUE);
7193 7194 7195 7196
    test_color();
    test_columns();
    test_sorting();
    test_ownerdata();
7197
    test_ownerdata_multiselect();
7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208
    test_norecompute();
    test_nosortheader();
    test_indentation();
    test_finditem();
    test_hover();
    test_destroynotify();
    test_createdragimage();
    test_dispinfo();
    test_LVM_SETITEMTEXT();
    test_LVM_REDRAWITEMS();
    test_oneclickactivate();
7209
    test_state_image();
7210
    test_LVSCW_AUTOSIZE();
7211
    test_LVN_ENDLABELEDIT();
7212
    test_LVM_GETCOUNTPERPAGE();
7213
    test_item_state_change();
7214
    test_selected_column();
7215
    test_LVM_GETNEXTITEMINDEX();
7216
    test_LVM_SETBKIMAGE(TRUE);
7217

7218
    unload_v6_module(ctx_cookie, hCtx);
7219

7220
    DestroyWindow(hwndparent);
7221
}