user32/listbox: Fix redraw after LB_SETCOUNT message.
[wine.git] / dlls / user32 / tests / listbox.c
blob7817d623134995cb99a36a2759b1a976246b05d9
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 unsigned int got_selchange, got_drawitem;
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 got_drawitem++;
297 break;
300 case WM_COMMAND:
301 if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
302 break;
304 default:
305 break;
308 return DefWindowProcA(hwnd, msg, wparam, lparam);
311 static HWND create_parent( void )
313 WNDCLASSA cls;
314 HWND parent;
315 static ATOM class;
317 if (!class)
319 cls.style = 0;
320 cls.lpfnWndProc = main_window_proc;
321 cls.cbClsExtra = 0;
322 cls.cbWndExtra = 0;
323 cls.hInstance = GetModuleHandleA(NULL);
324 cls.hIcon = 0;
325 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
326 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
327 cls.lpszMenuName = NULL;
328 cls.lpszClassName = "main_window_class";
329 class = RegisterClassA( &cls );
332 parent = CreateWindowExA(0, "main_window_class", NULL,
333 WS_POPUP | WS_VISIBLE,
334 100, 100, 400, 400,
335 GetDesktopWindow(), 0,
336 GetModuleHandleA(NULL), NULL);
337 return parent;
340 static void test_ownerdraw(void)
342 static const DWORD styles[] =
345 LBS_NODATA
347 static const struct {
348 UINT message;
349 WPARAM wparam;
350 LPARAM lparam;
351 UINT drawitem;
352 } testcase[] = {
353 { WM_NULL, 0, 0, 0 },
354 { WM_PAINT, 0, 0, 0 },
355 { LB_GETCOUNT, 0, 0, 0 },
356 { LB_SETCOUNT, ARRAY_SIZE(strings), 0, ARRAY_SIZE(strings) },
357 { LB_ADDSTRING, 0, (LPARAM)"foo", ARRAY_SIZE(strings)+1 },
358 { LB_DELETESTRING, 0, 0, ARRAY_SIZE(strings)-1 },
360 HWND parent, hLB;
361 INT ret;
362 RECT rc;
363 UINT i;
365 parent = create_parent();
366 assert(parent);
368 for (i = 0; i < ARRAY_SIZE(styles); i++)
370 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent);
371 assert(hLB);
373 SetForegroundWindow(hLB);
374 UpdateWindow(hLB);
376 /* make height short enough */
377 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
378 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
379 SWP_NOZORDER | SWP_NOMOVE);
381 /* make 0 item invisible */
382 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
383 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
384 ok(ret == 1, "wrong top index %d\n", ret);
386 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
387 trace("item 0 rect %s\n", wine_dbgstr_rect(&rc));
388 ok(!IsRectEmpty(&rc), "empty item rect\n");
389 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
391 DestroyWindow(hLB);
393 /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
394 hLB = CreateWindowA("listbox", "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i],
395 0, 0, 100, 100, NULL, NULL, NULL, 0);
396 ok(hLB != NULL, "last error 0x%08x\n", GetLastError());
398 ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n");
400 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
401 ok(ret == 0, "Unexpected return value %d.\n", ret);
402 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
403 ok(ret == 1, "Unexpected return value %d.\n", ret);
405 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
406 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
408 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
409 ok(ret == 13, "Unexpected item height %d.\n", ret);
411 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
412 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
414 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
415 ok(ret == 42, "Unexpected item height %d.\n", ret);
417 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
418 ok(ret == 42, "Unexpected item height %d.\n", ret);
420 DestroyWindow (hLB);
423 /* test pending redraw state */
424 for (i = 0; i < ARRAY_SIZE(testcase); i++)
426 winetest_push_context("%d", i);
427 hLB = create_listbox(LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent);
428 assert(hLB);
430 ret = SendMessageA(hLB, WM_SETREDRAW, FALSE, 0);
431 ok(!ret, "got %d\n", ret);
432 ret = SendMessageA(hLB, testcase[i].message, testcase[i].wparam, testcase[i].lparam);
433 if (testcase[i].message >= LB_ADDSTRING && testcase[i].message < LB_MSGMAX &&
434 testcase[i].message != LB_SETCOUNT)
435 ok(ret > 0, "expected > 0, got %d\n", ret);
436 else
437 ok(!ret, "expected 0, got %d\n", ret);
439 got_drawitem = 0;
440 ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW);
441 ok(ret, "RedrawWindow failed\n");
442 ok(!got_drawitem, "got %u\n", got_drawitem);
444 ret = SendMessageA(hLB, WM_SETREDRAW, TRUE, 0);
445 ok(!ret, "got %d\n", ret);
447 got_drawitem = 0;
448 ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW);
449 ok(ret, "RedrawWindow failed\n");
450 ok(got_drawitem == testcase[i].drawitem, "expected %u, got %u\n", testcase[i].drawitem, got_drawitem);
452 DestroyWindow(hLB);
453 winetest_pop_context();
456 DestroyWindow(parent);
459 #define listbox_test_query(exp, got) \
460 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
461 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
462 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
463 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
465 static void test_LB_SELITEMRANGE(void)
467 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
468 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
469 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
470 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
471 HWND hLB;
472 struct listbox_stat answer;
473 INT ret;
475 trace("testing LB_SELITEMRANGE\n");
477 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
478 assert(hLB);
480 listbox_query(hLB, &answer);
481 listbox_test_query(test_nosel, answer);
483 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
484 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
485 listbox_query(hLB, &answer);
486 listbox_test_query(test_1, answer);
488 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
489 listbox_query(hLB, &answer);
490 listbox_test_query(test_nosel, answer);
492 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
493 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
494 listbox_query(hLB, &answer);
495 listbox_test_query(test_3, answer);
497 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
498 listbox_query(hLB, &answer);
499 listbox_test_query(test_nosel, answer);
501 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
502 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
503 listbox_query(hLB, &answer);
504 listbox_test_query(test_nosel, answer);
506 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
507 listbox_query(hLB, &answer);
508 listbox_test_query(test_nosel, answer);
510 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
511 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
512 listbox_query(hLB, &answer);
513 listbox_test_query(test_1, answer);
515 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
516 listbox_query(hLB, &answer);
517 listbox_test_query(test_nosel, answer);
519 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
520 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
521 listbox_query(hLB, &answer);
522 listbox_test_query(test_nosel, answer);
524 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
525 listbox_query(hLB, &answer);
526 listbox_test_query(test_nosel, answer);
528 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
529 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
530 listbox_query(hLB, &answer);
531 listbox_test_query(test_2, answer);
533 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
534 listbox_query(hLB, &answer);
535 listbox_test_query(test_nosel, answer);
537 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
538 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
539 listbox_query(hLB, &answer);
540 listbox_test_query(test_2, answer);
542 DestroyWindow(hLB);
545 static void test_LB_SETCURSEL(void)
547 HWND parent, hLB;
548 INT ret;
550 trace("testing LB_SETCURSEL\n");
552 parent = create_parent();
553 assert(parent);
555 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
556 assert(hLB);
558 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
560 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
561 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
563 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
564 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
565 ret = GetScrollPos(hLB, SB_VERT);
566 ok(ret == 0, "expected vscroll 0, got %d\n", ret);
568 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
569 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
571 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
572 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
573 ret = GetScrollPos(hLB, SB_VERT);
574 ok(ret == 1, "expected vscroll 1, got %d\n", ret);
576 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
577 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
579 DestroyWindow(hLB);
581 hLB = create_listbox(0, 0);
582 ok(hLB != NULL, "Failed to create ListBox window.\n");
584 ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
585 ok(ret == 1, "Unexpected return value %d.\n", ret);
587 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
588 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
590 DestroyWindow(hLB);
592 /* LBS_EXTENDEDSEL */
593 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
594 ok(hLB != NULL, "Failed to create ListBox window.\n");
596 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
597 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
599 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
600 ok(ret == -1, "Unexpected return value %d.\n", ret);
602 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
603 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
605 DestroyWindow(hLB);
607 /* LBS_MULTIPLESEL */
608 hLB = create_listbox(LBS_MULTIPLESEL, 0);
609 ok(hLB != NULL, "Failed to create ListBox window.\n");
611 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
612 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
614 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
615 ok(ret == -1, "Unexpected return value %d.\n", ret);
617 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
618 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
620 DestroyWindow(hLB);
623 static void test_LB_SETSEL(void)
625 HWND list;
626 int ret;
628 /* LBS_EXTENDEDSEL */
629 list = create_listbox(LBS_EXTENDEDSEL, 0);
630 ok(list != NULL, "Failed to create ListBox window.\n");
632 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
633 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
634 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
635 ok(ret == 0, "Unexpected caret index %d.\n", ret);
637 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
638 ok(ret == 0, "Unexpected return value %d.\n", ret);
639 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
640 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
641 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
642 ok(ret == 0, "Unexpected caret index %d.\n", ret);
644 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
645 ok(ret == 0, "Unexpected return value %d.\n", ret);
646 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
647 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
648 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
649 ok(ret == 1, "Unexpected caret index %d.\n", ret);
651 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
652 ok(ret == 0, "Unexpected return value %d.\n", ret);
653 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
654 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
655 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
656 ok(ret == 1, "Unexpected caret index %d.\n", ret);
658 DestroyWindow(list);
660 /* LBS_MULTIPLESEL */
661 list = create_listbox(LBS_MULTIPLESEL, 0);
662 ok(list != NULL, "Failed to create ListBox window.\n");
664 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
665 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
666 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
667 ok(ret == 0, "Unexpected caret index %d.\n", ret);
669 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
670 ok(ret == 0, "Unexpected return value %d.\n", ret);
671 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
672 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
673 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
674 ok(ret == 0, "Unexpected caret index %d.\n", ret);
676 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
677 ok(ret == 0, "Unexpected return value %d.\n", ret);
678 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
679 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
680 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
681 ok(ret == 1, "Unexpected caret index %d.\n", ret);
683 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
684 ok(ret == 0, "Unexpected return value %d.\n", ret);
685 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
686 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
687 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
688 ok(ret == 1, "Unexpected caret index %d.\n", ret);
690 DestroyWindow(list);
693 static void test_listbox_height(void)
695 HWND hList;
696 int r, id;
698 hList = CreateWindowA( "ListBox", "list test", 0,
699 1, 1, 600, 100, NULL, NULL, NULL, NULL );
700 ok( hList != NULL, "failed to create listbox\n");
702 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
703 ok( id == 0, "item id wrong\n");
705 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
706 ok( r == 0, "send message failed\n");
708 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
709 ok( r == 20, "height wrong\n");
711 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
712 ok( r == -1, "send message failed\n");
714 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
715 ok( r == 20, "height wrong\n");
717 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
718 ok( r == -1, "send message failed\n");
720 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
721 ok( r == 20, "height wrong\n");
723 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
724 ok( r == 0, "send message failed\n");
726 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
727 ok( r == 0xff, "height wrong\n");
729 DestroyWindow( hList );
732 static void test_changing_selection_styles(void)
734 static const DWORD styles[] =
737 LBS_NODATA | LBS_OWNERDRAWFIXED
739 static const DWORD selstyles[] =
742 LBS_MULTIPLESEL,
743 LBS_EXTENDEDSEL,
744 LBS_MULTIPLESEL | LBS_EXTENDEDSEL
746 static const LONG selexpect_single[] = { 0, 0, 1 };
747 static const LONG selexpect_single2[] = { 1, 0, 0 };
748 static const LONG selexpect_multi[] = { 1, 0, 1 };
749 static const LONG selexpect_multi2[] = { 1, 1, 0 };
751 HWND parent, listbox;
752 DWORD style;
753 LONG ret;
754 UINT i, j, k;
756 parent = create_parent();
757 ok(parent != NULL, "Failed to create parent window.\n");
758 for (i = 0; i < ARRAY_SIZE(styles); i++)
760 /* Test if changing selection styles affects selection storage */
761 for (j = 0; j < ARRAY_SIZE(selstyles); j++)
763 LONG setcursel_expect, selitemrange_expect, getselcount_expect;
764 const LONG *selexpect;
766 listbox = CreateWindowA("listbox", "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE,
767 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
768 ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j);
770 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
772 setcursel_expect = LB_ERR;
773 selitemrange_expect = LB_OKAY;
774 getselcount_expect = 2;
775 selexpect = selexpect_multi;
777 else
779 setcursel_expect = 2;
780 selitemrange_expect = LB_ERR;
781 getselcount_expect = LB_ERR;
782 selexpect = selexpect_single;
785 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
787 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x");
788 ok(ret == k, "%u: Unexpected return value %d, expected %d.\n", j, ret, k);
790 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
791 ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\n", j, ret);
793 /* Select items with different methods */
794 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
795 ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
796 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0));
797 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
798 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2));
799 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
801 /* Verify that the proper items are selected */
802 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
804 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
805 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
806 j, ret, selexpect[k]);
809 /* Now change the selection style */
810 style = GetWindowLongA(listbox, GWL_STYLE);
811 ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j],
812 "%u: unexpected window styles %#x.\n", j, style);
813 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
814 style &= ~selstyles[j];
815 else
816 style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
817 SetWindowLongA(listbox, GWL_STYLE, style);
818 style = GetWindowLongA(listbox, GWL_STYLE);
819 ok(!(style & selstyles[j]), "%u: unexpected window styles %#x.\n", j, style);
821 /* Verify that the same items are selected */
822 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
823 ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
824 j, getselcount_expect, ret);
826 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
828 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
829 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
830 j, ret, selexpect[k]);
833 /* Lastly see if we can still change the selection as before with old style */
834 if (setcursel_expect != LB_ERR) setcursel_expect = 0;
835 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
836 ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
837 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1));
838 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
839 ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2));
840 ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
842 /* And verify the selections */
843 selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2;
844 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
845 ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
846 j, getselcount_expect, ret);
848 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
850 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
851 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
852 j, ret, selexpect[k]);
855 DestroyWindow(listbox);
858 DestroyWindow(parent);
861 static void test_itemfrompoint(void)
863 /* WS_POPUP is required in order to have a more accurate size calculation (
864 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
865 behavior of partially-displayed item.
867 HWND hList = CreateWindowA( "ListBox", "list test",
868 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
869 1, 1, 600, 100, NULL, NULL, NULL, NULL );
870 ULONG r, id;
871 RECT rc;
873 /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
874 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
875 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
877 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
878 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
880 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
881 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
883 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
884 ok( id == 0, "item id wrong\n");
885 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
886 ok( id == 1, "item id wrong\n");
888 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
889 ok( r == 0x1, "ret %x\n", r );
891 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
892 ok( r == 0x10001 || broken(r == 1), /* nt4 */
893 "ret %x\n", r );
895 /* Resize control so that below assertions about sizes are valid */
896 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
897 ok( r == 1, "ret %x\n", r);
898 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
899 ok( r != 0, "ret %x\n", r);
901 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
902 ok( id == 2, "item id wrong\n");
903 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
904 ok( id == 3, "item id wrong\n");
905 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
906 ok( id == 4, "item id wrong\n");
907 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
908 ok( id == 5, "item id wrong\n");
909 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
910 ok( id == 6, "item id wrong\n");
911 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
912 ok( id == 7, "item id wrong\n");
914 /* Set the listbox up so that id 1 is at the top, this leaves 5
915 partially visible at the bottom and 6, 7 are invisible */
917 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
918 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
919 ok( r == 1, "top %d\n", r);
921 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
922 ok( r == 1, "ret %x\n", r);
923 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
924 ok( r == 0, "ret %x\n", r);
926 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
927 ok( r == 1, "ret %x\n", r);
929 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
930 ok( r == 0x10001 || broken(r == 1), /* nt4 */
931 "ret %x\n", r );
933 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
934 ok( r == 0x10001 || broken(r == 1), /* nt4 */
935 "ret %x\n", r );
937 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
938 ok( r == 0x10005 || broken(r == 5), /* nt4 */
939 "item %x\n", r );
941 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
942 ok( r == 0x10005 || broken(r == 5), /* nt4 */
943 "item %x\n", r );
945 DestroyWindow( hList );
948 static void test_listbox_item_data(void)
950 HWND hList;
951 int r, id;
953 hList = CreateWindowA( "ListBox", "list test", 0,
954 1, 1, 600, 100, NULL, NULL, NULL, NULL );
955 ok( hList != NULL, "failed to create listbox\n");
957 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
958 ok( id == 0, "item id wrong\n");
960 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
961 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
963 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
964 ok( r == 20, "get item data failed\n");
966 DestroyWindow( hList );
969 static void test_listbox_LB_DIR(void)
971 char path[MAX_PATH], curdir[MAX_PATH];
972 HWND hList;
973 int res, itemCount;
974 int itemCount_justFiles;
975 int itemCount_justDrives;
976 int itemCount_allFiles;
977 int itemCount_allDirs;
978 int i;
979 char pathBuffer[MAX_PATH];
980 char * p;
981 char driveletter;
982 const char *wildcard = "*";
983 HANDLE file;
984 BOOL ret;
986 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
988 GetTempPathA(ARRAY_SIZE(path), path);
989 ret = SetCurrentDirectoryA(path);
990 ok(ret, "Failed to set current directory.\n");
992 ret = CreateDirectoryA("lb_dir_test", NULL);
993 ok(ret, "Failed to create test directory.\n");
995 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
996 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
997 CloseHandle( file );
999 /* NOTE: for this test to succeed, there must be no subdirectories
1000 under the current directory. In addition, there must be at least
1001 one file that fits the wildcard w*.c . Normally, the test
1002 directory itself satisfies both conditions.
1004 hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
1005 1, 1, 600, 100, NULL, NULL, NULL, NULL );
1006 assert(hList);
1008 /* Test for standard usage */
1010 /* This should list all the files in the test directory. */
1011 strcpy(pathBuffer, wildcard);
1012 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1013 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1014 if (res == -1) /* "*" wildcard doesn't work on win9x */
1016 wildcard = "*.*";
1017 strcpy(pathBuffer, wildcard);
1018 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1020 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
1022 /* There should be some content in the listbox */
1023 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1024 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
1025 itemCount_allFiles = itemCount;
1026 ok(res + 1 == itemCount,
1027 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
1028 itemCount - 1, res);
1030 /* This tests behavior when no files match the wildcard */
1031 strcpy(pathBuffer, BAD_EXTENSION);
1032 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1033 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1034 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1036 /* There should be NO content in the listbox */
1037 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1038 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1041 /* This should list all the w*.c files in the test directory
1042 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1044 strcpy(pathBuffer, "w*.c");
1045 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1046 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1047 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
1049 /* Path specification does NOT converted to uppercase */
1050 ok (!strcmp(pathBuffer, "w*.c"),
1051 "expected no change to pathBuffer, got %s\n", pathBuffer);
1053 /* There should be some content in the listbox */
1054 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1055 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
1056 itemCount_justFiles = itemCount;
1057 ok(res + 1 == itemCount,
1058 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
1059 itemCount - 1, res);
1061 /* Every single item in the control should start with a w and end in .c */
1062 for (i = 0; i < itemCount; i++) {
1063 memset(pathBuffer, 0, MAX_PATH);
1064 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1065 p = pathBuffer + strlen(pathBuffer);
1066 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1067 (*(p-1) == 'c' || *(p-1) == 'C') &&
1068 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1071 /* Test DDL_DIRECTORY */
1072 strcpy(pathBuffer, wildcard);
1073 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1074 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1075 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
1077 /* There should be some content in the listbox.
1078 * All files plus "[..]"
1080 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1081 itemCount_allDirs = itemCount - itemCount_allFiles;
1082 ok (itemCount > itemCount_allFiles,
1083 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
1084 itemCount, itemCount_allFiles);
1085 ok(res + 1 == itemCount,
1086 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
1087 itemCount - 1, res);
1089 /* This tests behavior when no files match the wildcard */
1090 strcpy(pathBuffer, BAD_EXTENSION);
1091 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1092 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1093 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1095 /* There should be NO content in the listbox */
1096 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1097 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1100 /* Test DDL_DIRECTORY */
1101 strcpy(pathBuffer, "w*.c");
1102 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1103 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1104 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
1106 /* There should be some content in the listbox. Since the parent directory does not
1107 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
1109 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1110 ok (itemCount == itemCount_justFiles,
1111 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
1112 itemCount, itemCount_justFiles);
1113 ok(res + 1 == itemCount,
1114 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
1115 itemCount - 1, res);
1117 /* Every single item in the control should start with a w and end in .c. */
1118 for (i = 0; i < itemCount; i++) {
1119 memset(pathBuffer, 0, MAX_PATH);
1120 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1121 p = pathBuffer + strlen(pathBuffer);
1123 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1124 (*(p-1) == 'c' || *(p-1) == 'C') &&
1125 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1129 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
1130 strcpy(pathBuffer, wildcard);
1131 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1132 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1133 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
1135 /* There should be some content in the listbox. In particular, there should
1136 * be at least one element before, since the string "[-c-]" should
1137 * have been added. Depending on the user setting, more drives might have
1138 * been added.
1140 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1141 ok (itemCount >= 1,
1142 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
1143 itemCount, 1);
1144 itemCount_justDrives = itemCount;
1145 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1147 /* Every single item in the control should fit the format [-c-] */
1148 for (i = 0; i < itemCount; i++) {
1149 memset(pathBuffer, 0, MAX_PATH);
1150 driveletter = '\0';
1151 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1152 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1153 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1154 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1155 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1156 /* Correct after invalid entry is found */
1157 trace("removing count of invalid entry %s\n", pathBuffer);
1158 itemCount_justDrives--;
1162 /* This tests behavior when no files match the wildcard */
1163 strcpy(pathBuffer, BAD_EXTENSION);
1164 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1165 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1166 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1167 BAD_EXTENSION, res, itemCount_justDrives -1);
1169 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1170 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
1171 itemCount, itemCount_justDrives);
1173 trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
1174 itemCount_justFiles, itemCount_justDrives);
1176 /* Test DDL_DRIVES. */
1177 strcpy(pathBuffer, wildcard);
1178 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1179 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1180 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1182 /* There should be some content in the listbox. In particular, there should
1183 * be at least one element before, since the string "[-c-]" should
1184 * have been added. Depending on the user setting, more drives might have
1185 * been added.
1187 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1188 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
1189 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
1190 itemCount, itemCount_justDrives + itemCount_allFiles);
1191 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
1193 /* This tests behavior when no files match the wildcard */
1194 strcpy(pathBuffer, BAD_EXTENSION);
1195 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1196 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1197 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
1198 BAD_EXTENSION, res, itemCount_justDrives -1);
1200 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1201 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1204 /* Test DDL_DRIVES. */
1205 strcpy(pathBuffer, "w*.c");
1206 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1207 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1208 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1210 /* There should be some content in the listbox. In particular, there should
1211 * be at least one element before, since the string "[-c-]" should
1212 * have been added. Depending on the user setting, more drives might have
1213 * been added.
1215 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1216 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1217 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1218 itemCount, itemCount_justDrives + itemCount_justFiles);
1219 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1221 /* Every single item in the control should fit the format [-c-], or w*.c */
1222 for (i = 0; i < itemCount; i++) {
1223 memset(pathBuffer, 0, MAX_PATH);
1224 driveletter = '\0';
1225 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1226 p = pathBuffer + strlen(pathBuffer);
1227 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1228 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1229 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1230 } else {
1232 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1233 (*(p-1) == 'c' || *(p-1) == 'C') &&
1234 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1239 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1240 strcpy(pathBuffer, wildcard);
1241 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1242 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1243 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1245 /* There should be some content in the listbox. In particular, there should
1246 * be exactly the number of plain files, plus the number of mapped drives.
1248 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1249 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1250 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1251 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1252 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1254 /* Every single item in the control should start with a w and end in .c,
1255 * except for the "[..]" string, which should appear exactly as it is,
1256 * and the mapped drives in the format "[-X-]".
1258 for (i = 0; i < itemCount; i++) {
1259 memset(pathBuffer, 0, MAX_PATH);
1260 driveletter = '\0';
1261 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1262 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1263 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1267 /* This tests behavior when no files match the wildcard */
1268 strcpy(pathBuffer, BAD_EXTENSION);
1269 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1270 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1271 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1272 BAD_EXTENSION, res, itemCount_justDrives -1);
1274 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1275 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1279 /* Test DDL_DIRECTORY|DDL_DRIVES. */
1280 strcpy(pathBuffer, "w*.c");
1281 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1282 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1283 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1285 /* There should be some content in the listbox. In particular, there should
1286 * be exactly the number of plain files, plus the number of mapped drives.
1288 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1289 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1290 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1291 itemCount, itemCount_justFiles + itemCount_justDrives);
1292 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1294 /* Every single item in the control should start with a w and end in .c,
1295 * except the mapped drives in the format "[-X-]". The "[..]" directory
1296 * should not appear.
1298 for (i = 0; i < itemCount; i++) {
1299 memset(pathBuffer, 0, MAX_PATH);
1300 driveletter = '\0';
1301 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1302 p = pathBuffer + strlen(pathBuffer);
1303 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1304 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1305 } else {
1307 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1308 (*(p-1) == 'c' || *(p-1) == 'C') &&
1309 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1313 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1314 strcpy(pathBuffer, wildcard);
1315 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1316 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1317 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
1319 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1320 ok (itemCount == itemCount_allDirs,
1321 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1322 itemCount, itemCount_allDirs);
1323 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1325 if (itemCount)
1327 memset(pathBuffer, 0, MAX_PATH);
1328 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1329 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1332 /* This tests behavior when no files match the wildcard */
1333 strcpy(pathBuffer, BAD_EXTENSION);
1334 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1335 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1336 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1337 BAD_EXTENSION, res, -1);
1339 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1340 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1343 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1344 strcpy(pathBuffer, "w*.c");
1345 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1346 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1347 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1349 /* There should be no elements, since "[..]" does not fit w*.c */
1350 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1351 ok (itemCount == 0,
1352 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1353 itemCount, 0);
1355 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1356 strcpy(pathBuffer, wildcard);
1357 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1358 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1359 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1361 /* There should be no plain files on the listbox */
1362 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1363 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1364 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1365 itemCount, itemCount_justDrives + itemCount_allDirs);
1366 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1368 for (i = 0; i < itemCount; i++) {
1369 memset(pathBuffer, 0, MAX_PATH);
1370 driveletter = '\0';
1371 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1372 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1373 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1374 } else {
1375 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1376 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1380 /* This tests behavior when no files match the wildcard */
1381 strcpy(pathBuffer, BAD_EXTENSION);
1382 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1383 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1384 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1385 BAD_EXTENSION, res, itemCount_justDrives -1);
1387 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1388 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1390 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1391 strcpy(pathBuffer, "w*.c");
1392 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1393 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1394 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1396 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1397 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1398 ok (itemCount == itemCount_justDrives,
1399 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1400 itemCount, itemCount_justDrives);
1401 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1403 for (i = 0; i < itemCount; i++) {
1404 memset(pathBuffer, 0, MAX_PATH);
1405 driveletter = '\0';
1406 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1407 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1408 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1410 DestroyWindow(hList);
1412 DeleteFileA( "wtest1.tmp.c" );
1413 RemoveDirectoryA("lb_dir_test");
1415 SetCurrentDirectoryA(curdir);
1418 static HWND g_listBox;
1419 static HWND g_label;
1421 #define ID_TEST_LABEL 1001
1422 #define ID_TEST_LISTBOX 1002
1424 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCTA lpcs)
1426 g_label = CreateWindowA(
1427 "Static",
1428 "Contents of static control before DlgDirList.",
1429 WS_CHILD | WS_VISIBLE,
1430 10, 10, 512, 32,
1431 hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1432 if (!g_label) return FALSE;
1433 g_listBox = CreateWindowA(
1434 "ListBox",
1435 "DlgDirList test",
1436 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1437 10, 60, 256, 256,
1438 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1439 if (!g_listBox) return FALSE;
1441 return TRUE;
1444 static LRESULT CALLBACK listbox_container_window_procA (
1445 HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1447 LRESULT result = 0;
1449 switch (uiMsg) {
1450 case WM_DESTROY:
1451 PostQuitMessage(0);
1452 break;
1453 case WM_CREATE:
1454 result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1455 ? 0 : (LRESULT)-1;
1456 break;
1457 default:
1458 result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1459 break;
1461 return result;
1464 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1466 WNDCLASSA cls;
1468 cls.style = 0;
1469 cls.cbClsExtra = 0;
1470 cls.cbWndExtra = 0;
1471 cls.hInstance = hInst;
1472 cls.hIcon = NULL;
1473 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1474 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1475 cls.lpszMenuName = NULL;
1476 cls.lpfnWndProc = listbox_container_window_procA;
1477 cls.lpszClassName = "ListboxContainerClass";
1478 if (!RegisterClassA (&cls)) return FALSE;
1480 return TRUE;
1483 static void test_listbox_dlgdir(void)
1485 HINSTANCE hInst;
1486 HWND hWnd;
1487 int res, itemCount;
1488 int itemCount_allDirs;
1489 int itemCount_justFiles;
1490 int itemCount_justDrives;
1491 int i;
1492 char pathBuffer[MAX_PATH];
1493 char itemBuffer[MAX_PATH];
1494 char tempBuffer[MAX_PATH];
1495 char * p;
1496 char driveletter;
1497 HANDLE file;
1499 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1500 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1501 CloseHandle( file );
1503 /* NOTE: for this test to succeed, there must be no subdirectories
1504 under the current directory. In addition, there must be at least
1505 one file that fits the wildcard w*.c . Normally, the test
1506 directory itself satisfies both conditions.
1509 hInst = GetModuleHandleA(0);
1510 if (!RegisterListboxWindowClass(hInst)) assert(0);
1511 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1512 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1513 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1514 NULL, NULL, hInst, 0);
1515 assert(hWnd);
1517 /* Test for standard usage */
1519 /* The following should be overwritten by the directory path */
1520 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1522 /* This should list all the w*.c files in the test directory
1523 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1525 strcpy(pathBuffer, "w*.c");
1526 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1527 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1529 /* Path specification gets converted to uppercase */
1530 ok (!strcmp(pathBuffer, "W*.C"),
1531 "expected conversion to uppercase, got %s\n", pathBuffer);
1533 /* Loaded path should have overwritten the label text */
1534 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1535 trace("Static control after DlgDirList: %s\n", pathBuffer);
1536 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1538 /* There should be some content in the listbox */
1539 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1540 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1541 itemCount_justFiles = itemCount;
1543 /* Every single item in the control should start with a w and end in .c */
1544 for (i = 0; i < itemCount; i++) {
1545 memset(pathBuffer, 0, MAX_PATH);
1546 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1547 p = pathBuffer + strlen(pathBuffer);
1548 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1549 (*(p-1) == 'c' || *(p-1) == 'C') &&
1550 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1553 /* Test behavior when no files match the wildcard */
1554 strcpy(pathBuffer, BAD_EXTENSION);
1555 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1556 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1558 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1559 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1561 /* Test DDL_DIRECTORY */
1562 strcpy(pathBuffer, "w*.c");
1563 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1564 DDL_DIRECTORY);
1565 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1567 /* There should be some content in the listbox. In particular, there should
1568 * be exactly more elements than before, since the directories should
1569 * have been added.
1571 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1572 itemCount_allDirs = itemCount - itemCount_justFiles;
1573 ok (itemCount >= itemCount_justFiles,
1574 "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1575 itemCount, itemCount_justFiles);
1577 /* Every single item in the control should start with a w and end in .c,
1578 * except for the "[..]" string, which should appear exactly as it is.
1580 for (i = 0; i < itemCount; i++) {
1581 memset(pathBuffer, 0, MAX_PATH);
1582 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1583 p = pathBuffer + strlen(pathBuffer);
1584 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1585 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1586 (*(p-1) == 'c' || *(p-1) == 'C') &&
1587 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1590 /* Test behavior when no files match the wildcard */
1591 strcpy(pathBuffer, BAD_EXTENSION);
1592 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1593 DDL_DIRECTORY);
1594 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1596 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1597 ok (itemCount == itemCount_allDirs,
1598 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1599 itemCount_allDirs, itemCount);
1600 for (i = 0; i < itemCount; i++) {
1601 memset(pathBuffer, 0, MAX_PATH);
1602 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1603 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1604 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1608 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1609 strcpy(pathBuffer, "w*.c");
1610 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1611 DDL_DRIVES);
1612 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1614 /* There should be some content in the listbox. In particular, there should
1615 * be at least one element before, since the string "[-c-]" should
1616 * have been added. Depending on the user setting, more drives might have
1617 * been added.
1619 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1620 ok (itemCount >= 1,
1621 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1622 itemCount, 1);
1623 itemCount_justDrives = itemCount;
1625 /* Every single item in the control should fit the format [-c-] */
1626 for (i = 0; i < itemCount; i++) {
1627 memset(pathBuffer, 0, MAX_PATH);
1628 driveletter = '\0';
1629 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1630 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1631 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1632 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1633 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1634 /* Correct after invalid entry is found */
1635 trace("removing count of invalid entry %s\n", pathBuffer);
1636 itemCount_justDrives--;
1640 /* Test behavior when no files match the wildcard */
1641 strcpy(pathBuffer, BAD_EXTENSION);
1642 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1643 DDL_DRIVES);
1644 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1646 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1647 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1650 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1651 strcpy(pathBuffer, "w*.c");
1652 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1653 DDL_DIRECTORY|DDL_DRIVES);
1654 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1656 /* There should be some content in the listbox. In particular, there should
1657 * be exactly the number of plain files, plus the number of mapped drives,
1658 * plus one "[..]"
1660 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1661 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1662 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1663 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1665 /* Every single item in the control should start with a w and end in .c,
1666 * except for the "[..]" string, which should appear exactly as it is,
1667 * and the mapped drives in the format "[-X-]".
1669 for (i = 0; i < itemCount; i++) {
1670 memset(pathBuffer, 0, MAX_PATH);
1671 driveletter = '\0';
1672 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1673 p = pathBuffer + strlen(pathBuffer);
1674 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1675 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1676 } else {
1677 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1678 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1679 (*(p-1) == 'c' || *(p-1) == 'C') &&
1680 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1684 /* Test behavior when no files match the wildcard */
1685 strcpy(pathBuffer, BAD_EXTENSION);
1686 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1687 DDL_DIRECTORY|DDL_DRIVES);
1688 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1690 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1691 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1692 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1693 itemCount_justDrives + itemCount_allDirs, itemCount);
1697 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1698 strcpy(pathBuffer, "w*.c");
1699 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1700 DDL_DIRECTORY|DDL_EXCLUSIVE);
1701 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1703 /* There should be exactly one element: "[..]" */
1704 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1705 ok (itemCount == itemCount_allDirs,
1706 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1707 itemCount, itemCount_allDirs);
1709 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1711 memset(pathBuffer, 0, MAX_PATH);
1712 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1713 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1716 /* Test behavior when no files match the wildcard */
1717 strcpy(pathBuffer, BAD_EXTENSION);
1718 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1719 DDL_DIRECTORY|DDL_EXCLUSIVE);
1720 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1722 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1723 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1726 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1727 strcpy(pathBuffer, "w*.c");
1728 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1729 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1730 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1732 /* There should be no plain files on the listbox */
1733 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1734 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1735 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1736 itemCount, itemCount_justDrives + itemCount_allDirs);
1738 for (i = 0; i < itemCount; i++) {
1739 memset(pathBuffer, 0, MAX_PATH);
1740 driveletter = '\0';
1741 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)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 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1750 /* Test behavior when no files match the wildcard */
1751 strcpy(pathBuffer, BAD_EXTENSION);
1752 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1753 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1754 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1756 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1757 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1758 "DlgDirList() incorrectly filled the listbox!\n");
1760 /* Now test DlgDirSelectEx() in normal operation */
1761 /* Fill with everything - drives, directory and all plain files. */
1762 strcpy(pathBuffer, "*");
1763 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1764 DDL_DIRECTORY|DDL_DRIVES);
1765 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1767 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1768 memset(pathBuffer, 0, MAX_PATH);
1769 SetLastError(0xdeadbeef);
1770 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1771 ok (GetLastError() == 0xdeadbeef,
1772 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1773 GetLastError());
1774 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1775 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1777 ok (!*pathBuffer, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1779 /* Test proper drive/dir/file recognition */
1780 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1781 for (i = 0; i < itemCount; i++) {
1782 memset(itemBuffer, 0, MAX_PATH);
1783 memset(pathBuffer, 0, MAX_PATH);
1784 memset(tempBuffer, 0, MAX_PATH);
1785 driveletter = '\0';
1786 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1787 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1788 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1789 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1790 /* Current item is a drive letter */
1791 SetLastError(0xdeadbeef);
1792 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1793 ok (GetLastError() == 0xdeadbeef,
1794 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1795 i, GetLastError());
1796 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1798 /* For drive letters, DlgDirSelectEx tacks on a colon */
1799 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1800 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1801 } else if (itemBuffer[0] == '[') {
1802 /* Current item is the parent directory */
1803 SetLastError(0xdeadbeef);
1804 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1805 ok (GetLastError() == 0xdeadbeef,
1806 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1807 i, GetLastError());
1808 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1810 /* For directories, DlgDirSelectEx tacks on a backslash */
1811 p = pathBuffer + strlen(pathBuffer);
1812 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1814 tempBuffer[0] = '[';
1815 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1816 strcat(tempBuffer, "]");
1817 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1818 } else {
1819 /* Current item is a plain file */
1820 SetLastError(0xdeadbeef);
1821 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1822 ok (GetLastError() == 0xdeadbeef,
1823 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1824 i, GetLastError());
1825 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1827 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1828 * for example, "Makefile", which gets reported as "Makefile."
1830 strcpy(tempBuffer, itemBuffer);
1831 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1832 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1836 DeleteFileA( "wtest1.tmp.c" );
1838 /* Now test DlgDirSelectEx() in abnormal operation */
1839 /* Fill list with bogus entries, that look somewhat valid */
1840 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1841 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1842 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1843 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1844 for (i = 0; i < itemCount; i++) {
1845 memset(itemBuffer, 0, MAX_PATH);
1846 memset(pathBuffer, 0, MAX_PATH);
1847 memset(tempBuffer, 0, MAX_PATH);
1848 driveletter = '\0';
1849 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1850 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1851 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1852 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1853 /* Current item is a drive letter */
1854 SetLastError(0xdeadbeef);
1855 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1856 ok (GetLastError() == 0xdeadbeef,
1857 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1858 i, GetLastError());
1859 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1861 /* For drive letters, DlgDirSelectEx tacks on a colon */
1862 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1863 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1864 } else if (itemBuffer[0] == '[') {
1865 /* Current item is the parent directory */
1866 SetLastError(0xdeadbeef);
1867 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1868 ok (GetLastError() == 0xdeadbeef,
1869 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1870 i, GetLastError());
1871 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1873 /* For directories, DlgDirSelectEx tacks on a backslash */
1874 p = pathBuffer + strlen(pathBuffer);
1875 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1877 tempBuffer[0] = '[';
1878 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1879 strcat(tempBuffer, "]");
1880 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1881 } else {
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);
1890 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1891 * This affects for example, "Makefile", which gets reported as "Makefile."
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);
1899 /* Test behavior when loading folders from root with and without wildcard */
1900 strcpy(pathBuffer, "C:\\");
1901 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1902 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1903 ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1904 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1906 strcpy(pathBuffer, "C:\\*");
1907 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1908 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\* folders\n");
1909 ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1910 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1912 /* Try loading files from an invalid folder */
1913 SetLastError(0xdeadbeef);
1914 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1915 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1916 ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1917 ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1918 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1920 DestroyWindow(hWnd);
1923 static void test_set_count( void )
1925 static const DWORD styles[] =
1927 LBS_OWNERDRAWFIXED,
1928 LBS_HASSTRINGS,
1930 HWND parent, listbox;
1931 unsigned int i;
1932 LONG ret;
1933 RECT r;
1935 parent = create_parent();
1936 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1938 UpdateWindow( listbox );
1939 GetUpdateRect( listbox, &r, TRUE );
1940 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1942 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1943 ok( ret == 0, "got %d\n", ret );
1944 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1945 ok( ret == 100, "got %d\n", ret );
1947 GetUpdateRect( listbox, &r, TRUE );
1948 ok( !IsRectEmpty( &r ), "got empty rect\n");
1950 ValidateRect( listbox, NULL );
1951 GetUpdateRect( listbox, &r, TRUE );
1952 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1954 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1955 ok( ret == 0, "got %d\n", ret );
1957 GetUpdateRect( listbox, &r, TRUE );
1958 ok( !IsRectEmpty( &r ), "got empty rect\n");
1960 ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 );
1961 ok( ret == 0, "got %d\n", ret );
1962 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1963 ok( ret == -5, "got %d\n", ret );
1965 DestroyWindow( listbox );
1967 for (i = 0; i < ARRAY_SIZE(styles); ++i)
1969 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
1971 SetLastError( 0xdeadbeef );
1972 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1973 ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
1974 ok( GetLastError() == ERROR_SETCOUNT_ON_BAD_LB, "Unexpected error %d.\n", GetLastError() );
1976 DestroyWindow( listbox );
1979 DestroyWindow( parent );
1982 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1983 static int lb_getlistboxinfo;
1985 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1987 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1989 if (message == LB_GETLISTBOXINFO)
1990 lb_getlistboxinfo++;
1992 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1995 static void test_GetListBoxInfo(void)
1997 HWND listbox, parent;
1998 WNDPROC oldproc;
1999 DWORD ret;
2001 pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetListBoxInfo");
2003 if (!pGetListBoxInfo)
2005 win_skip("GetListBoxInfo() not available\n");
2006 return;
2009 parent = create_parent();
2010 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2012 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
2013 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
2015 lb_getlistboxinfo = 0;
2016 ret = pGetListBoxInfo(listbox);
2017 ok(ret > 0, "got %d\n", ret);
2018 todo_wine
2019 ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
2021 DestroyWindow(listbox);
2022 DestroyWindow(parent);
2025 static void test_init_storage( void )
2027 static const DWORD styles[] =
2029 LBS_HASSTRINGS,
2030 LBS_NODATA | LBS_OWNERDRAWFIXED,
2032 HWND parent, listbox;
2033 LONG ret, items_size;
2034 int i, j;
2036 parent = create_parent();
2037 for (i = 0; i < ARRAY_SIZE(styles); i++)
2039 listbox = CreateWindowA("listbox", "TestList", styles[i] | WS_CHILD,
2040 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
2042 items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0);
2043 ok(items_size >= 100, "expected at least 100, got %d\n", items_size);
2045 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
2046 ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2048 /* it doesn't grow since the space was already reserved */
2049 ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0);
2050 ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2052 /* it doesn't shrink the reserved space */
2053 ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0);
2054 ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2056 /* now populate almost all of it so it's not reserved anymore */
2057 if (styles[i] & LBS_NODATA)
2059 ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0);
2060 ok(ret == 0, "unexpected return value %d\n", ret);
2062 else
2064 for (j = 0; j < items_size - 1; j++)
2066 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2067 ok(ret == j, "expected %d, got %d\n", j, ret);
2071 /* we still have one more reserved slot, so it doesn't grow yet */
2072 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2073 ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2075 /* fill the slot and check again, it should grow this time */
2076 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2077 ok(ret == items_size - 1, "expected %d, got %d\n", items_size - 1, ret);
2078 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
2079 ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2080 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2081 ok(ret > items_size, "expected it to grow past %d, got %d\n", items_size, ret);
2083 DestroyWindow(listbox);
2085 DestroyWindow(parent);
2088 static void test_missing_lbuttonup( void )
2090 HWND listbox, parent, capture;
2092 parent = create_parent();
2093 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2095 /* Send button down without a corresponding button up */
2096 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10,10));
2097 capture = GetCapture();
2098 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
2100 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
2101 got_selchange = 0;
2102 SetFocus(NULL);
2103 capture = GetCapture();
2104 ok(capture == NULL, "got %p\n", capture);
2105 ok(got_selchange, "got %d\n", got_selchange);
2107 DestroyWindow(listbox);
2108 DestroyWindow(parent);
2111 static void test_extents(void)
2113 HWND listbox, parent;
2114 DWORD res;
2115 SCROLLINFO sinfo;
2116 BOOL br;
2118 parent = create_parent();
2120 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2122 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2123 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2125 sinfo.cbSize = sizeof(sinfo);
2126 sinfo.fMask = SIF_RANGE;
2127 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2128 ok(br == TRUE, "GetScrollInfo failed\n");
2129 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2130 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2131 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2132 "List box should not have a horizontal scroll bar\n");
2134 /* horizontal extent < width */
2135 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2137 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2138 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2140 sinfo.cbSize = sizeof(sinfo);
2141 sinfo.fMask = SIF_RANGE;
2142 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2143 ok(br == TRUE, "GetScrollInfo failed\n");
2144 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2145 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2146 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2147 "List box should not have a horizontal scroll bar\n");
2149 /* horizontal extent > width */
2150 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2152 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2153 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2155 sinfo.cbSize = sizeof(sinfo);
2156 sinfo.fMask = SIF_RANGE;
2157 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2158 ok(br == TRUE, "GetScrollInfo failed\n");
2159 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2160 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2161 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2162 "List box should not have a horizontal scroll bar\n");
2164 DestroyWindow(listbox);
2167 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
2169 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2170 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2172 sinfo.cbSize = sizeof(sinfo);
2173 sinfo.fMask = SIF_RANGE;
2174 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2175 ok(br == TRUE, "GetScrollInfo failed\n");
2176 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2177 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2178 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2179 "List box should not have a horizontal scroll bar\n");
2181 /* horizontal extent < width */
2182 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2184 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2185 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2187 sinfo.cbSize = sizeof(sinfo);
2188 sinfo.fMask = SIF_RANGE;
2189 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2190 ok(br == TRUE, "GetScrollInfo failed\n");
2191 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2192 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2193 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2194 "List box should not have a horizontal scroll bar\n");
2196 /* horizontal extent > width */
2197 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2199 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2200 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2202 sinfo.cbSize = sizeof(sinfo);
2203 sinfo.fMask = SIF_RANGE;
2204 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2205 ok(br == TRUE, "GetScrollInfo failed\n");
2206 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2207 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2208 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2209 "List box should have a horizontal scroll bar\n");
2211 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2213 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2214 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2216 sinfo.cbSize = sizeof(sinfo);
2217 sinfo.fMask = SIF_RANGE;
2218 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2219 ok(br == TRUE, "GetScrollInfo failed\n");
2220 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2221 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2222 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2223 "List box should not have a horizontal scroll bar\n");
2225 DestroyWindow(listbox);
2228 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
2230 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2231 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2233 sinfo.cbSize = sizeof(sinfo);
2234 sinfo.fMask = SIF_RANGE;
2235 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2236 ok(br == TRUE, "GetScrollInfo failed\n");
2237 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2238 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2239 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2240 "List box should have a horizontal scroll bar\n");
2242 /* horizontal extent < width */
2243 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2245 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2246 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2248 sinfo.cbSize = sizeof(sinfo);
2249 sinfo.fMask = SIF_RANGE;
2250 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2251 ok(br == TRUE, "GetScrollInfo failed\n");
2252 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2253 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2254 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2255 "List box should have a horizontal scroll bar\n");
2257 /* horizontal extent > width */
2258 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2260 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2261 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2263 sinfo.cbSize = sizeof(sinfo);
2264 sinfo.fMask = SIF_RANGE;
2265 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2266 ok(br == TRUE, "GetScrollInfo failed\n");
2267 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2268 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2269 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2270 "List box should have a horizontal scroll bar\n");
2272 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2274 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2275 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2277 sinfo.cbSize = sizeof(sinfo);
2278 sinfo.fMask = SIF_RANGE;
2279 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2280 ok(br == TRUE, "GetScrollInfo failed\n");
2281 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2282 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2283 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2284 "List box should have a horizontal scroll bar\n");
2286 DestroyWindow(listbox);
2288 DestroyWindow(parent);
2291 static void test_WM_MEASUREITEM(void)
2293 HWND parent, listbox;
2294 LRESULT data;
2296 parent = create_parent();
2297 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2299 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2300 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
2301 DestroyWindow(parent);
2303 parent = create_parent();
2304 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2306 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2307 ok(!data, "data = %08lx\n", data);
2308 DestroyWindow(parent);
2311 static void test_LBS_NODATA(void)
2313 static const DWORD invalid_styles[] =
2316 LBS_OWNERDRAWVARIABLE,
2317 LBS_SORT,
2318 LBS_HASSTRINGS,
2319 LBS_OWNERDRAWFIXED | LBS_SORT,
2320 LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
2322 static const UINT invalid_idx[] = { -2, 2 };
2323 static const UINT valid_idx[] = { 0, 1 };
2324 static const ULONG_PTR zero_data;
2325 HWND listbox, parent;
2326 unsigned int i;
2327 ULONG_PTR data;
2328 INT ret;
2330 listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
2331 0, 0, 100, 100, NULL, NULL, NULL, 0);
2332 ok(listbox != NULL, "Failed to create ListBox window.\n");
2334 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2335 ok(ret == 0, "Unexpected return value %d.\n", ret);
2336 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2337 ok(ret == 1, "Unexpected return value %d.\n", ret);
2338 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
2339 ok(ret == 2, "Unexpected return value %d.\n", ret);
2341 /* Invalid indices. */
2342 for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
2344 ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
2345 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2346 ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
2347 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2348 if (ret == LB_ERR)
2350 ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
2351 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2353 ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
2354 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2357 /* Valid indices. */
2358 for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
2360 ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
2361 ok(ret == TRUE, "Unexpected return value %d.\n", ret);
2362 ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
2363 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2365 memset(&data, 0xee, sizeof(data));
2366 ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
2367 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2368 ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
2370 ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
2371 ok(ret == 0, "Unexpected return value %d.\n", ret);
2374 /* More messages that don't work with LBS_NODATA. */
2375 SetLastError(0xdeadbeef);
2376 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0);
2377 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2378 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2379 SetLastError(0xdeadbeef);
2380 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
2381 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2382 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2383 SetLastError(0xdeadbeef);
2384 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0);
2385 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2386 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2387 SetLastError(0xdeadbeef);
2388 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
2389 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2390 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2391 SetLastError(0xdeadbeef);
2392 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0);
2393 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2394 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2395 SetLastError(0xdeadbeef);
2396 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
2397 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2398 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2400 DestroyWindow(listbox);
2402 /* Invalid window style combinations. */
2403 parent = create_parent();
2404 ok(parent != NULL, "Failed to create parent window.\n");
2406 for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
2408 DWORD style;
2410 listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
2411 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
2412 ok(listbox != NULL, "Failed to create a listbox.\n");
2414 style = GetWindowLongA(listbox, GWL_STYLE);
2415 ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style);
2416 ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
2417 ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
2418 DestroyWindow(listbox);
2421 DestroyWindow(parent);
2424 START_TEST(listbox)
2426 const struct listbox_test SS =
2427 /* {add_style} */
2428 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2429 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2430 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2431 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2432 /* {selected, anchor, caret, selcount}{TODO fields} */
2433 const struct listbox_test SS_NS =
2434 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2435 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2436 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2437 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2438 const struct listbox_test MS =
2439 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2440 { 1, 1, 1, 1}, {0,0,0,0},
2441 { 2, 1, 2, 1}, {0,0,0,0},
2442 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2443 const struct listbox_test MS_NS =
2444 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2445 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2446 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2447 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2448 const struct listbox_test ES =
2449 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2450 { 1, 1, 1, 1}, {0,0,0,0},
2451 { 2, 2, 2, 1}, {0,0,0,0},
2452 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2453 const struct listbox_test ES_NS =
2454 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2455 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2456 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2457 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2458 const struct listbox_test EMS =
2459 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2460 { 1, 1, 1, 1}, {0,0,0,0},
2461 { 2, 2, 2, 1}, {0,0,0,0},
2462 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2463 const struct listbox_test EMS_NS =
2464 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2465 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2466 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2467 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2469 trace (" Testing single selection...\n");
2470 check (0, SS);
2471 trace (" ... with NOSEL\n");
2472 check (LBS_NOSEL, SS_NS);
2473 trace (" ... LBS_NODATA variant ...\n");
2474 check (LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
2475 trace (" ... with NOSEL\n");
2476 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
2478 trace (" Testing multiple selection...\n");
2479 check (LBS_MULTIPLESEL, MS);
2480 trace (" ... with NOSEL\n");
2481 check (LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2482 trace (" ... LBS_NODATA variant ...\n");
2483 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
2484 trace (" ... with NOSEL\n");
2485 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2487 trace (" Testing extended selection...\n");
2488 check (LBS_EXTENDEDSEL, ES);
2489 trace (" ... with NOSEL\n");
2490 check (LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2491 trace (" ... LBS_NODATA variant ...\n");
2492 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
2493 trace (" ... with NOSEL\n");
2494 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2496 trace (" Testing extended and multiple selection...\n");
2497 check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2498 trace (" ... with NOSEL\n");
2499 check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2500 trace (" ... LBS_NODATA variant ...\n");
2501 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2502 trace (" ... with NOSEL\n");
2503 check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2505 check_item_height();
2506 test_ownerdraw();
2507 test_LB_SELITEMRANGE();
2508 test_LB_SETCURSEL();
2509 test_listbox_height();
2510 test_changing_selection_styles();
2511 test_itemfrompoint();
2512 test_listbox_item_data();
2513 test_listbox_LB_DIR();
2514 test_listbox_dlgdir();
2515 test_set_count();
2516 test_init_storage();
2517 test_GetListBoxInfo();
2518 test_missing_lbuttonup();
2519 test_extents();
2520 test_WM_MEASUREITEM();
2521 test_LB_SETSEL();
2522 test_LBS_NODATA();