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