1 /* Unit test suite for list boxes. 2 * 3 * Copyright 2003 Ferenc Wagner 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 #include <stdio.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "wingdi.h" 26 #include "winuser.h" 27 #include "winnls.h" 28 #include "commctrl.h" 29 30 #include "wine/heap.h" 31 #include "wine/test.h" 32 #include "v6util.h" 33 #include "msg.h" 34 35 enum seq_index 36 { 37 LB_SEQ_INDEX, 38 PARENT_SEQ_INDEX, 39 NUM_MSG_SEQUENCES 40 }; 41 42 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 43 44 /* encoded MEASUREITEMSTRUCT into a WPARAM */ 45 typedef struct 46 { 47 union 48 { 49 struct 50 { 51 UINT CtlType : 4; 52 UINT CtlID : 4; 53 UINT itemID : 4; 54 UINT wParam : 20; 55 } item; 56 WPARAM wp; 57 } u; 58 } MEASURE_ITEM_STRUCT; 59 60 static unsigned hash_Ly_W(const WCHAR *str) 61 { 62 unsigned hash = 0; 63 64 for (; *str; str++) 65 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u; 66 67 return hash; 68 } 69 70 static unsigned hash_Ly(const char *str) 71 { 72 unsigned hash = 0; 73 74 for (; *str; str++) 75 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u; 76 77 return hash; 78 } 79 80 static const char * const strings[4] = { 81 "First added", 82 "Second added", 83 "Third added", 84 "Fourth added which is very long because at some time we only had a 256 byte character buffer and " 85 "that was overflowing in one of those applications that had a common dialog file open box and tried " 86 "to add a 300 characters long custom filter string which of course the code did not like and crashed. " 87 "Just make sure this string is longer than 256 characters." 88 }; 89 90 static const char BAD_EXTENSION[] = "*.badtxt"; 91 92 #define ID_LISTBOX 1 93 94 static LRESULT WINAPI listbox_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 95 { 96 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 97 static LONG defwndproc_counter = 0; 98 struct message msg = { 0 }; 99 LRESULT ret; 100 101 switch (message) 102 { 103 case WM_SIZE: 104 case WM_GETTEXT: 105 case WM_PAINT: 106 case WM_ERASEBKGND: 107 case WM_WINDOWPOSCHANGING: 108 case WM_WINDOWPOSCHANGED: 109 case WM_NCCALCSIZE: 110 case WM_NCPAINT: 111 case WM_NCHITTEST: 112 case WM_DEVICECHANGE: 113 break; 114 115 default: 116 msg.message = message; 117 msg.flags = sent|wparam|lparam; 118 if (defwndproc_counter) msg.flags |= defwinproc; 119 msg.wParam = wParam; 120 msg.lParam = lParam; 121 add_message(sequences, LB_SEQ_INDEX, &msg); 122 } 123 124 defwndproc_counter++; 125 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 126 defwndproc_counter--; 127 128 return ret; 129 } 130 131 static HWND create_listbox(DWORD add_style, HWND parent) 132 { 133 INT_PTR ctl_id = 0; 134 WNDPROC oldproc; 135 HWND handle; 136 137 if (parent) 138 ctl_id = ID_LISTBOX; 139 140 handle = CreateWindowA(WC_LISTBOXA, "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100, 141 parent, (HMENU)ctl_id, NULL, 0); 142 ok(handle != NULL, "Failed to create listbox window.\n"); 143 144 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]); 145 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]); 146 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]); 147 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]); 148 149 oldproc = (WNDPROC)SetWindowLongPtrA(handle, GWLP_WNDPROC, (LONG_PTR)listbox_wnd_proc); 150 SetWindowLongPtrA(handle, GWLP_USERDATA, (LONG_PTR)oldproc); 151 152 return handle; 153 } 154 155 struct listbox_prop 156 { 157 DWORD add_style; 158 }; 159 160 struct listbox_stat 161 { 162 int selected, anchor, caret, selcount; 163 }; 164 165 struct listbox_test 166 { 167 struct listbox_stat init, init_todo; 168 struct listbox_stat click, click_todo; 169 struct listbox_stat step, step_todo; 170 struct listbox_stat sel, sel_todo; 171 }; 172 173 static void listbox_query(HWND handle, struct listbox_stat *results) 174 { 175 results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0); 176 results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0); 177 results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0); 178 results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0); 179 } 180 181 static void buttonpress(HWND handle, WORD x, WORD y) 182 { 183 LPARAM lp = x + (y << 16); 184 185 SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp); 186 SendMessageA(handle, WM_LBUTTONUP, 0, lp); 187 } 188 189 static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended) 190 { 191 LPARAM lp = 1 + (scancode << 16) + (extended ? KEYEVENTF_EXTENDEDKEY : 0); 192 193 SendMessageA(handle, WM_KEYDOWN, keycode, lp); 194 SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000); 195 } 196 197 #define listbox_field_ok(t, s, f, got) \ 198 ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \ 199 ": expected %d, got %d\n", style, t.s.f, got.f) 200 201 #define listbox_todo_field_ok(t, s, f, got) \ 202 todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); } 203 204 #define listbox_ok(t, s, got) \ 205 listbox_todo_field_ok(t, s, selected, got); \ 206 listbox_todo_field_ok(t, s, anchor, got); \ 207 listbox_todo_field_ok(t, s, caret, got); \ 208 listbox_todo_field_ok(t, s, selcount, got) 209 210 static void run_test(DWORD style, const struct listbox_test test) 211 { 212 static const struct message delete_seq[] = 213 { 214 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, 215 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, 216 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, 217 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, 218 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc, 0, 0 }, 219 { 0 } 220 }; 221 struct listbox_stat answer; 222 int i, res, count; 223 RECT second_item; 224 HWND hLB; 225 226 hLB = create_listbox (style, 0); 227 228 listbox_query (hLB, &answer); 229 listbox_ok (test, init, answer); 230 231 SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item); 232 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top); 233 234 listbox_query(hLB, &answer); 235 listbox_ok(test, click, answer); 236 237 keypress(hLB, VK_DOWN, 0x50, TRUE); 238 239 listbox_query(hLB, &answer); 240 listbox_ok(test, step, answer); 241 242 DestroyWindow(hLB); 243 244 hLB = create_listbox(style, 0); 245 246 SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2)); 247 listbox_query(hLB, &answer); 248 listbox_ok(test, sel, answer); 249 250 for (i = 0; i < 4 && !(style & LBS_NODATA); i++) 251 { 252 DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0); 253 int resA, resW; 254 WCHAR *txtw; 255 CHAR *txt; 256 257 txt = heap_alloc_zero(size + 1); 258 resA = SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt); 259 ok(!strcmp(txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]); 260 261 txtw = heap_alloc_zero((size + 1) * sizeof(*txtw)); 262 resW = SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw); 263 ok(resA == resW, "Unexpected text length.\n"); 264 WideCharToMultiByte(CP_ACP, 0, txtw, -1, txt, size, NULL, NULL); 265 ok(!strcmp (txt, strings[i]), "Unexpected string for item %d, %s vs %s.\n", i, txt, strings[i]); 266 267 heap_free(txtw); 268 heap_free(txt); 269 } 270 271 /* Confirm the count of items, and that an invalid delete does not remove anything */ 272 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0); 273 ok(res == 4, "Expected 4 items, got %d\n", res); 274 res = SendMessageA(hLB, LB_DELETESTRING, -1, 0); 275 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res); 276 res = SendMessageA(hLB, LB_DELETESTRING, 4, 0); 277 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res); 278 count = SendMessageA(hLB, LB_GETCOUNT, 0, 0); 279 ok(count == 4, "Unexpected item count %d.\n", count); 280 281 /* Emptying listbox sends a LB_RESETCONTENT to itself. */ 282 flush_sequence(sequences, LB_SEQ_INDEX); 283 for (i = count; i--;) 284 { 285 res = SendMessageA(hLB, LB_DELETESTRING, 0, 0); 286 ok(res == i, "Unexpected return value %d.\n", res); 287 } 288 ok_sequence(sequences, LB_SEQ_INDEX, delete_seq, "Emptying listbox", FALSE); 289 290 DestroyWindow(hLB); 291 } 292 293 static void test_item_height(void) 294 { 295 INT itemHeight; 296 TEXTMETRICA tm; 297 HFONT font; 298 HWND hLB; 299 HDC hdc; 300 301 hLB = create_listbox (0, 0); 302 ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n"); 303 ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n"); 304 ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n"); 305 ReleaseDC( hLB, hdc); 306 307 ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n"); 308 309 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); 310 ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight); 311 312 DestroyWindow (hLB); 313 314 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100, NULL, NULL, NULL, 0); 315 316 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); 317 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n", 318 itemHeight, tm.tmHeight); 319 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0); 320 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n", 321 itemHeight, tm.tmHeight); 322 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0); 323 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n", 324 itemHeight, tm.tmHeight); 325 326 DestroyWindow (hLB); 327 } 328 329 static int got_selchange; 330 331 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 332 { 333 static LONG defwndproc_counter = 0; 334 struct message m = { 0 }; 335 LRESULT ret; 336 337 m.message = msg; 338 m.flags = sent|wparam|lparam; 339 if (defwndproc_counter) m.flags |= defwinproc; 340 m.wParam = wParam; 341 m.lParam = lParam; 342 343 switch (msg) 344 { 345 case WM_MEASUREITEM: 346 { 347 MEASUREITEMSTRUCT *mis = (void *)lParam; 348 BOOL is_unicode_data = FALSE; 349 MEASURE_ITEM_STRUCT mi; 350 351 if (mis->CtlType == ODT_LISTBOX) 352 { 353 HWND ctrl = GetDlgItem(hwnd, mis->CtlID); 354 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; 355 } 356 357 mi.u.wp = 0; 358 mi.u.item.CtlType = mis->CtlType; 359 mi.u.item.CtlID = mis->CtlID; 360 mi.u.item.itemID = mis->itemID; 361 mi.u.item.wParam = wParam; 362 363 m.wParam = mi.u.wp; 364 if (is_unicode_data) 365 m.lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0; 366 else 367 m.lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0; 368 add_message(sequences, PARENT_SEQ_INDEX, &m); 369 370 ok(wParam == mis->CtlID, "got wParam=%08lx, expected %08x\n", wParam, mis->CtlID); 371 ok(mis->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mis->CtlType); 372 ok(mis->CtlID == 1, "mi->CtlID = %u\n", mis->CtlID); 373 ok(mis->itemHeight, "mi->itemHeight = 0\n"); 374 375 break; 376 } 377 case WM_COMPAREITEM: 378 { 379 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lParam; 380 HWND ctrl = GetDlgItem(hwnd, cis->CtlID); 381 BOOL is_unicode_data = TRUE; 382 383 ok(wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, wParam); 384 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem); 385 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1); 386 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2); 387 388 if (cis->CtlType == ODT_LISTBOX) 389 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; 390 391 if (is_unicode_data) 392 { 393 m.wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0; 394 m.lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0; 395 } 396 else 397 { 398 m.wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0; 399 m.lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0; 400 } 401 add_message(sequences, PARENT_SEQ_INDEX, &m); 402 break; 403 } 404 case WM_DRAWITEM: 405 { 406 RECT rc_item, rc_client, rc_clip; 407 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; 408 409 ok(wParam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wParam, dis->CtlID); 410 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType); 411 412 GetClientRect(dis->hwndItem, &rc_client); 413 GetClipBox(dis->hDC, &rc_clip); 414 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip), 415 "client rect of the listbox should be equal to the clip box," 416 "or the clip box should be empty\n"); 417 418 SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item); 419 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n"); 420 421 break; 422 } 423 424 case WM_COMMAND: 425 if (HIWORD( wParam ) == LBN_SELCHANGE) got_selchange++; 426 break; 427 428 default: 429 break; 430 } 431 432 defwndproc_counter++; 433 ret = DefWindowProcA(hwnd, msg, wParam, lParam); 434 defwndproc_counter--; 435 436 return msg == WM_COMPAREITEM ? -1 : ret; 437 } 438 439 static HWND create_parent( void ) 440 { 441 static ATOM class; 442 WNDCLASSA cls; 443 444 if (!class) 445 { 446 cls.style = 0; 447 cls.lpfnWndProc = main_window_proc; 448 cls.cbClsExtra = 0; 449 cls.cbWndExtra = 0; 450 cls.hInstance = GetModuleHandleA(NULL); 451 cls.hIcon = 0; 452 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 453 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 454 cls.lpszMenuName = NULL; 455 cls.lpszClassName = "main_window_class"; 456 class = RegisterClassA( &cls ); 457 } 458 459 return CreateWindowExA(0, "main_window_class", NULL, WS_POPUP | WS_VISIBLE, 100, 100, 400, 400, GetDesktopWindow(), 460 0, GetModuleHandleA(NULL), NULL); 461 } 462 463 static void test_ownerdraw(void) 464 { 465 static const DWORD styles[] = 466 { 467 0, 468 LBS_NODATA 469 }; 470 HWND parent, hLB; 471 INT ret; 472 RECT rc; 473 UINT i; 474 475 parent = create_parent(); 476 ok(parent != NULL, "Failed to create parent window.\n"); 477 478 for (i = 0; i < ARRAY_SIZE(styles); i++) 479 { 480 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent); 481 ok(hLB != NULL, "Failed to create listbox window.\n"); 482 483 SetForegroundWindow(hLB); 484 UpdateWindow(hLB); 485 486 /* make height short enough */ 487 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc); 488 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, SWP_NOZORDER | SWP_NOMOVE); 489 490 /* make 0 item invisible */ 491 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0); 492 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0); 493 ok(ret == 1, "wrong top index %d\n", ret); 494 495 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc); 496 ok(!IsRectEmpty(&rc), "empty item rect\n"); 497 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top); 498 499 DestroyWindow(hLB); 500 501 /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */ 502 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i], 503 0, 0, 100, 100, NULL, NULL, NULL, 0); 504 ok(hLB != NULL, "last error 0x%08x\n", GetLastError()); 505 506 ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n"); 507 508 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0); 509 ok(ret == 0, "Unexpected return value %d.\n", ret); 510 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0); 511 ok(ret == 1, "Unexpected return value %d.\n", ret); 512 513 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13); 514 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret); 515 516 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); 517 ok(ret == 13, "Unexpected item height %d.\n", ret); 518 519 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42); 520 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret); 521 522 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0); 523 ok(ret == 42, "Unexpected item height %d.\n", ret); 524 525 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0); 526 ok(ret == 42, "Unexpected item height %d.\n", ret); 527 528 DestroyWindow (hLB); 529 } 530 531 DestroyWindow(parent); 532 } 533 534 #define listbox_test_query(exp, got) \ 535 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \ 536 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \ 537 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \ 538 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount); 539 540 static void test_LB_SELITEMRANGE(void) 541 { 542 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 }; 543 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 }; 544 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 }; 545 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 }; 546 struct listbox_stat answer; 547 HWND hLB; 548 INT ret; 549 550 hLB = create_listbox(LBS_EXTENDEDSEL, 0); 551 ok(hLB != NULL, "Failed to create listbox window.\n"); 552 553 listbox_query(hLB, &answer); 554 listbox_test_query(test_nosel, answer); 555 556 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2)); 557 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 558 listbox_query(hLB, &answer); 559 listbox_test_query(test_1, answer); 560 561 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 562 listbox_query(hLB, &answer); 563 listbox_test_query(test_nosel, answer); 564 565 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4)); 566 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 567 listbox_query(hLB, &answer); 568 listbox_test_query(test_3, answer); 569 570 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 571 listbox_query(hLB, &answer); 572 listbox_test_query(test_nosel, answer); 573 574 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5)); 575 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 576 listbox_query(hLB, &answer); 577 listbox_test_query(test_nosel, answer); 578 579 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 580 listbox_query(hLB, &answer); 581 listbox_test_query(test_nosel, answer); 582 583 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10)); 584 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 585 listbox_query(hLB, &answer); 586 listbox_test_query(test_1, answer); 587 588 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 589 listbox_query(hLB, &answer); 590 listbox_test_query(test_nosel, answer); 591 592 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10)); 593 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 594 listbox_query(hLB, &answer); 595 listbox_test_query(test_nosel, answer); 596 597 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 598 listbox_query(hLB, &answer); 599 listbox_test_query(test_nosel, answer); 600 601 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1)); 602 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 603 listbox_query(hLB, &answer); 604 listbox_test_query(test_2, answer); 605 606 SendMessageA(hLB, LB_SETSEL, FALSE, -1); 607 listbox_query(hLB, &answer); 608 listbox_test_query(test_nosel, answer); 609 610 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1)); 611 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret); 612 listbox_query(hLB, &answer); 613 listbox_test_query(test_2, answer); 614 615 DestroyWindow(hLB); 616 } 617 618 static void test_LB_SETCURSEL(void) 619 { 620 HWND parent, hLB; 621 INT ret; 622 623 parent = create_parent(); 624 ok(parent != NULL, "Failed to create parent window.\n"); 625 626 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent); 627 ok(hLB != NULL, "Failed to create listbox.\n"); 628 629 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32); 630 631 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 632 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 633 634 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); 635 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret); 636 ret = GetScrollPos(hLB, SB_VERT); 637 ok(ret == 0, "expected vscroll 0, got %d\n", ret); 638 639 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 640 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 641 642 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0); 643 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret); 644 ret = GetScrollPos(hLB, SB_VERT); 645 ok(ret == 1, "expected vscroll 1, got %d\n", ret); 646 647 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 648 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 649 650 DestroyWindow(hLB); 651 652 hLB = create_listbox(0, 0); 653 ok(hLB != NULL, "Failed to create ListBox window.\n"); 654 655 ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0); 656 ok(ret == 1, "Unexpected return value %d.\n", ret); 657 658 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 659 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 660 661 DestroyWindow(hLB); 662 663 /* LBS_EXTENDEDSEL */ 664 hLB = create_listbox(LBS_EXTENDEDSEL, 0); 665 ok(hLB != NULL, "Failed to create listbox.\n"); 666 667 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 668 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 669 670 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); 671 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret); 672 673 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 674 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 675 676 DestroyWindow(hLB); 677 678 /* LBS_MULTIPLESEL */ 679 hLB = create_listbox(LBS_MULTIPLESEL, 0); 680 ok(hLB != NULL, "Failed to create listbox.\n"); 681 682 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 683 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 684 685 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0); 686 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret); 687 688 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0); 689 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 690 691 DestroyWindow(hLB); 692 } 693 694 static void test_LB_SETSEL(void) 695 { 696 HWND list; 697 int ret; 698 699 /* LBS_EXTENDEDSEL */ 700 list = create_listbox(LBS_EXTENDEDSEL, 0); 701 ok(list != NULL, "Failed to create ListBox window.\n"); 702 703 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 704 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 705 706 ret = SendMessageA(list, LB_SETSEL, TRUE, 0); 707 ok(ret == 0, "Unexpected return value %d.\n", ret); 708 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 709 ok(ret == 0, "Unexpected anchor index %d.\n", ret); 710 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 711 ok(ret == 0, "Unexpected caret index %d.\n", ret); 712 713 ret = SendMessageA(list, LB_SETSEL, TRUE, 1); 714 ok(ret == 0, "Unexpected return value %d.\n", ret); 715 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 716 ok(ret == 1, "Unexpected anchor index %d.\n", ret); 717 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 718 ok(ret == 1, "Unexpected caret index %d.\n", ret); 719 720 ret = SendMessageA(list, LB_SETSEL, FALSE, 1); 721 ok(ret == 0, "Unexpected return value %d.\n", ret); 722 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 723 ok(ret == 1, "Unexpected anchor index %d.\n", ret); 724 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 725 ok(ret == 1, "Unexpected caret index %d.\n", ret); 726 727 DestroyWindow(list); 728 729 /* LBS_MULTIPLESEL */ 730 list = create_listbox(LBS_MULTIPLESEL, 0); 731 ok(list != NULL, "Failed to create ListBox window.\n"); 732 733 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 734 ok(ret == -1, "Unexpected anchor index %d.\n", ret); 735 736 ret = SendMessageA(list, LB_SETSEL, TRUE, 0); 737 ok(ret == 0, "Unexpected return value %d.\n", ret); 738 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 739 ok(ret == 0, "Unexpected anchor index %d.\n", ret); 740 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 741 ok(ret == 0, "Unexpected caret index %d.\n", ret); 742 743 ret = SendMessageA(list, LB_SETSEL, TRUE, 1); 744 ok(ret == 0, "Unexpected return value %d.\n", ret); 745 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 746 ok(ret == 1, "Unexpected anchor index %d.\n", ret); 747 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 748 ok(ret == 1, "Unexpected caret index %d.\n", ret); 749 750 ret = SendMessageA(list, LB_SETSEL, FALSE, 1); 751 ok(ret == 0, "Unexpected return value %d.\n", ret); 752 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0); 753 ok(ret == 1, "Unexpected anchor index %d.\n", ret); 754 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0); 755 ok(ret == 1, "Unexpected caret index %d.\n", ret); 756 757 DestroyWindow(list); 758 } 759 760 static void test_listbox_height(void) 761 { 762 HWND hList; 763 int r, id; 764 765 hList = CreateWindowA( WC_LISTBOXA, "list test", 0, 766 1, 1, 600, 100, NULL, NULL, NULL, NULL ); 767 ok( hList != NULL, "failed to create listbox\n"); 768 769 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi"); 770 ok( id == 0, "item id wrong\n"); 771 772 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 )); 773 ok( r == 0, "send message failed\n"); 774 775 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 776 ok( r == 20, "height wrong\n"); 777 778 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 )); 779 ok( r == -1, "send message failed\n"); 780 781 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 782 ok( r == 20, "height wrong\n"); 783 784 /* Before Windows 10 1709 (or 1703?) the item height was limited to 255. 785 * Since then, with comctl32 V6 the limit is 65535. 786 */ 787 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 256, 0 )); 788 ok(r == 0 || broken(r == -1), "Failed to set item height, %d.\n", r); 789 if (r == -1) 790 { 791 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 792 ok( r == 20, "Unexpected item height %d.\n", r); 793 } 794 else 795 { 796 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 797 ok( r == 256, "Unexpected item height %d.\n", r); 798 799 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 65535, 0 )); 800 ok(r == 0, "Failed to set item height, %d.\n", r); 801 802 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 803 ok( r == 65535, "Unexpected item height %d.\n", r); 804 } 805 806 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 )); 807 ok( r == 0, "send message failed\n"); 808 809 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 ); 810 ok( r == 0xff, "height wrong\n"); 811 812 DestroyWindow( hList ); 813 } 814 815 static void test_changing_selection_styles(void) 816 { 817 static const DWORD styles[] = 818 { 819 0, 820 LBS_NODATA | LBS_OWNERDRAWFIXED 821 }; 822 static const DWORD selstyles[] = 823 { 824 0, 825 LBS_MULTIPLESEL, 826 LBS_EXTENDEDSEL, 827 LBS_MULTIPLESEL | LBS_EXTENDEDSEL 828 }; 829 static const LONG selexpect_single[] = { 0, 0, 1 }; 830 static const LONG selexpect_single2[] = { 1, 0, 0 }; 831 static const LONG selexpect_multi[] = { 1, 0, 1 }; 832 static const LONG selexpect_multi2[] = { 1, 1, 0 }; 833 834 HWND parent, listbox; 835 DWORD style; 836 LONG ret; 837 UINT i, j, k; 838 839 parent = create_parent(); 840 ok(parent != NULL, "Failed to create parent window.\n"); 841 for (i = 0; i < ARRAY_SIZE(styles); i++) 842 { 843 /* Test if changing selection styles affects selection storage */ 844 for (j = 0; j < ARRAY_SIZE(selstyles); j++) 845 { 846 LONG setcursel_expect, selitemrange_expect, getselcount_expect; 847 const LONG *selexpect; 848 849 listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE, 850 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0); 851 ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j); 852 853 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) 854 { 855 setcursel_expect = LB_ERR; 856 selitemrange_expect = LB_OKAY; 857 getselcount_expect = 2; 858 selexpect = selexpect_multi; 859 } 860 else 861 { 862 setcursel_expect = 2; 863 selitemrange_expect = LB_ERR; 864 getselcount_expect = LB_ERR; 865 selexpect = selexpect_single; 866 } 867 868 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) 869 { 870 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x"); 871 ok(ret == k, "%u: Unexpected return value %d, expected %d.\n", j, ret, k); 872 } 873 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0); 874 ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\n", j, ret); 875 876 /* Select items with different methods */ 877 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0); 878 ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret); 879 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0)); 880 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); 881 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2)); 882 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); 883 884 /* Verify that the proper items are selected */ 885 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) 886 { 887 ret = SendMessageA(listbox, LB_GETSEL, k, 0); 888 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", 889 j, ret, selexpect[k]); 890 } 891 892 /* Now change the selection style */ 893 style = GetWindowLongA(listbox, GWL_STYLE); 894 ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j], 895 "%u: unexpected window styles %#x.\n", j, style); 896 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) 897 style &= ~selstyles[j]; 898 else 899 style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL; 900 SetWindowLongA(listbox, GWL_STYLE, style); 901 style = GetWindowLongA(listbox, GWL_STYLE); 902 ok(!(style & selstyles[j]), "%u: unexpected window styles %#x.\n", j, style); 903 904 /* Verify that the same items are selected */ 905 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0); 906 ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n", 907 j, getselcount_expect, ret); 908 909 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) 910 { 911 ret = SendMessageA(listbox, LB_GETSEL, k, 0); 912 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", 913 j, ret, selexpect[k]); 914 } 915 916 /* Lastly see if we can still change the selection as before with old style */ 917 if (setcursel_expect != LB_ERR) setcursel_expect = 0; 918 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0); 919 ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret); 920 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1)); 921 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); 922 ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2)); 923 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret); 924 925 /* And verify the selections */ 926 selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2; 927 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0); 928 ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n", 929 j, getselcount_expect, ret); 930 931 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++) 932 { 933 ret = SendMessageA(listbox, LB_GETSEL, k, 0); 934 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n", 935 j, ret, selexpect[k]); 936 } 937 938 DestroyWindow(listbox); 939 } 940 } 941 DestroyWindow(parent); 942 } 943 944 static void test_itemfrompoint(void) 945 { 946 /* WS_POPUP is required in order to have a more accurate size calculation ( 947 without caption). LBS_NOINTEGRALHEIGHT is required in order to test 948 behavior of partially-displayed item. 949 */ 950 HWND hList = CreateWindowA( WC_LISTBOXA, "list test", 951 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT, 952 1, 1, 600, 100, NULL, NULL, NULL, NULL ); 953 ULONG r, id; 954 RECT rc; 955 956 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 )); 957 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r ); 958 959 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 )); 960 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r ); 961 962 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 )); 963 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r ); 964 965 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi"); 966 ok( id == 0, "item id wrong\n"); 967 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1"); 968 ok( id == 1, "item id wrong\n"); 969 970 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 )); 971 ok( r == 0x1, "ret %x\n", r ); 972 973 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 )); 974 ok( r == MAKELPARAM(1, 1), "Unexpected ret value %#x.\n", r ); 975 976 /* Resize control so that below assertions about sizes are valid */ 977 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc); 978 ok( r == 1, "ret %x\n", r); 979 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE); 980 ok( r != 0, "ret %x\n", r); 981 982 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2"); 983 ok( id == 2, "item id wrong\n"); 984 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3"); 985 ok( id == 3, "item id wrong\n"); 986 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4"); 987 ok( id == 4, "item id wrong\n"); 988 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5"); 989 ok( id == 5, "item id wrong\n"); 990 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6"); 991 ok( id == 6, "item id wrong\n"); 992 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7"); 993 ok( id == 7, "item id wrong\n"); 994 995 /* Set the listbox up so that id 1 is at the top, this leaves 5 996 partially visible at the bottom and 6, 7 are invisible */ 997 998 SendMessageA( hList, LB_SETTOPINDEX, 1, 0); 999 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0); 1000 ok( r == 1, "top %d\n", r); 1001 1002 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc); 1003 ok( r == 1, "ret %x\n", r); 1004 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc); 1005 ok( r == 0, "ret %x\n", r); 1006 1007 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) ); 1008 ok( r == 1, "ret %x\n", r); 1009 1010 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) ); 1011 ok( r == 0x10001, "ret %x\n", r ); 1012 1013 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) ); 1014 ok( r == 0x10001, "ret %x\n", r ); 1015 1016 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) ); 1017 ok( r == 0x10005, "item %x\n", r ); 1018 1019 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) ); 1020 ok( r == 0x10005, "item %x\n", r ); 1021 1022 DestroyWindow( hList ); 1023 } 1024 1025 static void test_listbox_item_data(void) 1026 { 1027 HWND hList; 1028 int r, id; 1029 1030 hList = CreateWindowA( WC_LISTBOXA, "list test", 0, 1031 1, 1, 600, 100, NULL, NULL, NULL, NULL ); 1032 ok( hList != NULL, "failed to create listbox\n"); 1033 1034 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi"); 1035 ok( id == 0, "item id wrong\n"); 1036 1037 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 )); 1038 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r); 1039 1040 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0); 1041 ok( r == 20, "get item data failed\n"); 1042 1043 DestroyWindow( hList ); 1044 } 1045 1046 static void test_listbox_LB_DIR(void) 1047 { 1048 char path[MAX_PATH], curdir[MAX_PATH]; 1049 HWND hList; 1050 int res, itemCount; 1051 int itemCount_justFiles; 1052 int itemCount_justDrives; 1053 int itemCount_allFiles; 1054 int itemCount_allDirs; 1055 int i; 1056 char pathBuffer[MAX_PATH]; 1057 char * p; 1058 char driveletter; 1059 const char *wildcard = "*"; 1060 HANDLE file; 1061 BOOL ret; 1062 1063 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir); 1064 1065 GetTempPathA(ARRAY_SIZE(path), path); 1066 ret = SetCurrentDirectoryA(path); 1067 ok(ret, "Failed to set current directory.\n"); 1068 1069 ret = CreateDirectoryA("lb_dir_test", NULL); 1070 ok(ret, "Failed to create test directory.\n"); 1071 1072 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); 1073 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError()); 1074 CloseHandle( file ); 1075 1076 /* NOTE: for this test to succeed, there must be no subdirectories 1077 under the current directory. In addition, there must be at least 1078 one file that fits the wildcard w*.c . Normally, the test 1079 directory itself satisfies both conditions. 1080 */ 1081 hList = CreateWindowA( WC_LISTBOXA, "list test", WS_VISIBLE|WS_POPUP, 1082 1, 1, 600, 100, NULL, NULL, NULL, NULL ); 1083 ok(hList != NULL, "Failed to create listbox window.\n"); 1084 1085 /* Test for standard usage */ 1086 1087 /* This should list all the files in the test directory. */ 1088 strcpy(pathBuffer, wildcard); 1089 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1090 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); 1091 if (res == -1) /* "*" wildcard doesn't work on win9x */ 1092 { 1093 wildcard = "*.*"; 1094 strcpy(pathBuffer, wildcard); 1095 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); 1096 } 1097 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError()); 1098 1099 /* There should be some content in the listbox */ 1100 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1101 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n"); 1102 itemCount_allFiles = itemCount; 1103 ok(res + 1 == itemCount, 1104 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n", 1105 itemCount - 1, res); 1106 1107 /* This tests behavior when no files match the wildcard */ 1108 strcpy(pathBuffer, BAD_EXTENSION); 1109 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1110 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); 1111 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res); 1112 1113 /* There should be NO content in the listbox */ 1114 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1115 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n"); 1116 1117 1118 /* This should list all the w*.c files in the test directory 1119 * As of this writing, this includes win.c, winstation.c, wsprintf.c 1120 */ 1121 strcpy(pathBuffer, "w*.c"); 1122 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1123 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer); 1124 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError()); 1125 1126 /* Path specification does NOT converted to uppercase */ 1127 ok (!strcmp(pathBuffer, "w*.c"), 1128 "expected no change to pathBuffer, got %s\n", pathBuffer); 1129 1130 /* There should be some content in the listbox */ 1131 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1132 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n"); 1133 itemCount_justFiles = itemCount; 1134 ok(res + 1 == itemCount, 1135 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n", 1136 itemCount - 1, res); 1137 1138 /* Every single item in the control should start with a w and end in .c */ 1139 for (i = 0; i < itemCount; i++) 1140 { 1141 memset(pathBuffer, 0, MAX_PATH); 1142 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1143 p = pathBuffer + strlen(pathBuffer); 1144 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1145 (*(p-1) == 'c' || *(p-1) == 'C') && 1146 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1147 } 1148 1149 /* Test DDL_DIRECTORY */ 1150 strcpy(pathBuffer, wildcard); 1151 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1152 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); 1153 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError()); 1154 1155 /* There should be some content in the listbox. 1156 * All files plus "[..]" 1157 */ 1158 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1159 itemCount_allDirs = itemCount - itemCount_allFiles; 1160 ok (itemCount >= itemCount_allFiles, 1161 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n", 1162 itemCount, itemCount_allFiles); 1163 ok(res + 1 == itemCount, 1164 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n", 1165 itemCount - 1, res); 1166 1167 /* This tests behavior when no files match the wildcard */ 1168 strcpy(pathBuffer, BAD_EXTENSION); 1169 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1170 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); 1171 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res); 1172 1173 /* There should be NO content in the listbox */ 1174 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1175 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n"); 1176 1177 /* Test DDL_DIRECTORY */ 1178 strcpy(pathBuffer, "w*.c"); 1179 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1180 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); 1181 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError()); 1182 1183 /* There should be some content in the listbox. Since the parent directory does not 1184 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY 1185 */ 1186 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1187 ok (itemCount == itemCount_justFiles, 1188 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n", 1189 itemCount, itemCount_justFiles); 1190 ok(res + 1 == itemCount, 1191 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n", 1192 itemCount - 1, res); 1193 1194 /* Every single item in the control should start with a w and end in .c. */ 1195 for (i = 0; i < itemCount; i++) 1196 { 1197 memset(pathBuffer, 0, MAX_PATH); 1198 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1199 p = pathBuffer + strlen(pathBuffer); 1200 ok( 1201 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1202 (*(p-1) == 'c' || *(p-1) == 'C') && 1203 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1204 } 1205 1206 /* Test DDL_DRIVES|DDL_EXCLUSIVE */ 1207 strcpy(pathBuffer, wildcard); 1208 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1209 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1210 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError()); 1211 1212 /* There should be some content in the listbox. In particular, there should 1213 * be at least one element before, since the string "[-c-]" should 1214 * have been added. Depending on the user setting, more drives might have 1215 * been added. 1216 */ 1217 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1218 ok (itemCount >= 1, 1219 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n", 1220 itemCount, 1); 1221 itemCount_justDrives = itemCount; 1222 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n"); 1223 1224 /* Every single item in the control should fit the format [-c-] */ 1225 for (i = 0; i < itemCount; i++) 1226 { 1227 memset(pathBuffer, 0, MAX_PATH); 1228 driveletter = '\0'; 1229 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1230 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" ); 1231 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer); 1232 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1233 if (!(driveletter >= 'a' && driveletter <= 'z')) 1234 { 1235 /* Correct after invalid entry is found */ 1236 itemCount_justDrives--; 1237 } 1238 } 1239 1240 /* This tests behavior when no files match the wildcard */ 1241 strcpy(pathBuffer, BAD_EXTENSION); 1242 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1243 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1244 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n", 1245 BAD_EXTENSION, res, itemCount_justDrives -1); 1246 1247 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1248 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n", 1249 itemCount, itemCount_justDrives); 1250 1251 /* Test DDL_DRIVES. */ 1252 strcpy(pathBuffer, wildcard); 1253 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1254 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); 1255 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); 1256 1257 /* There should be some content in the listbox. In particular, there should 1258 * be at least one element before, since the string "[-c-]" should 1259 * have been added. Depending on the user setting, more drives might have 1260 * been added. 1261 */ 1262 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1263 ok (itemCount == itemCount_justDrives + itemCount_allFiles, 1264 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n", 1265 itemCount, itemCount_justDrives + itemCount_allFiles); 1266 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n"); 1267 1268 /* This tests behavior when no files match the wildcard */ 1269 strcpy(pathBuffer, BAD_EXTENSION); 1270 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1271 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); 1272 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n", 1273 BAD_EXTENSION, res, itemCount_justDrives -1); 1274 1275 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1276 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1); 1277 1278 /* Test DDL_DRIVES. */ 1279 strcpy(pathBuffer, "w*.c"); 1280 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1281 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); 1282 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError()); 1283 1284 /* There should be some content in the listbox. In particular, there should 1285 * be at least one element before, since the string "[-c-]" should 1286 * have been added. Depending on the user setting, more drives might have 1287 * been added. 1288 */ 1289 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1290 ok (itemCount == itemCount_justDrives + itemCount_justFiles, 1291 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n", 1292 itemCount, itemCount_justDrives + itemCount_justFiles); 1293 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n"); 1294 1295 /* Every single item in the control should fit the format [-c-], or w*.c */ 1296 for (i = 0; i < itemCount; i++) 1297 { 1298 memset(pathBuffer, 0, MAX_PATH); 1299 driveletter = '\0'; 1300 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1301 p = pathBuffer + strlen(pathBuffer); 1302 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1303 { 1304 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" ); 1305 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1306 } 1307 else 1308 { 1309 ok( 1310 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1311 (*(p-1) == 'c' || *(p-1) == 'C') && 1312 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1313 } 1314 } 1315 1316 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */ 1317 strcpy(pathBuffer, wildcard); 1318 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1319 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); 1320 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); 1321 1322 /* There should be some content in the listbox. In particular, there should 1323 * be exactly the number of plain files, plus the number of mapped drives. 1324 */ 1325 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1326 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs, 1327 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n", 1328 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs); 1329 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n"); 1330 1331 /* Every single item in the control should start with a w and end in .c, 1332 * except for the "[..]" string, which should appear exactly as it is, 1333 * and the mapped drives in the format "[-X-]". 1334 */ 1335 for (i = 0; i < itemCount; i++) 1336 { 1337 memset(pathBuffer, 0, MAX_PATH); 1338 driveletter = '\0'; 1339 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1340 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1341 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1342 } 1343 1344 /* This tests behavior when no files match the wildcard */ 1345 strcpy(pathBuffer, BAD_EXTENSION); 1346 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1347 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); 1348 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n", 1349 BAD_EXTENSION, res, itemCount_justDrives -1); 1350 1351 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1352 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1); 1353 1354 /* Test DDL_DIRECTORY|DDL_DRIVES. */ 1355 strcpy(pathBuffer, "w*.c"); 1356 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1357 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); 1358 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError()); 1359 1360 /* There should be some content in the listbox. In particular, there should 1361 * be exactly the number of plain files, plus the number of mapped drives. 1362 */ 1363 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1364 ok (itemCount == itemCount_justFiles + itemCount_justDrives, 1365 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n", 1366 itemCount, itemCount_justFiles + itemCount_justDrives); 1367 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n"); 1368 1369 /* Every single item in the control should start with a w and end in .c, 1370 * except the mapped drives in the format "[-X-]". The "[..]" directory 1371 * should not appear. 1372 */ 1373 for (i = 0; i < itemCount; i++) 1374 { 1375 memset(pathBuffer, 0, MAX_PATH); 1376 driveletter = '\0'; 1377 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1378 p = pathBuffer + strlen(pathBuffer); 1379 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1380 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1381 else 1382 ok( 1383 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1384 (*(p-1) == 'c' || *(p-1) == 'C') && 1385 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1386 } 1387 1388 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */ 1389 strcpy(pathBuffer, wildcard); 1390 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1391 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1392 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", 1393 GetLastError()); 1394 1395 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1396 ok (itemCount == itemCount_allDirs, 1397 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1398 itemCount, itemCount_allDirs); 1399 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n"); 1400 1401 if (itemCount) 1402 { 1403 memset(pathBuffer, 0, MAX_PATH); 1404 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer); 1405 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer); 1406 } 1407 1408 /* This tests behavior when no files match the wildcard */ 1409 strcpy(pathBuffer, BAD_EXTENSION); 1410 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1411 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1412 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n", 1413 BAD_EXTENSION, res, -1); 1414 1415 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1416 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1); 1417 1418 1419 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */ 1420 strcpy(pathBuffer, "w*.c"); 1421 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1422 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1423 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR); 1424 1425 /* There should be no elements, since "[..]" does not fit w*.c */ 1426 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1427 ok (itemCount == 0, 1428 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1429 itemCount, 0); 1430 1431 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */ 1432 strcpy(pathBuffer, wildcard); 1433 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1434 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1435 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); 1436 1437 /* There should be no plain files on the listbox */ 1438 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1439 ok (itemCount == itemCount_justDrives + itemCount_allDirs, 1440 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1441 itemCount, itemCount_justDrives + itemCount_allDirs); 1442 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n"); 1443 1444 for (i = 0; i < itemCount; i++) 1445 { 1446 memset(pathBuffer, 0, MAX_PATH); 1447 driveletter = '\0'; 1448 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1449 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1450 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1451 else 1452 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', 1453 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer); 1454 } 1455 1456 /* This tests behavior when no files match the wildcard */ 1457 strcpy(pathBuffer, BAD_EXTENSION); 1458 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1459 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1460 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n", 1461 BAD_EXTENSION, res, itemCount_justDrives -1); 1462 1463 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1464 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1); 1465 1466 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */ 1467 strcpy(pathBuffer, "w*.c"); 1468 SendMessageA(hList, LB_RESETCONTENT, 0, 0); 1469 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); 1470 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); 1471 1472 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */ 1473 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0); 1474 ok (itemCount == itemCount_justDrives, 1475 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1476 itemCount, itemCount_justDrives); 1477 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n"); 1478 1479 for (i = 0; i < itemCount; i++) 1480 { 1481 memset(pathBuffer, 0, MAX_PATH); 1482 driveletter = '\0'; 1483 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer); 1484 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer); 1485 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1486 } 1487 DestroyWindow(hList); 1488 1489 DeleteFileA( "wtest1.tmp.c" ); 1490 RemoveDirectoryA("lb_dir_test"); 1491 1492 SetCurrentDirectoryA(curdir); 1493 } 1494 1495 static HWND g_listBox; 1496 static HWND g_label; 1497 1498 #define ID_TEST_LABEL 1001 1499 #define ID_TEST_LISTBOX 1002 1500 1501 static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs) 1502 { 1503 g_label = CreateWindowA(WC_STATICA, "Contents of static control before DlgDirList.", 1504 WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0); 1505 if (!g_label) return FALSE; 1506 1507 g_listBox = CreateWindowA(WC_LISTBOXA, "DlgDirList test", 1508 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256, 1509 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0); 1510 if (!g_listBox) return FALSE; 1511 1512 return TRUE; 1513 } 1514 1515 static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) 1516 { 1517 LRESULT result = 0; 1518 1519 switch (uiMsg) 1520 { 1521 case WM_DESTROY: 1522 PostQuitMessage(0); 1523 break; 1524 case WM_CREATE: 1525 result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1; 1526 break; 1527 default: 1528 result = DefWindowProcA(hwnd, uiMsg, wParam, lParam); 1529 break; 1530 } 1531 return result; 1532 } 1533 1534 static BOOL RegisterListboxWindowClass(HINSTANCE hInst) 1535 { 1536 WNDCLASSA cls; 1537 1538 cls.style = 0; 1539 cls.cbClsExtra = 0; 1540 cls.cbWndExtra = 0; 1541 cls.hInstance = hInst; 1542 cls.hIcon = NULL; 1543 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW); 1544 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 1545 cls.lpszMenuName = NULL; 1546 cls.lpfnWndProc = listbox_container_window_procA; 1547 cls.lpszClassName = "ListboxContainerClass"; 1548 if (!RegisterClassA (&cls)) return FALSE; 1549 1550 return TRUE; 1551 } 1552 1553 static void test_listbox_dlgdir(void) 1554 { 1555 HINSTANCE hInst; 1556 HWND hWnd; 1557 int res, itemCount; 1558 int itemCount_allDirs; 1559 int itemCount_justFiles; 1560 int itemCount_justDrives; 1561 int i; 1562 char pathBuffer[MAX_PATH]; 1563 char itemBuffer[MAX_PATH]; 1564 char tempBuffer[MAX_PATH]; 1565 char * p; 1566 char driveletter; 1567 HANDLE file; 1568 BOOL ret; 1569 1570 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); 1571 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError()); 1572 CloseHandle( file ); 1573 1574 /* NOTE: for this test to succeed, there must be no subdirectories 1575 under the current directory. In addition, there must be at least 1576 one file that fits the wildcard w*.c . Normally, the test 1577 directory itself satisfies both conditions. 1578 */ 1579 1580 hInst = GetModuleHandleA(0); 1581 ret = RegisterListboxWindowClass(hInst); 1582 ok(ret, "Failed to register test class.\n"); 1583 1584 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass", 1585 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 1586 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 1587 NULL, NULL, hInst, 0); 1588 ok(hWnd != NULL, "Failed to create container window.\n"); 1589 1590 /* Test for standard usage */ 1591 1592 /* The following should be overwritten by the directory path */ 1593 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents"); 1594 1595 /* This should list all the w*.c files in the test directory 1596 * As of this writing, this includes win.c, winstation.c, wsprintf.c 1597 */ 1598 strcpy(pathBuffer, "w*.c"); 1599 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0); 1600 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError()); 1601 1602 /* Path specification gets converted to uppercase */ 1603 ok (!strcmp(pathBuffer, "W*.C"), 1604 "expected conversion to uppercase, got %s\n", pathBuffer); 1605 1606 /* Loaded path should have overwritten the label text */ 1607 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer); 1608 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n"); 1609 1610 /* There should be some content in the listbox */ 1611 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1612 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n"); 1613 itemCount_justFiles = itemCount; 1614 1615 /* Every single item in the control should start with a w and end in .c */ 1616 for (i = 0; i < itemCount; i++) 1617 { 1618 memset(pathBuffer, 0, MAX_PATH); 1619 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1620 p = pathBuffer + strlen(pathBuffer); 1621 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1622 (*(p-1) == 'c' || *(p-1) == 'C') && 1623 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1624 } 1625 1626 /* Test behavior when no files match the wildcard */ 1627 strcpy(pathBuffer, BAD_EXTENSION); 1628 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0); 1629 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res); 1630 1631 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1632 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n"); 1633 1634 /* Test DDL_DIRECTORY */ 1635 strcpy(pathBuffer, "w*.c"); 1636 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY); 1637 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError()); 1638 1639 /* There should be some content in the listbox. In particular, there should 1640 * be exactly more elements than before, since the directories should 1641 * have been added. 1642 */ 1643 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1644 itemCount_allDirs = itemCount - itemCount_justFiles; 1645 ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n", 1646 itemCount, itemCount_justFiles); 1647 1648 /* Every single item in the control should start with a w and end in .c, 1649 * except for the "[..]" string, which should appear exactly as it is. 1650 */ 1651 for (i = 0; i < itemCount; i++) 1652 { 1653 memset(pathBuffer, 0, MAX_PATH); 1654 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1655 p = pathBuffer + strlen(pathBuffer); 1656 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') || 1657 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1658 (*(p-1) == 'c' || *(p-1) == 'C') && 1659 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1660 } 1661 1662 /* Test behavior when no files match the wildcard */ 1663 strcpy(pathBuffer, BAD_EXTENSION); 1664 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY); 1665 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res); 1666 1667 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1668 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n", 1669 itemCount_allDirs, itemCount); 1670 for (i = 0; i < itemCount; i++) 1671 { 1672 memset(pathBuffer, 0, MAX_PATH); 1673 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1674 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', 1675 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer); 1676 } 1677 1678 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */ 1679 strcpy(pathBuffer, "w*.c"); 1680 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES); 1681 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError()); 1682 1683 /* There should be some content in the listbox. In particular, there should 1684 * be at least one element before, since the string "[-c-]" should 1685 * have been added. Depending on the user setting, more drives might have 1686 * been added. 1687 */ 1688 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1689 ok (itemCount >= 1, 1690 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n", 1691 itemCount, 1); 1692 itemCount_justDrives = itemCount; 1693 1694 /* Every single item in the control should fit the format [-c-] */ 1695 for (i = 0; i < itemCount; i++) 1696 { 1697 memset(pathBuffer, 0, MAX_PATH); 1698 driveletter = '\0'; 1699 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1700 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" ); 1701 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer); 1702 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1703 if (!(driveletter >= 'a' && driveletter <= 'z')) { 1704 /* Correct after invalid entry is found */ 1705 trace("removing count of invalid entry %s\n", pathBuffer); 1706 itemCount_justDrives--; 1707 } 1708 } 1709 1710 /* Test behavior when no files match the wildcard */ 1711 strcpy(pathBuffer, BAD_EXTENSION); 1712 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES); 1713 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res); 1714 1715 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1716 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n"); 1717 1718 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */ 1719 strcpy(pathBuffer, "w*.c"); 1720 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES); 1721 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError()); 1722 1723 /* There should be some content in the listbox. In particular, there should 1724 * be exactly the number of plain files, plus the number of mapped drives, 1725 * plus one "[..]" 1726 */ 1727 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1728 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs, 1729 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n", 1730 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs); 1731 1732 /* Every single item in the control should start with a w and end in .c, 1733 * except for the "[..]" string, which should appear exactly as it is, 1734 * and the mapped drives in the format "[-X-]". 1735 */ 1736 for (i = 0; i < itemCount; i++) 1737 { 1738 memset(pathBuffer, 0, MAX_PATH); 1739 driveletter = '\0'; 1740 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1741 p = pathBuffer + strlen(pathBuffer); 1742 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1743 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1744 else 1745 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') || 1746 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && 1747 (*(p-1) == 'c' || *(p-1) == 'C') && 1748 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); 1749 } 1750 1751 /* Test behavior when no files match the wildcard */ 1752 strcpy(pathBuffer, BAD_EXTENSION); 1753 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES); 1754 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res); 1755 1756 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1757 ok (itemCount == itemCount_justDrives + itemCount_allDirs, 1758 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n", 1759 itemCount_justDrives + itemCount_allDirs, itemCount); 1760 1761 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */ 1762 strcpy(pathBuffer, "w*.c"); 1763 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE); 1764 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError()); 1765 1766 /* There should be exactly one element: "[..]" */ 1767 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1768 ok (itemCount == itemCount_allDirs, 1769 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1770 itemCount, itemCount_allDirs); 1771 1772 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */ 1773 { 1774 memset(pathBuffer, 0, MAX_PATH); 1775 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer); 1776 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n"); 1777 } 1778 1779 /* Test behavior when no files match the wildcard */ 1780 strcpy(pathBuffer, BAD_EXTENSION); 1781 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE); 1782 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res); 1783 1784 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1785 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n"); 1786 1787 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */ 1788 strcpy(pathBuffer, "w*.c"); 1789 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE); 1790 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError()); 1791 1792 /* There should be no plain files on the listbox */ 1793 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1794 ok (itemCount == itemCount_justDrives + itemCount_allDirs, 1795 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", 1796 itemCount, itemCount_justDrives + itemCount_allDirs); 1797 1798 for (i = 0; i < itemCount; i++) 1799 { 1800 memset(pathBuffer, 0, MAX_PATH); 1801 driveletter = '\0'; 1802 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); 1803 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) 1804 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); 1805 else 1806 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', 1807 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer); 1808 } 1809 1810 /* Test behavior when no files match the wildcard */ 1811 strcpy(pathBuffer, BAD_EXTENSION); 1812 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE); 1813 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res); 1814 1815 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1816 ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n"); 1817 1818 /* Now test DlgDirSelectEx() in normal operation */ 1819 /* Fill with everything - drives, directory and all plain files. */ 1820 strcpy(pathBuffer, "*"); 1821 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES); 1822 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError()); 1823 1824 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */ 1825 memset(pathBuffer, 0, MAX_PATH); 1826 SetLastError(0xdeadbeef); 1827 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1828 ok (GetLastError() == 0xdeadbeef, 1829 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n", 1830 GetLastError()); 1831 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res); 1832 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */ 1833 /* 1834 ok (!*pathBuffer, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer); 1835 */ 1836 /* Test proper drive/dir/file recognition */ 1837 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1838 for (i = 0; i < itemCount; i++) 1839 { 1840 memset(itemBuffer, 0, MAX_PATH); 1841 memset(pathBuffer, 0, MAX_PATH); 1842 memset(tempBuffer, 0, MAX_PATH); 1843 driveletter = '\0'; 1844 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer); 1845 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0); 1846 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i); 1847 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) 1848 { 1849 /* Current item is a drive letter */ 1850 SetLastError(0xdeadbeef); 1851 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1852 ok (GetLastError() == 0xdeadbeef, 1853 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1854 i, GetLastError()); 1855 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); 1856 1857 /* For drive letters, DlgDirSelectEx tacks on a colon */ 1858 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0', 1859 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter); 1860 } 1861 else if (itemBuffer[0] == '[') 1862 { 1863 /* Current item is the parent directory */ 1864 SetLastError(0xdeadbeef); 1865 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1866 ok (GetLastError() == 0xdeadbeef, 1867 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1868 i, GetLastError()); 1869 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); 1870 1871 /* For directories, DlgDirSelectEx tacks on a backslash */ 1872 p = pathBuffer + strlen(pathBuffer); 1873 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer); 1874 1875 tempBuffer[0] = '['; 1876 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer)); 1877 strcat(tempBuffer, "]"); 1878 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer); 1879 } 1880 else 1881 { 1882 /* Current item is a plain file */ 1883 SetLastError(0xdeadbeef); 1884 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1885 ok (GetLastError() == 0xdeadbeef, 1886 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1887 i, GetLastError()); 1888 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer); 1889 1890 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects 1891 * for example, "Makefile", which gets reported as "Makefile." 1892 */ 1893 strcpy(tempBuffer, itemBuffer); 1894 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, "."); 1895 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer); 1896 } 1897 } 1898 1899 DeleteFileA( "wtest1.tmp.c" ); 1900 1901 /* Now test DlgDirSelectEx() in abnormal operation */ 1902 /* Fill list with bogus entries, that look somewhat valid */ 1903 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0); 1904 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]"); 1905 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil"); 1906 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0); 1907 for (i = 0; i < itemCount; i++) 1908 { 1909 memset(itemBuffer, 0, MAX_PATH); 1910 memset(pathBuffer, 0, MAX_PATH); 1911 memset(tempBuffer, 0, MAX_PATH); 1912 driveletter = '\0'; 1913 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer); 1914 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0); 1915 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i); 1916 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) 1917 { 1918 /* Current item is a drive letter */ 1919 SetLastError(0xdeadbeef); 1920 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1921 ok (GetLastError() == 0xdeadbeef, 1922 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1923 i, GetLastError()); 1924 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); 1925 1926 /* For drive letters, DlgDirSelectEx tacks on a colon */ 1927 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0', 1928 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter); 1929 } 1930 else if (itemBuffer[0] == '[') 1931 { 1932 /* Current item is the parent directory */ 1933 SetLastError(0xdeadbeef); 1934 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1935 ok (GetLastError() == 0xdeadbeef, 1936 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1937 i, GetLastError()); 1938 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer); 1939 1940 /* For directories, DlgDirSelectEx tacks on a backslash */ 1941 p = pathBuffer + strlen(pathBuffer); 1942 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer); 1943 1944 tempBuffer[0] = '['; 1945 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer)); 1946 strcat(tempBuffer, "]"); 1947 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer); 1948 } 1949 else 1950 { 1951 /* Current item is a plain file */ 1952 SetLastError(0xdeadbeef); 1953 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX); 1954 ok (GetLastError() == 0xdeadbeef, 1955 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n", 1956 i, GetLastError()); 1957 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer); 1958 1959 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension. 1960 * This affects for example, "Makefile", which gets reported as "Makefile." 1961 */ 1962 strcpy(tempBuffer, itemBuffer); 1963 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, "."); 1964 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer); 1965 } 1966 } 1967 1968 /* Test behavior when loading folders from root with and without wildcard */ 1969 strcpy(pathBuffer, "C:\\"); 1970 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); 1971 ok(res, "DlgDirList failed to list C:\\ folders\n"); 1972 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer); 1973 1974 strcpy(pathBuffer, "C:\\*"); 1975 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); 1976 ok(res, "DlgDirList failed to list C:\\* folders\n"); 1977 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer); 1978 1979 /* Try loading files from an invalid folder */ 1980 SetLastError(0xdeadbeef); 1981 strcpy(pathBuffer, "C:\\INVALID$$DIR"); 1982 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE); 1983 ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res); 1984 ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS, 1985 "GetLastError should return 0x589, got 0x%X\n",GetLastError()); 1986 1987 DestroyWindow(hWnd); 1988 } 1989 1990 static void test_set_count( void ) 1991 { 1992 static const DWORD styles[] = 1993 { 1994 LBS_OWNERDRAWFIXED, 1995 LBS_HASSTRINGS, 1996 }; 1997 HWND parent, listbox; 1998 unsigned int i; 1999 LONG ret; 2000 RECT r; 2001 2002 parent = create_parent(); 2003 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent ); 2004 2005 UpdateWindow( listbox ); 2006 GetUpdateRect( listbox, &r, TRUE ); 2007 ok( IsRectEmpty( &r ), "got non-empty rect\n"); 2008 2009 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 ); 2010 ok( ret == 0, "got %d\n", ret ); 2011 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 ); 2012 ok( ret == 100, "got %d\n", ret ); 2013 2014 GetUpdateRect( listbox, &r, TRUE ); 2015 ok( !IsRectEmpty( &r ), "got empty rect\n"); 2016 2017 ValidateRect( listbox, NULL ); 2018 GetUpdateRect( listbox, &r, TRUE ); 2019 ok( IsRectEmpty( &r ), "got non-empty rect\n"); 2020 2021 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 ); 2022 ok( ret == 0, "got %d\n", ret ); 2023 2024 GetUpdateRect( listbox, &r, TRUE ); 2025 ok( !IsRectEmpty( &r ), "got empty rect\n"); 2026 2027 ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 ); 2028 ok( ret == 0, "got %d\n", ret ); 2029 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 ); 2030 ok( ret == -5, "got %d\n", ret ); 2031 2032 DestroyWindow( listbox ); 2033 2034 for (i = 0; i < ARRAY_SIZE(styles); ++i) 2035 { 2036 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent ); 2037 2038 SetLastError( 0xdeadbeef ); 2039 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 ); 2040 ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret ); 2041 ok( GetLastError() == 0xdeadbeef, "Unexpected error %d.\n", GetLastError() ); 2042 2043 DestroyWindow( listbox ); 2044 } 2045 2046 DestroyWindow( parent ); 2047 } 2048 2049 static void test_GetListBoxInfo(void) 2050 { 2051 static const struct message getlistboxinfo_seq[] = 2052 { 2053 { LB_GETLISTBOXINFO, sent }, 2054 { 0 } 2055 }; 2056 HWND listbox, parent; 2057 DWORD ret; 2058 2059 parent = create_parent(); 2060 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent); 2061 2062 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2063 ret = GetListBoxInfo(listbox); 2064 ok(ret > 0, "got %d\n", ret); 2065 ok_sequence(sequences, LB_SEQ_INDEX, getlistboxinfo_seq, "GetListBoxInfo()", FALSE); 2066 2067 DestroyWindow(listbox); 2068 DestroyWindow(parent); 2069 } 2070 2071 static void test_init_storage( void ) 2072 { 2073 static const DWORD styles[] = 2074 { 2075 LBS_HASSTRINGS, 2076 LBS_NODATA | LBS_OWNERDRAWFIXED, 2077 }; 2078 HWND parent, listbox; 2079 LONG ret, items_size; 2080 int i, j; 2081 2082 parent = create_parent(); 2083 for (i = 0; i < ARRAY_SIZE(styles); i++) 2084 { 2085 listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | WS_CHILD, 2086 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0); 2087 2088 items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0); 2089 ok(items_size >= 100, "expected at least 100, got %d\n", items_size); 2090 2091 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); 2092 ok(ret == items_size, "expected %d, got %d\n", items_size, ret); 2093 2094 /* it doesn't grow since the space was already reserved */ 2095 ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0); 2096 ok(ret == items_size, "expected %d, got %d\n", items_size, ret); 2097 2098 /* it doesn't shrink the reserved space */ 2099 ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0); 2100 ok(ret == items_size, "expected %d, got %d\n", items_size, ret); 2101 2102 /* now populate almost all of it so it's not reserved anymore */ 2103 if (styles[i] & LBS_NODATA) 2104 { 2105 ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0); 2106 ok(ret == 0, "unexpected return value %d\n", ret); 2107 } 2108 else 2109 { 2110 for (j = 0; j < items_size - 1; j++) 2111 { 2112 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)""); 2113 ok(ret == j, "expected %d, got %d\n", j, ret); 2114 } 2115 } 2116 2117 /* we still have one more reserved slot, so it doesn't grow yet */ 2118 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0); 2119 ok(ret == items_size, "expected %d, got %d\n", items_size, ret); 2120 2121 /* fill the slot and check again, it should grow this time */ 2122 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)""); 2123 ok(ret == items_size - 1, "expected %d, got %d\n", items_size - 1, ret); 2124 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0); 2125 ok(ret == items_size, "expected %d, got %d\n", items_size, ret); 2126 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0); 2127 ok(ret > items_size, "expected it to grow past %d, got %d\n", items_size, ret); 2128 2129 DestroyWindow(listbox); 2130 } 2131 DestroyWindow(parent); 2132 } 2133 2134 static void test_missing_lbuttonup(void) 2135 { 2136 HWND listbox, parent, capture; 2137 2138 parent = create_parent(); 2139 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent); 2140 2141 /* Send button down without a corresponding button up */ 2142 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10)); 2143 capture = GetCapture(); 2144 ok(capture == listbox, "got %p expected %p\n", capture, listbox); 2145 2146 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */ 2147 got_selchange = 0; 2148 SetFocus(NULL); 2149 capture = GetCapture(); 2150 ok(capture == NULL, "got %p\n", capture); 2151 ok(got_selchange, "got %d\n", got_selchange); 2152 2153 DestroyWindow(listbox); 2154 DestroyWindow(parent); 2155 } 2156 2157 static void test_extents(void) 2158 { 2159 HWND listbox, parent; 2160 SCROLLINFO sinfo; 2161 DWORD res; 2162 BOOL br; 2163 2164 parent = create_parent(); 2165 2166 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent); 2167 2168 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2169 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); 2170 2171 sinfo.cbSize = sizeof(sinfo); 2172 sinfo.fMask = SIF_RANGE; 2173 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2174 ok(br == TRUE, "GetScrollInfo failed\n"); 2175 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2176 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax); 2177 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2178 "List box should not have a horizontal scroll bar\n"); 2179 2180 /* horizontal extent < width */ 2181 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); 2182 2183 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2184 ok(res == 64, "Got wrong horizontal extent: %u\n", res); 2185 2186 sinfo.cbSize = sizeof(sinfo); 2187 sinfo.fMask = SIF_RANGE; 2188 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2189 ok(br == TRUE, "GetScrollInfo failed\n"); 2190 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2191 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax); 2192 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2193 "List box should not have a horizontal scroll bar\n"); 2194 2195 /* horizontal extent > width */ 2196 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); 2197 2198 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2199 ok(res == 184, "Got wrong horizontal extent: %u\n", res); 2200 2201 sinfo.cbSize = sizeof(sinfo); 2202 sinfo.fMask = SIF_RANGE; 2203 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2204 ok(br == TRUE, "GetScrollInfo failed\n"); 2205 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2206 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax); 2207 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2208 "List box should not have a horizontal scroll bar\n"); 2209 2210 DestroyWindow(listbox); 2211 2212 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent); 2213 2214 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2215 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); 2216 2217 sinfo.cbSize = sizeof(sinfo); 2218 sinfo.fMask = SIF_RANGE; 2219 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2220 ok(br == TRUE, "GetScrollInfo failed\n"); 2221 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2222 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax); 2223 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2224 "List box should not have a horizontal scroll bar\n"); 2225 2226 /* horizontal extent < width */ 2227 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); 2228 2229 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2230 ok(res == 64, "Got wrong horizontal extent: %u\n", res); 2231 2232 sinfo.cbSize = sizeof(sinfo); 2233 sinfo.fMask = SIF_RANGE; 2234 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2235 ok(br == TRUE, "GetScrollInfo failed\n"); 2236 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2237 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax); 2238 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2239 "List box should not have a horizontal scroll bar\n"); 2240 2241 /* horizontal extent > width */ 2242 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); 2243 2244 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2245 ok(res == 184, "Got wrong horizontal extent: %u\n", res); 2246 2247 sinfo.cbSize = sizeof(sinfo); 2248 sinfo.fMask = SIF_RANGE; 2249 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2250 ok(br == TRUE, "GetScrollInfo failed\n"); 2251 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2252 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax); 2253 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0, 2254 "List box should have a horizontal scroll bar\n"); 2255 2256 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0); 2257 2258 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2259 ok(res == 0, "Got wrong horizontal extent: %u\n", res); 2260 2261 sinfo.cbSize = sizeof(sinfo); 2262 sinfo.fMask = SIF_RANGE; 2263 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2264 ok(br == TRUE, "GetScrollInfo failed\n"); 2265 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2266 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax); 2267 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0, 2268 "List box should not have a horizontal scroll bar\n"); 2269 2270 DestroyWindow(listbox); 2271 2272 2273 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent); 2274 2275 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2276 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res); 2277 2278 sinfo.cbSize = sizeof(sinfo); 2279 sinfo.fMask = SIF_RANGE; 2280 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2281 ok(br == TRUE, "GetScrollInfo failed\n"); 2282 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2283 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax); 2284 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0, 2285 "List box should have a horizontal scroll bar\n"); 2286 2287 /* horizontal extent < width */ 2288 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0); 2289 2290 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2291 ok(res == 64, "Got wrong horizontal extent: %u\n", res); 2292 2293 sinfo.cbSize = sizeof(sinfo); 2294 sinfo.fMask = SIF_RANGE; 2295 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2296 ok(br == TRUE, "GetScrollInfo failed\n"); 2297 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2298 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax); 2299 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0, 2300 "List box should have a horizontal scroll bar\n"); 2301 2302 /* horizontal extent > width */ 2303 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0); 2304 2305 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2306 ok(res == 184, "Got wrong horizontal extent: %u\n", res); 2307 2308 sinfo.cbSize = sizeof(sinfo); 2309 sinfo.fMask = SIF_RANGE; 2310 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2311 ok(br == TRUE, "GetScrollInfo failed\n"); 2312 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2313 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax); 2314 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0, 2315 "List box should have a horizontal scroll bar\n"); 2316 2317 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0); 2318 2319 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0); 2320 ok(res == 0, "Got wrong horizontal extent: %u\n", res); 2321 2322 sinfo.cbSize = sizeof(sinfo); 2323 sinfo.fMask = SIF_RANGE; 2324 br = GetScrollInfo(listbox, SB_HORZ, &sinfo); 2325 ok(br == TRUE, "GetScrollInfo failed\n"); 2326 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin); 2327 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax); 2328 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0, 2329 "List box should have a horizontal scroll bar\n"); 2330 2331 DestroyWindow(listbox); 2332 2333 DestroyWindow(parent); 2334 } 2335 2336 static void test_listbox(void) 2337 { 2338 static const struct listbox_test SS = 2339 /* {add_style} */ 2340 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, 2341 { 1, 1, 1, LB_ERR}, {0,0,0,0}, 2342 { 2, 2, 2, LB_ERR}, {0,0,0,0}, 2343 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; 2344 2345 /* {selected, anchor, caret, selcount}{TODO fields} */ 2346 static const struct listbox_test SS_NS = 2347 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, 2348 { 1, 1, 1, LB_ERR}, {0,0,0,0}, 2349 { 2, 2, 2, LB_ERR}, {0,0,0,0}, 2350 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; 2351 2352 static const struct listbox_test MS = 2353 {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, 2354 { 1, 1, 1, 1}, {0,0,0,0}, 2355 { 2, 1, 2, 1}, {0,0,0,0}, 2356 { 0, LB_ERR, 0, 2}, {0,0,0,0}}; 2357 2358 static const struct listbox_test MS_NS = 2359 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, 2360 { 1, 1, 1, LB_ERR}, {0,0,0,0}, 2361 { 2, 2, 2, LB_ERR}, {0,0,0,0}, 2362 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; 2363 2364 static const struct listbox_test ES = 2365 {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, 2366 { 1, 1, 1, 1}, {0,0,0,0}, 2367 { 2, 2, 2, 1}, {0,0,0,0}, 2368 { 0, LB_ERR, 0, 2}, {0,0,0,0}}; 2369 2370 static const struct listbox_test ES_NS = 2371 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, 2372 { 1, 1, 1, LB_ERR}, {0,0,0,0}, 2373 { 2, 2, 2, LB_ERR}, {0,0,0,0}, 2374 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; 2375 2376 static const struct listbox_test EMS = 2377 {{ 0, LB_ERR, 0, 0}, {0,0,0,0}, 2378 { 1, 1, 1, 1}, {0,0,0,0}, 2379 { 2, 2, 2, 1}, {0,0,0,0}, 2380 { 0, LB_ERR, 0, 2}, {0,0,0,0}}; 2381 2382 static const struct listbox_test EMS_NS = 2383 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, 2384 { 1, 1, 1, LB_ERR}, {0,0,0,0}, 2385 { 2, 2, 2, LB_ERR}, {0,0,0,0}, 2386 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}}; 2387 2388 run_test(0, SS); 2389 run_test(LBS_NOSEL, SS_NS); 2390 run_test(LBS_MULTIPLESEL, MS); 2391 run_test(LBS_MULTIPLESEL | LBS_NOSEL, MS_NS); 2392 run_test(LBS_EXTENDEDSEL, ES); 2393 run_test(LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS); 2394 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS); 2395 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS); 2396 2397 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED, SS); 2398 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS); 2399 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS); 2400 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS); 2401 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES); 2402 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS); 2403 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS); 2404 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS); 2405 } 2406 2407 static const struct message lb_addstring_ownerdraw_parent_seq[] = 2408 { 2409 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed }, 2410 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee }, 2411 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef }, 2412 { 0 } 2413 }; 2414 2415 static const struct message lb_addstring_sort_parent_seq[] = 2416 { 2417 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed }, 2418 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee }, 2419 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee }, 2420 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef }, 2421 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef }, 2422 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef }, 2423 { 0 } 2424 }; 2425 2426 static const struct message empty_seq[] = 2427 { 2428 { 0 } 2429 }; 2430 2431 static void test_WM_MEASUREITEM(void) 2432 { 2433 HWND parent, listbox; 2434 LRESULT data, ret; 2435 2436 parent = create_parent(); 2437 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent); 2438 2439 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0); 2440 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]); 2441 DestroyWindow(parent); 2442 2443 parent = create_parent(); 2444 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent); 2445 2446 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0); 2447 ok(!data, "data = %08lx\n", data); 2448 2449 /* LBS_HASSTRINGS */ 2450 parent = create_parent(); 2451 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL, 2452 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE, 2453 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); 2454 2455 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2456 2457 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); 2458 ok(ret == 0, "expected 0, got %ld\n", ret); 2459 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); 2460 ok(ret == 1, "expected 1, got %ld\n", ret); 2461 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); 2462 ok(ret == 2, "expected 2, got %ld\n", ret); 2463 2464 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq, 2465 "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE); 2466 DestroyWindow(listbox); 2467 2468 /* LBS_SORT, no LBS_HASSTRINGS */ 2469 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL, 2470 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE, 2471 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); 2472 2473 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2474 2475 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); 2476 ok(ret == 0, "expected 0, got %ld\n", ret); 2477 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); 2478 ok(ret == 1, "expected 1, got %ld\n", ret); 2479 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); 2480 ok(ret == 2, "expected 2, got %ld\n", ret); 2481 2482 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", FALSE); 2483 DestroyWindow(listbox); 2484 2485 /* LBS_HASSTRINGS */ 2486 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL, 2487 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE, 2488 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); 2489 2490 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2491 2492 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); 2493 ok(ret == 0, "expected 0, got %ld\n", ret); 2494 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); 2495 ok(ret == 1, "expected 1, got %ld\n", ret); 2496 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); 2497 ok(ret == 2, "expected 2, got %ld\n", ret); 2498 2499 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE); 2500 DestroyWindow(listbox); 2501 2502 /* LBS_HASSTRINGS, LBS_SORT */ 2503 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL, 2504 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE, 2505 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); 2506 2507 flush_sequences(sequences, NUM_MSG_SEQUENCES); 2508 2509 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); 2510 ok(ret == 0, "expected 0, got %ld\n", ret); 2511 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); 2512 ok(ret == 0, "expected 0, got %ld\n", ret); 2513 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); 2514 ok(ret == 1, "expected 1, got %ld\n", ret); 2515 2516 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE); 2517 DestroyWindow(listbox); 2518 2519 DestroyWindow(parent); 2520 } 2521 2522 static void test_LBS_NODATA(void) 2523 { 2524 static const DWORD invalid_styles[] = 2525 { 2526 0, 2527 LBS_OWNERDRAWVARIABLE, 2528 LBS_SORT, 2529 LBS_HASSTRINGS, 2530 LBS_OWNERDRAWFIXED | LBS_SORT, 2531 LBS_OWNERDRAWFIXED | LBS_HASSTRINGS, 2532 }; 2533 static const UINT invalid_idx[] = { -2, 2 }; 2534 static const UINT valid_idx[] = { 0, 1 }; 2535 static const ULONG_PTR zero_data; 2536 HWND listbox, parent; 2537 INT ret, text_len; 2538 unsigned int i; 2539 ULONG_PTR data; 2540 BOOL is_wow64; 2541 2542 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE, 2543 0, 0, 100, 100, NULL, NULL, NULL, 0); 2544 ok(listbox != NULL, "Failed to create ListBox window.\n"); 2545 2546 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0); 2547 ok(ret == 0, "Unexpected return value %d.\n", ret); 2548 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0); 2549 ok(ret == 1, "Unexpected return value %d.\n", ret); 2550 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0); 2551 ok(ret == 2, "Unexpected return value %d.\n", ret); 2552 2553 /* Invalid indices. */ 2554 for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i) 2555 { 2556 ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42); 2557 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2558 ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0); 2559 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2560 if (ret == LB_ERR) 2561 { 2562 ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data); 2563 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2564 } 2565 ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0); 2566 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2567 } 2568 2569 IsWow64Process(GetCurrentProcess(), &is_wow64); 2570 #ifdef _WIN64 2571 text_len = 8; 2572 #else 2573 text_len = is_wow64 ? 8 : 4; 2574 #endif 2575 2576 /* Valid indices. */ 2577 for (i = 0; i < ARRAY_SIZE(valid_idx); ++i) 2578 { 2579 ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42); 2580 ok(ret == TRUE, "Unexpected return value %d.\n", ret); 2581 ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0); 2582 todo_wine_if(is_wow64) 2583 ok(ret == text_len, "Unexpected return value %d.\n", ret); 2584 2585 memset(&data, 0xee, sizeof(data)); 2586 ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data); 2587 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret); 2588 ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n"); 2589 2590 ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0); 2591 ok(ret == 0, "Unexpected return value %d.\n", ret); 2592 } 2593 2594 /* More messages that don't work with LBS_NODATA. */ 2595 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0); 2596 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2597 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42); 2598 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2599 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0); 2600 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2601 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42); 2602 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2603 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0); 2604 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2605 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42); 2606 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret); 2607 2608 DestroyWindow(listbox); 2609 2610 /* Invalid window style combinations. */ 2611 parent = create_parent(); 2612 ok(parent != NULL, "Failed to create parent window.\n"); 2613 2614 for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i) 2615 { 2616 DWORD style; 2617 2618 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i], 2619 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0); 2620 ok(listbox != NULL, "Failed to create a listbox.\n"); 2621 2622 style = GetWindowLongA(listbox, GWL_STYLE); 2623 ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style); 2624 ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0); 2625 ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret); 2626 DestroyWindow(listbox); 2627 } 2628 2629 DestroyWindow(parent); 2630 } 2631 2632 START_TEST(listbox) 2633 { 2634 ULONG_PTR ctx_cookie; 2635 HANDLE hCtx; 2636 2637 if (!load_v6_module(&ctx_cookie, &hCtx)) 2638 return; 2639 2640 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 2641 2642 test_listbox(); 2643 test_item_height(); 2644 test_ownerdraw(); 2645 test_LB_SELITEMRANGE(); 2646 test_LB_SETCURSEL(); 2647 test_listbox_height(); 2648 test_changing_selection_styles(); 2649 test_itemfrompoint(); 2650 test_listbox_item_data(); 2651 test_listbox_LB_DIR(); 2652 test_listbox_dlgdir(); 2653 test_set_count(); 2654 test_init_storage(); 2655 test_GetListBoxInfo(); 2656 test_missing_lbuttonup(); 2657 test_extents(); 2658 test_WM_MEASUREITEM(); 2659 test_LB_SETSEL(); 2660 test_LBS_NODATA(); 2661 2662 unload_v6_module(ctx_cookie, hCtx); 2663 } 2664