user32/listbox: Make SetCount fail if LBS_NODATA is not set.
[wine.git] / dlls / user32 / tests / listbox.c
blob813968f3d6abd35c5a3fefc2b68a48497e296ed7
1 /* Unit test suite for list boxes.
3 * Copyright 2003 Ferenc Wagner
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.
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.
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
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
30 #include "wine/test.h"
32 #ifdef VISIBLE
33 #define WAIT Sleep (1000)
34 #define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW)
35 #else
36 #define WAIT
37 #define REDRAW
38 #endif
40 static const char * const strings[4] = {
41 "First added",
42 "Second added",
43 "Third added",
44 "Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters."
47 static const char BAD_EXTENSION[] = "*.badtxt";
49 static int strcmp_aw(LPCWSTR strw, const char *stra)
51 WCHAR buf[1024];
53 if (!stra) return 1;
54 MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, ARRAY_SIZE(buf));
55 return lstrcmpW(strw, buf);
58 static HWND
59 create_listbox (DWORD add_style, HWND parent)
61 HWND handle;
62 INT_PTR ctl_id=0;
63 if (parent)
64 ctl_id=1;
65 handle=CreateWindowA("LISTBOX", "TestList",
66 (LBS_STANDARD & ~LBS_SORT) | add_style,
67 0, 0, 100, 100,
68 parent, (HMENU)ctl_id, NULL, 0);
70 assert (handle);
71 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
72 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
73 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
74 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
76 #ifdef VISIBLE
77 ShowWindow (handle, SW_SHOW);
78 #endif
79 REDRAW;
81 return handle;
84 struct listbox_prop {
85 DWORD add_style;
88 struct listbox_stat {
89 int selected, anchor, caret, selcount;
92 struct listbox_test {
93 struct listbox_stat init, init_todo;
94 struct listbox_stat click, click_todo;
95 struct listbox_stat step, step_todo;
96 struct listbox_stat sel, sel_todo;
99 static void
100 listbox_query (HWND handle, struct listbox_stat *results)
102 results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
103 results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
104 results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
105 results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
108 static void
109 buttonpress (HWND handle, WORD x, WORD y)
111 LPARAM lp=x+(y<<16);
113 WAIT;
114 SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
115 SendMessageA(handle, WM_LBUTTONUP, 0, lp);
116 REDRAW;
119 static void
120 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
122 LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
124 WAIT;
125 SendMessageA(handle, WM_KEYDOWN, keycode, lp);
126 SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000);
127 REDRAW;
130 #define listbox_field_ok(t, s, f, got) \
131 ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
132 ": expected %d, got %d\n", style, t.s.f, got.f)
134 #define listbox_todo_field_ok(t, s, f, got) \
135 todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
137 #define listbox_ok(t, s, got) \
138 listbox_todo_field_ok(t, s, selected, got); \
139 listbox_todo_field_ok(t, s, anchor, got); \
140 listbox_todo_field_ok(t, s, caret, got); \
141 listbox_todo_field_ok(t, s, selcount, got)
143 static void
144 check (DWORD style, const struct listbox_test test)
146 struct listbox_stat answer;
147 RECT second_item;
148 int i;
149 int res;
150 HWND hLB;
152 hLB = create_listbox (style, 0);
154 listbox_query (hLB, &answer);
155 listbox_ok (test, init, answer);
157 SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
158 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
160 listbox_query (hLB, &answer);
161 listbox_ok (test, click, answer);
163 keypress (hLB, VK_DOWN, 0x50, TRUE);
165 listbox_query (hLB, &answer);
166 listbox_ok (test, step, answer);
168 DestroyWindow (hLB);
169 hLB = create_listbox(style, 0);
171 SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
172 listbox_query (hLB, &answer);
173 listbox_ok (test, sel, answer);
175 for (i = 0; i < 4 && !(style & LBS_NODATA); i++) {
176 DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
177 CHAR *txt;
178 WCHAR *txtw;
179 int resA, resW;
181 txt = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, size+1);
182 resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
183 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
185 txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2);
186 resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
187 ok(resA == resW, "Unexpected text length.\n");
188 WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
189 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
191 HeapFree (GetProcessHeap(), 0, txtw);
192 HeapFree (GetProcessHeap(), 0, txt);
195 /* Confirm the count of items, and that an invalid delete does not remove anything */
196 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
197 ok((res==4), "Expected 4 items, got %d\n", res);
198 res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
199 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
200 res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
201 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
202 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
203 ok((res==4), "Expected 4 items, got %d\n", res);
205 WAIT;
206 DestroyWindow (hLB);
209 static void check_item_height(void)
211 HWND hLB;
212 HDC hdc;
213 HFONT font;
214 TEXTMETRICA tm;
215 INT itemHeight;
217 hLB = create_listbox (0, 0);
218 ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
219 ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
220 ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
221 ReleaseDC( hLB, hdc);
223 ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
225 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
226 ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
228 DestroyWindow (hLB);
230 hLB = CreateWindowA("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE,
231 0, 0, 100, 100, NULL, NULL, NULL, 0);
232 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
233 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
234 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
235 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
236 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
237 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
238 DestroyWindow (hLB);
241 static int got_selchange;
243 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
245 switch (msg)
247 case WM_MEASUREITEM:
249 DWORD style = GetWindowLongA(GetWindow(hwnd, GW_CHILD), GWL_STYLE);
250 MEASUREITEMSTRUCT *mi = (void*)lparam;
252 ok(wparam == mi->CtlID, "got wParam=%08lx, expected %08x\n", wparam, mi->CtlID);
253 ok(mi->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mi->CtlType);
254 ok(mi->CtlID == 1, "mi->CtlID = %u\n", mi->CtlID);
255 ok(mi->itemHeight, "mi->itemHeight = 0\n");
257 if (mi->itemID > 4 || style & LBS_OWNERDRAWFIXED)
258 break;
260 if (style & LBS_HASSTRINGS)
262 ok(!strcmp_aw((WCHAR*)mi->itemData, strings[mi->itemID]),
263 "mi->itemData = %s (%d)\n", wine_dbgstr_w((WCHAR*)mi->itemData), mi->itemID);
265 else
267 ok((void*)mi->itemData == strings[mi->itemID],
268 "mi->itemData = %08lx, expected %p\n", mi->itemData, strings[mi->itemID]);
270 break;
272 case WM_DRAWITEM:
274 RECT rc_item, rc_client, rc_clip;
275 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
277 trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam);
279 ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n",
280 wparam, dis->CtlID);
281 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
283 GetClientRect(dis->hwndItem, &rc_client);
284 trace("hwndItem %p client rect %s\n", dis->hwndItem, wine_dbgstr_rect(&rc_client));
285 GetClipBox(dis->hDC, &rc_clip);
286 trace("clip rect %s\n", wine_dbgstr_rect(&rc_clip));
287 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
288 "client rect of the listbox should be equal to the clip box,"
289 "or the clip box should be empty\n");
291 trace("rcItem %s\n", wine_dbgstr_rect(&dis->rcItem));
292 SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
293 trace("item rect %s\n", wine_dbgstr_rect(&rc_item));
294 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
296 break;
299 case WM_COMMAND:
300 if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
301 break;
303 default:
304 break;
307 return DefWindowProcA(hwnd, msg, wparam, lparam);
310 static HWND create_parent( void )
312 WNDCLASSA cls;
313 HWND parent;
314 static ATOM class;
316 if (!class)
318 cls.style = 0;
319 cls.lpfnWndProc = main_window_proc;
320 cls.cbClsExtra = 0;
321 cls.cbWndExtra = 0;
322 cls.hInstance = GetModuleHandleA(NULL);
323 cls.hIcon = 0;
324 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
325 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
326 cls.lpszMenuName = NULL;
327 cls.lpszClassName = "main_window_class";
328 class = RegisterClassA( &cls );
331 parent = CreateWindowExA(0, "main_window_class", NULL,
332 WS_POPUP | WS_VISIBLE,
333 100, 100, 400, 400,
334 GetDesktopWindow(), 0,
335 GetModuleHandleA(NULL), NULL);
336 return parent;
339 static void test_ownerdraw(void)
341 HWND parent, hLB;
342 INT ret;
343 RECT rc;
345 parent = create_parent();
346 assert(parent);
348 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
349 assert(hLB);
351 SetForegroundWindow(hLB);
352 UpdateWindow(hLB);
354 /* make height short enough */
355 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
356 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
357 SWP_NOZORDER | SWP_NOMOVE);
359 /* make 0 item invisible */
360 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
361 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
362 ok(ret == 1, "wrong top index %d\n", ret);
364 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
365 trace("item 0 rect %s\n", wine_dbgstr_rect(&rc));
366 ok(!IsRectEmpty(&rc), "empty item rect\n");
367 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
369 DestroyWindow(hLB);
371 /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
372 hLB = CreateWindowA("listbox", "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100,
373 NULL, NULL, NULL, 0);
374 ok(hLB != NULL, "last error 0x%08x\n", GetLastError());
376 ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n");
378 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
379 ok(ret == 0, "Unexpected return value %d.\n", ret);
380 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
381 ok(ret == 1, "Unexpected return value %d.\n", ret);
383 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
384 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
386 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
387 ok(ret == 13, "Unexpected item height %d.\n", ret);
389 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
390 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
392 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
393 ok(ret == 42, "Unexpected item height %d.\n", ret);
395 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
396 ok(ret == 42, "Unexpected item height %d.\n", ret);
398 DestroyWindow (hLB);
400 DestroyWindow(parent);
403 #define listbox_test_query(exp, got) \
404 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
405 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
406 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
407 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
409 static void test_LB_SELITEMRANGE(void)
411 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
412 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
413 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
414 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
415 HWND hLB;
416 struct listbox_stat answer;
417 INT ret;
419 trace("testing LB_SELITEMRANGE\n");
421 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
422 assert(hLB);
424 listbox_query(hLB, &answer);
425 listbox_test_query(test_nosel, answer);
427 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
428 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
429 listbox_query(hLB, &answer);
430 listbox_test_query(test_1, answer);
432 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
433 listbox_query(hLB, &answer);
434 listbox_test_query(test_nosel, answer);
436 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
437 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
438 listbox_query(hLB, &answer);
439 listbox_test_query(test_3, answer);
441 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
442 listbox_query(hLB, &answer);
443 listbox_test_query(test_nosel, answer);
445 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
446 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
447 listbox_query(hLB, &answer);
448 listbox_test_query(test_nosel, answer);
450 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
451 listbox_query(hLB, &answer);
452 listbox_test_query(test_nosel, answer);
454 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
455 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
456 listbox_query(hLB, &answer);
457 listbox_test_query(test_1, answer);
459 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
460 listbox_query(hLB, &answer);
461 listbox_test_query(test_nosel, answer);
463 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
464 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
465 listbox_query(hLB, &answer);
466 listbox_test_query(test_nosel, answer);
468 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
469 listbox_query(hLB, &answer);
470 listbox_test_query(test_nosel, answer);
472 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
473 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
474 listbox_query(hLB, &answer);
475 listbox_test_query(test_2, answer);
477 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
478 listbox_query(hLB, &answer);
479 listbox_test_query(test_nosel, answer);
481 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
482 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
483 listbox_query(hLB, &answer);
484 listbox_test_query(test_2, answer);
486 DestroyWindow(hLB);
489 static void test_LB_SETCURSEL(void)
491 HWND parent, hLB;
492 INT ret;
494 trace("testing LB_SETCURSEL\n");
496 parent = create_parent();
497 assert(parent);
499 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
500 assert(hLB);
502 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
504 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
505 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
507 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
508 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
509 ret = GetScrollPos(hLB, SB_VERT);
510 ok(ret == 0, "expected vscroll 0, got %d\n", ret);
512 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
513 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
515 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
516 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
517 ret = GetScrollPos(hLB, SB_VERT);
518 ok(ret == 1, "expected vscroll 1, got %d\n", ret);
520 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
521 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
523 DestroyWindow(hLB);
525 hLB = create_listbox(0, 0);
526 ok(hLB != NULL, "Failed to create ListBox window.\n");
528 ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
529 ok(ret == 1, "Unexpected return value %d.\n", ret);
531 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
532 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
534 DestroyWindow(hLB);
536 /* LBS_EXTENDEDSEL */
537 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
538 ok(hLB != NULL, "Failed to create ListBox window.\n");
540 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
541 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
543 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
544 ok(ret == -1, "Unexpected return value %d.\n", ret);
546 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
547 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
549 DestroyWindow(hLB);
551 /* LBS_MULTIPLESEL */
552 hLB = create_listbox(LBS_MULTIPLESEL, 0);
553 ok(hLB != NULL, "Failed to create ListBox window.\n");
555 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
556 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
558 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
559 ok(ret == -1, "Unexpected return value %d.\n", ret);
561 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
562 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
564 DestroyWindow(hLB);
567 static void test_LB_SETSEL(void)
569 HWND list;
570 int ret;
572 /* LBS_EXTENDEDSEL */
573 list = create_listbox(LBS_EXTENDEDSEL, 0);
574 ok(list != NULL, "Failed to create ListBox window.\n");
576 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
577 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
579 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
580 ok(ret == 0, "Unexpected return value %d.\n", ret);
581 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
582 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
584 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
585 ok(ret == 0, "Unexpected return value %d.\n", ret);
586 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
587 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
589 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
590 ok(ret == 0, "Unexpected return value %d.\n", ret);
591 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
592 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
594 DestroyWindow(list);
596 /* LBS_MULTIPLESEL */
597 list = create_listbox(LBS_MULTIPLESEL, 0);
598 ok(list != NULL, "Failed to create ListBox window.\n");
600 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
601 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
603 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
604 ok(ret == 0, "Unexpected return value %d.\n", ret);
605 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
606 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
608 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
609 ok(ret == 0, "Unexpected return value %d.\n", ret);
610 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
611 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
613 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
614 ok(ret == 0, "Unexpected return value %d.\n", ret);
615 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
616 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
618 DestroyWindow(list);
621 static void test_listbox_height(void)
623 HWND hList;
624 int r, id;
626 hList = CreateWindowA( "ListBox", "list test", 0,
627 1, 1, 600, 100, NULL, NULL, NULL, NULL );
628 ok( hList != NULL, "failed to create listbox\n");
630 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
631 ok( id == 0, "item id wrong\n");
633 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
634 ok( r == 0, "send message failed\n");
636 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
637 ok( r == 20, "height wrong\n");
639 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
640 ok( r == -1, "send message failed\n");
642 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
643 ok( r == 20, "height wrong\n");
645 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
646 ok( r == -1, "send message failed\n");
648 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
649 ok( r == 20, "height wrong\n");
651 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
652 ok( r == 0, "send message failed\n");
654 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
655 ok( r == 0xff, "height wrong\n");
657 DestroyWindow( hList );
660 static void test_itemfrompoint(void)
662 /* WS_POPUP is required in order to have a more accurate size calculation (
663 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
664 behavior of partially-displayed item.
666 HWND hList = CreateWindowA( "ListBox", "list test",
667 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
668 1, 1, 600, 100, NULL, NULL, NULL, NULL );
669 ULONG r, id;
670 RECT rc;
672 /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
673 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
674 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
676 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
677 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
679 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
680 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
682 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
683 ok( id == 0, "item id wrong\n");
684 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
685 ok( id == 1, "item id wrong\n");
687 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
688 ok( r == 0x1, "ret %x\n", r );
690 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
691 ok( r == 0x10001 || broken(r == 1), /* nt4 */
692 "ret %x\n", r );
694 /* Resize control so that below assertions about sizes are valid */
695 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
696 ok( r == 1, "ret %x\n", r);
697 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
698 ok( r != 0, "ret %x\n", r);
700 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
701 ok( id == 2, "item id wrong\n");
702 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
703 ok( id == 3, "item id wrong\n");
704 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
705 ok( id == 4, "item id wrong\n");
706 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
707 ok( id == 5, "item id wrong\n");
708 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
709 ok( id == 6, "item id wrong\n");
710 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
711 ok( id == 7, "item id wrong\n");
713 /* Set the listbox up so that id 1 is at the top, this leaves 5
714 partially visible at the bottom and 6, 7 are invisible */
716 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
717 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
718 ok( r == 1, "top %d\n", r);
720 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
721 ok( r == 1, "ret %x\n", r);
722 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
723 ok( r == 0, "ret %x\n", r);
725 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
726 ok( r == 1, "ret %x\n", r);
728 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
729 ok( r == 0x10001 || broken(r == 1), /* nt4 */
730 "ret %x\n", r );
732 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
733 ok( r == 0x10001 || broken(r == 1), /* nt4 */
734 "ret %x\n", r );
736 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
737 ok( r == 0x10005 || broken(r == 5), /* nt4 */
738 "item %x\n", r );
740 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
741 ok( r == 0x10005 || broken(r == 5), /* nt4 */
742 "item %x\n", r );
744 DestroyWindow( hList );
747 static void test_listbox_item_data(void)
749 HWND hList;
750 int r, id;
752 hList = CreateWindowA( "ListBox", "list test", 0,
753 1, 1, 600, 100, NULL, NULL, NULL, NULL );
754 ok( hList != NULL, "failed to create listbox\n");
756 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
757 ok( id == 0, "item id wrong\n");
759 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
760 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
762 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
763 ok( r == 20, "get item data failed\n");
765 DestroyWindow( hList );
768 static void test_listbox_LB_DIR(void)
770 char path[MAX_PATH], curdir[MAX_PATH];
771 HWND hList;
772 int res, itemCount;
773 int itemCount_justFiles;
774 int itemCount_justDrives;
775 int itemCount_allFiles;
776 int itemCount_allDirs;
777 int i;
778 char pathBuffer[MAX_PATH];
779 char * p;
780 char driveletter;
781 const char *wildcard = "*";
782 HANDLE file;
783 BOOL ret;
785 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
787 GetTempPathA(ARRAY_SIZE(path), path);
788 ret = SetCurrentDirectoryA(path);
789 ok(ret, "Failed to set current directory.\n");
791 ret = CreateDirectoryA("lb_dir_test", NULL);
792 ok(ret, "Failed to create test directory.\n");
794 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
795 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
796 CloseHandle( file );
798 /* NOTE: for this test to succeed, there must be no subdirectories
799 under the current directory. In addition, there must be at least
800 one file that fits the wildcard w*.c . Normally, the test
801 directory itself satisfies both conditions.
803 hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
804 1, 1, 600, 100, NULL, NULL, NULL, NULL );
805 assert(hList);
807 /* Test for standard usage */
809 /* This should list all the files in the test directory. */
810 strcpy(pathBuffer, wildcard);
811 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
812 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
813 if (res == -1) /* "*" wildcard doesn't work on win9x */
815 wildcard = "*.*";
816 strcpy(pathBuffer, wildcard);
817 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
819 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
821 /* There should be some content in the listbox */
822 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
823 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
824 itemCount_allFiles = itemCount;
825 ok(res + 1 == itemCount,
826 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
827 itemCount - 1, res);
829 /* This tests behavior when no files match the wildcard */
830 strcpy(pathBuffer, BAD_EXTENSION);
831 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
832 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
833 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
835 /* There should be NO content in the listbox */
836 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
837 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
840 /* This should list all the w*.c files in the test directory
841 * As of this writing, this includes win.c, winstation.c, wsprintf.c
843 strcpy(pathBuffer, "w*.c");
844 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
845 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
846 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
848 /* Path specification does NOT converted to uppercase */
849 ok (!strcmp(pathBuffer, "w*.c"),
850 "expected no change to pathBuffer, got %s\n", pathBuffer);
852 /* There should be some content in the listbox */
853 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
854 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
855 itemCount_justFiles = itemCount;
856 ok(res + 1 == itemCount,
857 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
858 itemCount - 1, res);
860 /* Every single item in the control should start with a w and end in .c */
861 for (i = 0; i < itemCount; i++) {
862 memset(pathBuffer, 0, MAX_PATH);
863 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
864 p = pathBuffer + strlen(pathBuffer);
865 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
866 (*(p-1) == 'c' || *(p-1) == 'C') &&
867 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
870 /* Test DDL_DIRECTORY */
871 strcpy(pathBuffer, wildcard);
872 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
873 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
874 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
876 /* There should be some content in the listbox.
877 * All files plus "[..]"
879 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
880 itemCount_allDirs = itemCount - itemCount_allFiles;
881 ok (itemCount > itemCount_allFiles,
882 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
883 itemCount, itemCount_allFiles);
884 ok(res + 1 == itemCount,
885 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
886 itemCount - 1, res);
888 /* This tests behavior when no files match the wildcard */
889 strcpy(pathBuffer, BAD_EXTENSION);
890 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
891 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
892 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
894 /* There should be NO content in the listbox */
895 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
896 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
899 /* Test DDL_DIRECTORY */
900 strcpy(pathBuffer, "w*.c");
901 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
902 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
903 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
905 /* There should be some content in the listbox. Since the parent directory does not
906 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
908 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
909 ok (itemCount == itemCount_justFiles,
910 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
911 itemCount, itemCount_justFiles);
912 ok(res + 1 == itemCount,
913 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
914 itemCount - 1, res);
916 /* Every single item in the control should start with a w and end in .c. */
917 for (i = 0; i < itemCount; i++) {
918 memset(pathBuffer, 0, MAX_PATH);
919 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
920 p = pathBuffer + strlen(pathBuffer);
922 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
923 (*(p-1) == 'c' || *(p-1) == 'C') &&
924 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
928 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
929 strcpy(pathBuffer, wildcard);
930 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
931 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
932 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
934 /* There should be some content in the listbox. In particular, there should
935 * be at least one element before, since the string "[-c-]" should
936 * have been added. Depending on the user setting, more drives might have
937 * been added.
939 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
940 ok (itemCount >= 1,
941 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
942 itemCount, 1);
943 itemCount_justDrives = itemCount;
944 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
946 /* Every single item in the control should fit the format [-c-] */
947 for (i = 0; i < itemCount; i++) {
948 memset(pathBuffer, 0, MAX_PATH);
949 driveletter = '\0';
950 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
951 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
952 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
953 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
954 if (!(driveletter >= 'a' && driveletter <= 'z')) {
955 /* Correct after invalid entry is found */
956 trace("removing count of invalid entry %s\n", pathBuffer);
957 itemCount_justDrives--;
961 /* This tests behavior when no files match the wildcard */
962 strcpy(pathBuffer, BAD_EXTENSION);
963 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
964 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
965 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
966 BAD_EXTENSION, res, itemCount_justDrives -1);
968 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
969 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
970 itemCount, itemCount_justDrives);
972 trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
973 itemCount_justFiles, itemCount_justDrives);
975 /* Test DDL_DRIVES. */
976 strcpy(pathBuffer, wildcard);
977 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
978 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
979 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
981 /* There should be some content in the listbox. In particular, there should
982 * be at least one element before, since the string "[-c-]" should
983 * have been added. Depending on the user setting, more drives might have
984 * been added.
986 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
987 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
988 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
989 itemCount, itemCount_justDrives + itemCount_allFiles);
990 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
992 /* This tests behavior when no files match the wildcard */
993 strcpy(pathBuffer, BAD_EXTENSION);
994 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
995 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
996 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
997 BAD_EXTENSION, res, itemCount_justDrives -1);
999 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1000 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1003 /* Test DDL_DRIVES. */
1004 strcpy(pathBuffer, "w*.c");
1005 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1006 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1007 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1009 /* There should be some content in the listbox. In particular, there should
1010 * be at least one element before, since the string "[-c-]" should
1011 * have been added. Depending on the user setting, more drives might have
1012 * been added.
1014 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1015 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1016 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1017 itemCount, itemCount_justDrives + itemCount_justFiles);
1018 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1020 /* Every single item in the control should fit the format [-c-], or w*.c */
1021 for (i = 0; i < itemCount; i++) {
1022 memset(pathBuffer, 0, MAX_PATH);
1023 driveletter = '\0';
1024 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1025 p = pathBuffer + strlen(pathBuffer);
1026 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1027 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1028 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1029 } else {
1031 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1032 (*(p-1) == 'c' || *(p-1) == 'C') &&
1033 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1038 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1039 strcpy(pathBuffer, wildcard);
1040 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1041 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1042 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1044 /* There should be some content in the listbox. In particular, there should
1045 * be exactly the number of plain files, plus the number of mapped drives.
1047 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1048 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1049 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1050 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1051 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1053 /* Every single item in the control should start with a w and end in .c,
1054 * except for the "[..]" string, which should appear exactly as it is,
1055 * and the mapped drives in the format "[-X-]".
1057 for (i = 0; i < itemCount; i++) {
1058 memset(pathBuffer, 0, MAX_PATH);
1059 driveletter = '\0';
1060 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1061 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1062 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1066 /* This tests behavior when no files match the wildcard */
1067 strcpy(pathBuffer, BAD_EXTENSION);
1068 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1069 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1070 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1071 BAD_EXTENSION, res, itemCount_justDrives -1);
1073 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1074 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1078 /* Test DDL_DIRECTORY|DDL_DRIVES. */
1079 strcpy(pathBuffer, "w*.c");
1080 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1081 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1082 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1084 /* There should be some content in the listbox. In particular, there should
1085 * be exactly the number of plain files, plus the number of mapped drives.
1087 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1088 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1089 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1090 itemCount, itemCount_justFiles + itemCount_justDrives);
1091 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1093 /* Every single item in the control should start with a w and end in .c,
1094 * except the mapped drives in the format "[-X-]". The "[..]" directory
1095 * should not appear.
1097 for (i = 0; i < itemCount; i++) {
1098 memset(pathBuffer, 0, MAX_PATH);
1099 driveletter = '\0';
1100 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1101 p = pathBuffer + strlen(pathBuffer);
1102 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1103 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1104 } else {
1106 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1107 (*(p-1) == 'c' || *(p-1) == 'C') &&
1108 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1112 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1113 strcpy(pathBuffer, wildcard);
1114 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1115 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1116 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
1118 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1119 ok (itemCount == itemCount_allDirs,
1120 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1121 itemCount, itemCount_allDirs);
1122 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1124 if (itemCount)
1126 memset(pathBuffer, 0, MAX_PATH);
1127 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1128 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1131 /* This tests behavior when no files match the wildcard */
1132 strcpy(pathBuffer, BAD_EXTENSION);
1133 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1134 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1135 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1136 BAD_EXTENSION, res, -1);
1138 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1139 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1142 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1143 strcpy(pathBuffer, "w*.c");
1144 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1145 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1146 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1148 /* There should be no elements, since "[..]" does not fit w*.c */
1149 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1150 ok (itemCount == 0,
1151 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1152 itemCount, 0);
1154 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1155 strcpy(pathBuffer, wildcard);
1156 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1157 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1158 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1160 /* There should be no plain files on the listbox */
1161 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1162 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1163 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1164 itemCount, itemCount_justDrives + itemCount_allDirs);
1165 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1167 for (i = 0; i < itemCount; i++) {
1168 memset(pathBuffer, 0, MAX_PATH);
1169 driveletter = '\0';
1170 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1171 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1172 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1173 } else {
1174 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1175 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1179 /* This tests behavior when no files match the wildcard */
1180 strcpy(pathBuffer, BAD_EXTENSION);
1181 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1182 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1183 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1184 BAD_EXTENSION, res, itemCount_justDrives -1);
1186 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1187 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1189 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1190 strcpy(pathBuffer, "w*.c");
1191 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1192 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1193 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1195 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1196 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1197 ok (itemCount == itemCount_justDrives,
1198 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1199 itemCount, itemCount_justDrives);
1200 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1202 for (i = 0; i < itemCount; i++) {
1203 memset(pathBuffer, 0, MAX_PATH);
1204 driveletter = '\0';
1205 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1206 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1207 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1209 DestroyWindow(hList);
1211 DeleteFileA( "wtest1.tmp.c" );
1212 RemoveDirectoryA("lb_dir_test");
1214 SetCurrentDirectoryA(curdir);
1217 static HWND g_listBox;
1218 static HWND g_label;
1220 #define ID_TEST_LABEL 1001
1221 #define ID_TEST_LISTBOX 1002
1223 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCTA lpcs)
1225 g_label = CreateWindowA(
1226 "Static",
1227 "Contents of static control before DlgDirList.",
1228 WS_CHILD | WS_VISIBLE,
1229 10, 10, 512, 32,
1230 hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1231 if (!g_label) return FALSE;
1232 g_listBox = CreateWindowA(
1233 "ListBox",
1234 "DlgDirList test",
1235 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1236 10, 60, 256, 256,
1237 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1238 if (!g_listBox) return FALSE;
1240 return TRUE;
1243 static LRESULT CALLBACK listbox_container_window_procA (
1244 HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1246 LRESULT result = 0;
1248 switch (uiMsg) {
1249 case WM_DESTROY:
1250 PostQuitMessage(0);
1251 break;
1252 case WM_CREATE:
1253 result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1254 ? 0 : (LRESULT)-1;
1255 break;
1256 default:
1257 result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1258 break;
1260 return result;
1263 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1265 WNDCLASSA cls;
1267 cls.style = 0;
1268 cls.cbClsExtra = 0;
1269 cls.cbWndExtra = 0;
1270 cls.hInstance = hInst;
1271 cls.hIcon = NULL;
1272 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1273 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1274 cls.lpszMenuName = NULL;
1275 cls.lpfnWndProc = listbox_container_window_procA;
1276 cls.lpszClassName = "ListboxContainerClass";
1277 if (!RegisterClassA (&cls)) return FALSE;
1279 return TRUE;
1282 static void test_listbox_dlgdir(void)
1284 HINSTANCE hInst;
1285 HWND hWnd;
1286 int res, itemCount;
1287 int itemCount_allDirs;
1288 int itemCount_justFiles;
1289 int itemCount_justDrives;
1290 int i;
1291 char pathBuffer[MAX_PATH];
1292 char itemBuffer[MAX_PATH];
1293 char tempBuffer[MAX_PATH];
1294 char * p;
1295 char driveletter;
1296 HANDLE file;
1298 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1299 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1300 CloseHandle( file );
1302 /* NOTE: for this test to succeed, there must be no subdirectories
1303 under the current directory. In addition, there must be at least
1304 one file that fits the wildcard w*.c . Normally, the test
1305 directory itself satisfies both conditions.
1308 hInst = GetModuleHandleA(0);
1309 if (!RegisterListboxWindowClass(hInst)) assert(0);
1310 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1311 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1312 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1313 NULL, NULL, hInst, 0);
1314 assert(hWnd);
1316 /* Test for standard usage */
1318 /* The following should be overwritten by the directory path */
1319 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1321 /* This should list all the w*.c files in the test directory
1322 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1324 strcpy(pathBuffer, "w*.c");
1325 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1326 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1328 /* Path specification gets converted to uppercase */
1329 ok (!strcmp(pathBuffer, "W*.C"),
1330 "expected conversion to uppercase, got %s\n", pathBuffer);
1332 /* Loaded path should have overwritten the label text */
1333 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1334 trace("Static control after DlgDirList: %s\n", pathBuffer);
1335 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1337 /* There should be some content in the listbox */
1338 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1339 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1340 itemCount_justFiles = itemCount;
1342 /* Every single item in the control should start with a w and end in .c */
1343 for (i = 0; i < itemCount; i++) {
1344 memset(pathBuffer, 0, MAX_PATH);
1345 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1346 p = pathBuffer + strlen(pathBuffer);
1347 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1348 (*(p-1) == 'c' || *(p-1) == 'C') &&
1349 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1352 /* Test behavior when no files match the wildcard */
1353 strcpy(pathBuffer, BAD_EXTENSION);
1354 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1355 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1357 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1358 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1360 /* Test DDL_DIRECTORY */
1361 strcpy(pathBuffer, "w*.c");
1362 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1363 DDL_DIRECTORY);
1364 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1366 /* There should be some content in the listbox. In particular, there should
1367 * be exactly more elements than before, since the directories should
1368 * have been added.
1370 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1371 itemCount_allDirs = itemCount - itemCount_justFiles;
1372 ok (itemCount >= itemCount_justFiles,
1373 "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1374 itemCount, itemCount_justFiles);
1376 /* Every single item in the control should start with a w and end in .c,
1377 * except for the "[..]" string, which should appear exactly as it is.
1379 for (i = 0; i < itemCount; i++) {
1380 memset(pathBuffer, 0, MAX_PATH);
1381 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1382 p = pathBuffer + strlen(pathBuffer);
1383 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1384 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1385 (*(p-1) == 'c' || *(p-1) == 'C') &&
1386 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1389 /* Test behavior when no files match the wildcard */
1390 strcpy(pathBuffer, BAD_EXTENSION);
1391 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1392 DDL_DIRECTORY);
1393 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1395 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1396 ok (itemCount == itemCount_allDirs,
1397 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1398 itemCount_allDirs, itemCount);
1399 for (i = 0; i < itemCount; i++) {
1400 memset(pathBuffer, 0, MAX_PATH);
1401 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1402 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1403 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1407 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1408 strcpy(pathBuffer, "w*.c");
1409 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1410 DDL_DRIVES);
1411 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1413 /* There should be some content in the listbox. In particular, there should
1414 * be at least one element before, since the string "[-c-]" should
1415 * have been added. Depending on the user setting, more drives might have
1416 * been added.
1418 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1419 ok (itemCount >= 1,
1420 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1421 itemCount, 1);
1422 itemCount_justDrives = itemCount;
1424 /* Every single item in the control should fit the format [-c-] */
1425 for (i = 0; i < itemCount; i++) {
1426 memset(pathBuffer, 0, MAX_PATH);
1427 driveletter = '\0';
1428 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1429 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1430 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1431 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1432 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1433 /* Correct after invalid entry is found */
1434 trace("removing count of invalid entry %s\n", pathBuffer);
1435 itemCount_justDrives--;
1439 /* Test behavior when no files match the wildcard */
1440 strcpy(pathBuffer, BAD_EXTENSION);
1441 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1442 DDL_DRIVES);
1443 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1445 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1446 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1449 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1450 strcpy(pathBuffer, "w*.c");
1451 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1452 DDL_DIRECTORY|DDL_DRIVES);
1453 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1455 /* There should be some content in the listbox. In particular, there should
1456 * be exactly the number of plain files, plus the number of mapped drives,
1457 * plus one "[..]"
1459 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1460 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1461 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1462 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1464 /* Every single item in the control should start with a w and end in .c,
1465 * except for the "[..]" string, which should appear exactly as it is,
1466 * and the mapped drives in the format "[-X-]".
1468 for (i = 0; i < itemCount; i++) {
1469 memset(pathBuffer, 0, MAX_PATH);
1470 driveletter = '\0';
1471 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1472 p = pathBuffer + strlen(pathBuffer);
1473 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1474 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1475 } else {
1476 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1477 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1478 (*(p-1) == 'c' || *(p-1) == 'C') &&
1479 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1483 /* Test behavior when no files match the wildcard */
1484 strcpy(pathBuffer, BAD_EXTENSION);
1485 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1486 DDL_DIRECTORY|DDL_DRIVES);
1487 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1489 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1490 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1491 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1492 itemCount_justDrives + itemCount_allDirs, itemCount);
1496 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1497 strcpy(pathBuffer, "w*.c");
1498 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1499 DDL_DIRECTORY|DDL_EXCLUSIVE);
1500 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1502 /* There should be exactly one element: "[..]" */
1503 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1504 ok (itemCount == itemCount_allDirs,
1505 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1506 itemCount, itemCount_allDirs);
1508 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1510 memset(pathBuffer, 0, MAX_PATH);
1511 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1512 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1515 /* Test behavior when no files match the wildcard */
1516 strcpy(pathBuffer, BAD_EXTENSION);
1517 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1518 DDL_DIRECTORY|DDL_EXCLUSIVE);
1519 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1521 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1522 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1525 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1526 strcpy(pathBuffer, "w*.c");
1527 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1528 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1529 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1531 /* There should be no plain files on the listbox */
1532 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1533 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1534 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1535 itemCount, itemCount_justDrives + itemCount_allDirs);
1537 for (i = 0; i < itemCount; i++) {
1538 memset(pathBuffer, 0, MAX_PATH);
1539 driveletter = '\0';
1540 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1541 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1542 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1543 } else {
1544 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1545 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1549 /* Test behavior when no files match the wildcard */
1550 strcpy(pathBuffer, BAD_EXTENSION);
1551 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1552 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1553 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1555 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1556 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1557 "DlgDirList() incorrectly filled the listbox!\n");
1559 /* Now test DlgDirSelectEx() in normal operation */
1560 /* Fill with everything - drives, directory and all plain files. */
1561 strcpy(pathBuffer, "*");
1562 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1563 DDL_DIRECTORY|DDL_DRIVES);
1564 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1566 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1567 memset(pathBuffer, 0, MAX_PATH);
1568 SetLastError(0xdeadbeef);
1569 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1570 ok (GetLastError() == 0xdeadbeef,
1571 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1572 GetLastError());
1573 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1574 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1576 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1578 /* Test proper drive/dir/file recognition */
1579 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1580 for (i = 0; i < itemCount; i++) {
1581 memset(itemBuffer, 0, MAX_PATH);
1582 memset(pathBuffer, 0, MAX_PATH);
1583 memset(tempBuffer, 0, MAX_PATH);
1584 driveletter = '\0';
1585 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1586 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1587 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1588 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1589 /* Current item is a drive letter */
1590 SetLastError(0xdeadbeef);
1591 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1592 ok (GetLastError() == 0xdeadbeef,
1593 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1594 i, GetLastError());
1595 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1597 /* For drive letters, DlgDirSelectEx tacks on a colon */
1598 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1599 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1600 } else if (itemBuffer[0] == '[') {
1601 /* Current item is the parent directory */
1602 SetLastError(0xdeadbeef);
1603 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1604 ok (GetLastError() == 0xdeadbeef,
1605 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1606 i, GetLastError());
1607 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1609 /* For directories, DlgDirSelectEx tacks on a backslash */
1610 p = pathBuffer + strlen(pathBuffer);
1611 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1613 tempBuffer[0] = '[';
1614 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1615 strcat(tempBuffer, "]");
1616 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1617 } else {
1618 /* Current item is a plain file */
1619 SetLastError(0xdeadbeef);
1620 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1621 ok (GetLastError() == 0xdeadbeef,
1622 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1623 i, GetLastError());
1624 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1626 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1627 * for example, "Makefile", which gets reported as "Makefile."
1629 strcpy(tempBuffer, itemBuffer);
1630 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1631 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1635 DeleteFileA( "wtest1.tmp.c" );
1637 /* Now test DlgDirSelectEx() in abnormal operation */
1638 /* Fill list with bogus entries, that look somewhat valid */
1639 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1640 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1641 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1642 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1643 for (i = 0; i < itemCount; i++) {
1644 memset(itemBuffer, 0, MAX_PATH);
1645 memset(pathBuffer, 0, MAX_PATH);
1646 memset(tempBuffer, 0, MAX_PATH);
1647 driveletter = '\0';
1648 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1649 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1650 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1651 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1652 /* Current item is a drive letter */
1653 SetLastError(0xdeadbeef);
1654 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1655 ok (GetLastError() == 0xdeadbeef,
1656 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1657 i, GetLastError());
1658 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1660 /* For drive letters, DlgDirSelectEx tacks on a colon */
1661 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1662 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1663 } else if (itemBuffer[0] == '[') {
1664 /* Current item is the parent directory */
1665 SetLastError(0xdeadbeef);
1666 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1667 ok (GetLastError() == 0xdeadbeef,
1668 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1669 i, GetLastError());
1670 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1672 /* For directories, DlgDirSelectEx tacks on a backslash */
1673 p = pathBuffer + strlen(pathBuffer);
1674 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1676 tempBuffer[0] = '[';
1677 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1678 strcat(tempBuffer, "]");
1679 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1680 } else {
1681 /* Current item is a plain file */
1682 SetLastError(0xdeadbeef);
1683 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1684 ok (GetLastError() == 0xdeadbeef,
1685 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1686 i, GetLastError());
1687 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1689 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1690 * This affects for example, "Makefile", which gets reported as "Makefile."
1692 strcpy(tempBuffer, itemBuffer);
1693 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1694 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1698 /* Test behavior when loading folders from root with and without wildcard */
1699 strcpy(pathBuffer, "C:\\");
1700 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1701 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1702 todo_wine ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1703 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1705 strcpy(pathBuffer, "C:\\*");
1706 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1707 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\* folders\n");
1708 ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1709 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1711 /* Try loading files from an invalid folder */
1712 SetLastError(0xdeadbeef);
1713 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1714 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1715 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1716 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1717 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1719 DestroyWindow(hWnd);
1722 static void test_set_count( void )
1724 static const DWORD styles[] =
1726 LBS_OWNERDRAWFIXED,
1727 LBS_HASSTRINGS,
1729 HWND parent, listbox;
1730 unsigned int i;
1731 LONG ret;
1732 RECT r;
1734 parent = create_parent();
1735 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1737 UpdateWindow( listbox );
1738 GetUpdateRect( listbox, &r, TRUE );
1739 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1741 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1742 ok( ret == 0, "got %d\n", ret );
1743 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1744 ok( ret == 100, "got %d\n", ret );
1746 GetUpdateRect( listbox, &r, TRUE );
1747 ok( !IsRectEmpty( &r ), "got empty rect\n");
1749 ValidateRect( listbox, NULL );
1750 GetUpdateRect( listbox, &r, TRUE );
1751 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1753 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1754 ok( ret == 0, "got %d\n", ret );
1756 GetUpdateRect( listbox, &r, TRUE );
1757 ok( !IsRectEmpty( &r ), "got empty rect\n");
1759 DestroyWindow( listbox );
1761 for (i = 0; i < ARRAY_SIZE(styles); ++i)
1763 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
1765 SetLastError( 0xdeadbeef );
1766 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1767 ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
1768 ok( GetLastError() == ERROR_SETCOUNT_ON_BAD_LB, "Unexpected error %d.\n", GetLastError() );
1770 DestroyWindow( listbox );
1773 DestroyWindow( parent );
1776 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1777 static int lb_getlistboxinfo;
1779 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1781 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1783 if (message == LB_GETLISTBOXINFO)
1784 lb_getlistboxinfo++;
1786 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1789 static void test_GetListBoxInfo(void)
1791 HWND listbox, parent;
1792 WNDPROC oldproc;
1793 DWORD ret;
1795 pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetListBoxInfo");
1797 if (!pGetListBoxInfo)
1799 win_skip("GetListBoxInfo() not available\n");
1800 return;
1803 parent = create_parent();
1804 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1806 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1807 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1809 lb_getlistboxinfo = 0;
1810 ret = pGetListBoxInfo(listbox);
1811 ok(ret > 0, "got %d\n", ret);
1812 todo_wine
1813 ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
1815 DestroyWindow(listbox);
1816 DestroyWindow(parent);
1819 static void test_missing_lbuttonup( void )
1821 HWND listbox, parent, capture;
1823 parent = create_parent();
1824 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1826 /* Send button down without a corresponding button up */
1827 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10,10));
1828 capture = GetCapture();
1829 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1831 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1832 got_selchange = 0;
1833 SetFocus(NULL);
1834 capture = GetCapture();
1835 ok(capture == NULL, "got %p\n", capture);
1836 ok(got_selchange, "got %d\n", got_selchange);
1838 DestroyWindow(listbox);
1839 DestroyWindow(parent);
1842 static void test_extents(void)
1844 HWND listbox, parent;
1845 DWORD res;
1846 SCROLLINFO sinfo;
1847 BOOL br;
1849 parent = create_parent();
1851 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1853 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1854 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1856 sinfo.cbSize = sizeof(sinfo);
1857 sinfo.fMask = SIF_RANGE;
1858 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1859 ok(br == TRUE, "GetScrollInfo failed\n");
1860 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1861 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1862 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1863 "List box should not have a horizontal scroll bar\n");
1865 /* horizontal extent < width */
1866 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1868 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1869 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1871 sinfo.cbSize = sizeof(sinfo);
1872 sinfo.fMask = SIF_RANGE;
1873 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1874 ok(br == TRUE, "GetScrollInfo failed\n");
1875 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1876 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1877 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1878 "List box should not have a horizontal scroll bar\n");
1880 /* horizontal extent > width */
1881 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1883 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1884 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1886 sinfo.cbSize = sizeof(sinfo);
1887 sinfo.fMask = SIF_RANGE;
1888 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1889 ok(br == TRUE, "GetScrollInfo failed\n");
1890 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1891 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1892 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1893 "List box should not have a horizontal scroll bar\n");
1895 DestroyWindow(listbox);
1898 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1900 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1901 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1903 sinfo.cbSize = sizeof(sinfo);
1904 sinfo.fMask = SIF_RANGE;
1905 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1906 ok(br == TRUE, "GetScrollInfo failed\n");
1907 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1908 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1909 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1910 "List box should not have a horizontal scroll bar\n");
1912 /* horizontal extent < width */
1913 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1915 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1916 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1918 sinfo.cbSize = sizeof(sinfo);
1919 sinfo.fMask = SIF_RANGE;
1920 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1921 ok(br == TRUE, "GetScrollInfo failed\n");
1922 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1923 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1924 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1925 "List box should not have a horizontal scroll bar\n");
1927 /* horizontal extent > width */
1928 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1930 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1931 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1933 sinfo.cbSize = sizeof(sinfo);
1934 sinfo.fMask = SIF_RANGE;
1935 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1936 ok(br == TRUE, "GetScrollInfo failed\n");
1937 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1938 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1939 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1940 "List box should have a horizontal scroll bar\n");
1942 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1944 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1945 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1947 sinfo.cbSize = sizeof(sinfo);
1948 sinfo.fMask = SIF_RANGE;
1949 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1950 ok(br == TRUE, "GetScrollInfo failed\n");
1951 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1952 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1953 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1954 "List box should not have a horizontal scroll bar\n");
1956 DestroyWindow(listbox);
1959 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
1961 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1962 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1964 sinfo.cbSize = sizeof(sinfo);
1965 sinfo.fMask = SIF_RANGE;
1966 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1967 ok(br == TRUE, "GetScrollInfo failed\n");
1968 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1969 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1970 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1971 "List box should have a horizontal scroll bar\n");
1973 /* horizontal extent < width */
1974 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1976 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1977 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1979 sinfo.cbSize = sizeof(sinfo);
1980 sinfo.fMask = SIF_RANGE;
1981 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1982 ok(br == TRUE, "GetScrollInfo failed\n");
1983 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1984 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1985 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1986 "List box should have a horizontal scroll bar\n");
1988 /* horizontal extent > width */
1989 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1991 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1992 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1994 sinfo.cbSize = sizeof(sinfo);
1995 sinfo.fMask = SIF_RANGE;
1996 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1997 ok(br == TRUE, "GetScrollInfo failed\n");
1998 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1999 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2000 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2001 "List box should have a horizontal scroll bar\n");
2003 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2005 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2006 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2008 sinfo.cbSize = sizeof(sinfo);
2009 sinfo.fMask = SIF_RANGE;
2010 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2011 ok(br == TRUE, "GetScrollInfo failed\n");
2012 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2013 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2014 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2015 "List box should have a horizontal scroll bar\n");
2017 DestroyWindow(listbox);
2019 DestroyWindow(parent);
2022 static void test_WM_MEASUREITEM(void)
2024 HWND parent, listbox;
2025 LRESULT data;
2027 parent = create_parent();
2028 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2030 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2031 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
2032 DestroyWindow(parent);
2034 parent = create_parent();
2035 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2037 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2038 ok(!data, "data = %08lx\n", data);
2039 DestroyWindow(parent);
2042 static void test_LBS_NODATA(void)
2044 static const DWORD invalid_styles[] =
2047 LBS_OWNERDRAWVARIABLE,
2048 LBS_SORT,
2049 LBS_HASSTRINGS,
2050 LBS_OWNERDRAWFIXED | LBS_SORT,
2051 LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
2053 static const UINT invalid_idx[] = { -2, 2 };
2054 static const UINT valid_idx[] = { 0, 1 };
2055 static const ULONG_PTR zero_data;
2056 HWND listbox, parent;
2057 unsigned int i;
2058 ULONG_PTR data;
2059 INT ret;
2061 listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
2062 0, 0, 100, 100, NULL, NULL, NULL, 0);
2063 ok(listbox != NULL, "Failed to create ListBox window.\n");
2065 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2066 ok(ret == 0, "Unexpected return value %d.\n", ret);
2067 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2068 ok(ret == 1, "Unexpected return value %d.\n", ret);
2069 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
2070 ok(ret == 2, "Unexpected return value %d.\n", ret);
2072 /* Invalid indices. */
2073 for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
2075 ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
2076 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2077 ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
2078 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2079 if (ret == LB_ERR)
2081 ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
2082 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2084 ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
2085 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2088 /* Valid indices. */
2089 for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
2091 ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
2092 ok(ret == TRUE, "Unexpected return value %d.\n", ret);
2093 ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
2094 todo_wine_if(sizeof(void *) == 8)
2095 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2097 memset(&data, 0xee, sizeof(data));
2098 ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
2099 todo_wine_if(sizeof(void *) == 8)
2100 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2101 todo_wine
2102 ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
2104 ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
2105 todo_wine
2106 ok(ret == 0, "Unexpected return value %d.\n", ret);
2109 /* More messages that don't work with LBS_NODATA. */
2110 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
2111 todo_wine
2112 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2113 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
2114 todo_wine
2115 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2116 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
2117 todo_wine
2118 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2120 DestroyWindow(listbox);
2122 /* Invalid window style combinations. */
2123 parent = create_parent();
2124 ok(parent != NULL, "Failed to create parent window.\n");
2126 for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
2128 DWORD style;
2130 listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
2131 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
2132 ok(listbox != NULL, "Failed to create a listbox.\n");
2134 style = GetWindowLongA(listbox, GWL_STYLE);
2135 ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style);
2136 ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
2137 ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
2138 DestroyWindow(listbox);
2141 DestroyWindow(parent);
2144 START_TEST(listbox)
2146 const struct listbox_test SS =
2147 /* {add_style} */
2148 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2149 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2150 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2151 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2152 /* {selected, anchor, caret, selcount}{TODO fields} */
2153 const struct listbox_test SS_NS =
2154 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2155 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2156 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2157 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2158 const struct listbox_test MS =
2159 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2160 { 1, 1, 1, 1}, {0,0,0,0},
2161 { 2, 1, 2, 1}, {0,0,0,0},
2162 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2163 const struct listbox_test MS_NS =
2164 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2165 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2166 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2167 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2168 const struct listbox_test ES =
2169 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2170 { 1, 1, 1, 1}, {0,0,0,0},
2171 { 2, 2, 2, 1}, {0,0,0,0},
2172 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2173 const struct listbox_test ES_NS =
2174 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2175 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2176 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2177 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2178 const struct listbox_test EMS =
2179 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2180 { 1, 1, 1, 1}, {0,0,0,0},
2181 { 2, 2, 2, 1}, {0,0,0,0},
2182 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2183 const struct listbox_test EMS_NS =
2184 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2185 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2186 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2187 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2189 trace (" Testing single selection...\n");
2190 check (0, SS);
2191 trace (" ... with NOSEL\n");
2192 check (LBS_NOSEL, SS_NS);
2193 trace (" ... LBS_NODATA variant ...\n");
2194 check (LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
2195 trace (" ... with NOSEL\n");
2196 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
2198 trace (" Testing multiple selection...\n");
2199 check (LBS_MULTIPLESEL, MS);
2200 trace (" ... with NOSEL\n");
2201 check (LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2202 trace (" ... LBS_NODATA variant ...\n");
2203 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
2204 trace (" ... with NOSEL\n");
2205 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2207 trace (" Testing extended selection...\n");
2208 check (LBS_EXTENDEDSEL, ES);
2209 trace (" ... with NOSEL\n");
2210 check (LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2211 trace (" ... LBS_NODATA variant ...\n");
2212 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
2213 trace (" ... with NOSEL\n");
2214 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2216 trace (" Testing extended and multiple selection...\n");
2217 check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2218 trace (" ... with NOSEL\n");
2219 check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2220 trace (" ... LBS_NODATA variant ...\n");
2221 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2222 trace (" ... with NOSEL\n");
2223 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2225 check_item_height();
2226 test_ownerdraw();
2227 test_LB_SELITEMRANGE();
2228 test_LB_SETCURSEL();
2229 test_listbox_height();
2230 test_itemfrompoint();
2231 test_listbox_item_data();
2232 test_listbox_LB_DIR();
2233 test_listbox_dlgdir();
2234 test_set_count();
2235 test_GetListBoxInfo();
2236 test_missing_lbuttonup();
2237 test_extents();
2238 test_WM_MEASUREITEM();
2239 test_LB_SETSEL();
2240 test_LBS_NODATA();