user32: Only update listbox horizontal scroll info if WS_HSCROLL is set.
[wine.git] / dlls / user32 / tests / listbox.c
blobd99a82c8b8eef0fe54f00d1253bbdd49fbbcda0e
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 HWND
50 create_listbox (DWORD add_style, HWND parent)
52 HWND handle;
53 INT_PTR ctl_id=0;
54 if (parent)
55 ctl_id=1;
56 handle=CreateWindowA("LISTBOX", "TestList",
57 (LBS_STANDARD & ~LBS_SORT) | add_style,
58 0, 0, 100, 100,
59 parent, (HMENU)ctl_id, NULL, 0);
61 assert (handle);
62 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
63 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
64 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
65 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
67 #ifdef VISIBLE
68 ShowWindow (handle, SW_SHOW);
69 #endif
70 REDRAW;
72 return handle;
75 struct listbox_prop {
76 DWORD add_style;
79 struct listbox_stat {
80 int selected, anchor, caret, selcount;
83 struct listbox_test {
84 struct listbox_prop prop;
85 struct listbox_stat init, init_todo;
86 struct listbox_stat click, click_todo;
87 struct listbox_stat step, step_todo;
88 struct listbox_stat sel, sel_todo;
91 static void
92 listbox_query (HWND handle, struct listbox_stat *results)
94 results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
95 results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
96 results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
97 results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
100 static void
101 buttonpress (HWND handle, WORD x, WORD y)
103 LPARAM lp=x+(y<<16);
105 WAIT;
106 SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
107 SendMessageA(handle, WM_LBUTTONUP, 0, lp);
108 REDRAW;
111 static void
112 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
114 LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
116 WAIT;
117 SendMessageA(handle, WM_KEYDOWN, keycode, lp);
118 SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000);
119 REDRAW;
122 #define listbox_field_ok(t, s, f, got) \
123 ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
124 ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
125 t.s.f, got.f)
127 #define listbox_todo_field_ok(t, s, f, got) \
128 if (t.s##_todo.f) todo_wine { listbox_field_ok(t, s, f, got); } \
129 else listbox_field_ok(t, s, f, got)
131 #define listbox_ok(t, s, got) \
132 listbox_todo_field_ok(t, s, selected, got); \
133 listbox_todo_field_ok(t, s, anchor, got); \
134 listbox_todo_field_ok(t, s, caret, got); \
135 listbox_todo_field_ok(t, s, selcount, got)
137 static void
138 check (const struct listbox_test test)
140 struct listbox_stat answer;
141 HWND hLB=create_listbox (test.prop.add_style, 0);
142 RECT second_item;
143 int i;
144 int res;
146 listbox_query (hLB, &answer);
147 listbox_ok (test, init, answer);
149 SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
150 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
152 listbox_query (hLB, &answer);
153 listbox_ok (test, click, answer);
155 keypress (hLB, VK_DOWN, 0x50, TRUE);
157 listbox_query (hLB, &answer);
158 listbox_ok (test, step, answer);
160 DestroyWindow (hLB);
161 hLB=create_listbox (test.prop.add_style, 0);
163 SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
164 listbox_query (hLB, &answer);
165 listbox_ok (test, sel, answer);
167 for (i=0;i<4;i++) {
168 DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
169 CHAR *txt;
170 WCHAR *txtw;
171 int resA, resW;
173 txt = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, size+1);
174 resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
175 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
177 txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2);
178 resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
179 if (resA != resW) {
180 trace("SendMessageW(LB_GETTEXT) not supported on this platform (resA=%d resW=%d), skipping...\n",
181 resA, resW);
182 } else {
183 WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
184 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
187 HeapFree (GetProcessHeap(), 0, txtw);
188 HeapFree (GetProcessHeap(), 0, txt);
191 /* Confirm the count of items, and that an invalid delete does not remove anything */
192 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
193 ok((res==4), "Expected 4 items, got %d\n", res);
194 res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
195 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
196 res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
197 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
198 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
199 ok((res==4), "Expected 4 items, got %d\n", res);
201 WAIT;
202 DestroyWindow (hLB);
205 static void check_item_height(void)
207 HWND hLB;
208 HDC hdc;
209 HFONT font;
210 TEXTMETRICA tm;
211 INT itemHeight;
213 hLB = create_listbox (0, 0);
214 ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
215 ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
216 ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
217 ReleaseDC( hLB, hdc);
219 ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
221 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
222 ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
224 DestroyWindow (hLB);
226 hLB = CreateWindowA("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE,
227 0, 0, 100, 100, NULL, NULL, NULL, 0);
228 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
229 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
230 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
231 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
232 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
233 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
234 DestroyWindow (hLB);
237 static int got_selchange;
239 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
241 switch (msg)
243 case WM_DRAWITEM:
245 RECT rc_item, rc_client, rc_clip;
246 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
248 trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam);
250 ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n",
251 wparam, dis->CtlID);
252 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
254 GetClientRect(dis->hwndItem, &rc_client);
255 trace("hwndItem %p client rect (%d,%d-%d,%d)\n", dis->hwndItem,
256 rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
257 GetClipBox(dis->hDC, &rc_clip);
258 trace("clip rect (%d,%d-%d,%d)\n", rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
259 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
260 "client rect of the listbox should be equal to the clip box,"
261 "or the clip box should be empty\n");
263 trace("rcItem (%d,%d-%d,%d)\n", dis->rcItem.left, dis->rcItem.top,
264 dis->rcItem.right, dis->rcItem.bottom);
265 SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
266 trace("item rect (%d,%d-%d,%d)\n", rc_item.left, rc_item.top, rc_item.right, rc_item.bottom);
267 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
269 break;
272 case WM_COMMAND:
273 if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
274 break;
276 default:
277 break;
280 return DefWindowProcA(hwnd, msg, wparam, lparam);
283 static HWND create_parent( void )
285 WNDCLASSA cls;
286 HWND parent;
287 static ATOM class;
289 if (!class)
291 cls.style = 0;
292 cls.lpfnWndProc = main_window_proc;
293 cls.cbClsExtra = 0;
294 cls.cbWndExtra = 0;
295 cls.hInstance = GetModuleHandleA(NULL);
296 cls.hIcon = 0;
297 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
298 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
299 cls.lpszMenuName = NULL;
300 cls.lpszClassName = "main_window_class";
301 class = RegisterClassA( &cls );
304 parent = CreateWindowExA(0, "main_window_class", NULL,
305 WS_POPUP | WS_VISIBLE,
306 100, 100, 400, 400,
307 GetDesktopWindow(), 0,
308 GetModuleHandleA(NULL), NULL);
309 return parent;
312 static void test_ownerdraw(void)
314 HWND parent, hLB;
315 INT ret;
316 RECT rc;
318 parent = create_parent();
319 assert(parent);
321 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
322 assert(hLB);
324 SetForegroundWindow(hLB);
325 UpdateWindow(hLB);
327 /* make height short enough */
328 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
329 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
330 SWP_NOZORDER | SWP_NOMOVE);
332 /* make 0 item invisible */
333 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
334 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
335 ok(ret == 1, "wrong top index %d\n", ret);
337 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
338 trace("item 0 rect (%d,%d-%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
339 ok(!IsRectEmpty(&rc), "empty item rect\n");
340 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
342 DestroyWindow(hLB);
343 DestroyWindow(parent);
346 #define listbox_test_query(exp, got) \
347 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
348 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
349 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
350 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
352 static void test_selection(void)
354 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
355 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
356 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
357 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
358 HWND hLB;
359 struct listbox_stat answer;
360 INT ret;
362 trace("testing LB_SELITEMRANGE\n");
364 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
365 assert(hLB);
367 listbox_query(hLB, &answer);
368 listbox_test_query(test_nosel, answer);
370 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
371 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
372 listbox_query(hLB, &answer);
373 listbox_test_query(test_1, answer);
375 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
376 listbox_query(hLB, &answer);
377 listbox_test_query(test_nosel, answer);
379 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
380 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
381 listbox_query(hLB, &answer);
382 listbox_test_query(test_3, answer);
384 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
385 listbox_query(hLB, &answer);
386 listbox_test_query(test_nosel, answer);
388 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
389 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
390 listbox_query(hLB, &answer);
391 listbox_test_query(test_nosel, answer);
393 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
394 listbox_query(hLB, &answer);
395 listbox_test_query(test_nosel, answer);
397 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
398 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
399 listbox_query(hLB, &answer);
400 listbox_test_query(test_1, answer);
402 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
403 listbox_query(hLB, &answer);
404 listbox_test_query(test_nosel, answer);
406 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
407 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
408 listbox_query(hLB, &answer);
409 listbox_test_query(test_nosel, answer);
411 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
412 listbox_query(hLB, &answer);
413 listbox_test_query(test_nosel, answer);
415 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
416 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
417 listbox_query(hLB, &answer);
418 listbox_test_query(test_2, answer);
420 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
421 listbox_query(hLB, &answer);
422 listbox_test_query(test_nosel, answer);
424 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
425 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
426 listbox_query(hLB, &answer);
427 listbox_test_query(test_2, answer);
429 DestroyWindow(hLB);
432 static void test_listbox_height(void)
434 HWND hList;
435 int r, id;
437 hList = CreateWindowA( "ListBox", "list test", 0,
438 1, 1, 600, 100, NULL, NULL, NULL, NULL );
439 ok( hList != NULL, "failed to create listbox\n");
441 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
442 ok( id == 0, "item id wrong\n");
444 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
445 ok( r == 0, "send message failed\n");
447 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
448 ok( r == 20, "height wrong\n");
450 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
451 ok( r == -1, "send message failed\n");
453 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
454 ok( r == 20, "height wrong\n");
456 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
457 ok( r == -1, "send message failed\n");
459 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
460 ok( r == 20, "height wrong\n");
462 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
463 ok( r == 0, "send message failed\n");
465 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
466 ok( r == 0xff, "height wrong\n");
468 DestroyWindow( hList );
471 static void test_itemfrompoint(void)
473 /* WS_POPUP is required in order to have a more accurate size calculation (
474 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
475 behavior of partially-displayed item.
477 HWND hList = CreateWindowA( "ListBox", "list test",
478 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
479 1, 1, 600, 100, NULL, NULL, NULL, NULL );
480 ULONG r, id;
481 RECT rc;
483 /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
484 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
485 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
487 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
488 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
490 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
491 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
493 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
494 ok( id == 0, "item id wrong\n");
495 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
496 ok( id == 1, "item id wrong\n");
498 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
499 ok( r == 0x1, "ret %x\n", r );
501 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
502 ok( r == 0x10001 || broken(r == 1), /* nt4 */
503 "ret %x\n", r );
505 /* Resize control so that below assertions about sizes are valid */
506 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
507 ok( r == 1, "ret %x\n", r);
508 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
509 ok( r != 0, "ret %x\n", r);
511 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
512 ok( id == 2, "item id wrong\n");
513 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
514 ok( id == 3, "item id wrong\n");
515 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
516 ok( id == 4, "item id wrong\n");
517 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
518 ok( id == 5, "item id wrong\n");
519 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
520 ok( id == 6, "item id wrong\n");
521 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
522 ok( id == 7, "item id wrong\n");
524 /* Set the listbox up so that id 1 is at the top, this leaves 5
525 partially visible at the bottom and 6, 7 are invisible */
527 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
528 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
529 ok( r == 1, "top %d\n", r);
531 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
532 ok( r == 1, "ret %x\n", r);
533 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
534 ok( r == 0, "ret %x\n", r);
536 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
537 ok( r == 1, "ret %x\n", r);
539 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
540 ok( r == 0x10001 || broken(r == 1), /* nt4 */
541 "ret %x\n", r );
543 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
544 ok( r == 0x10001 || broken(r == 1), /* nt4 */
545 "ret %x\n", r );
547 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
548 ok( r == 0x10005 || broken(r == 5), /* nt4 */
549 "item %x\n", r );
551 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
552 ok( r == 0x10005 || broken(r == 5), /* nt4 */
553 "item %x\n", r );
555 DestroyWindow( hList );
558 static void test_listbox_item_data(void)
560 HWND hList;
561 int r, id;
563 hList = CreateWindowA( "ListBox", "list test", 0,
564 1, 1, 600, 100, NULL, NULL, NULL, NULL );
565 ok( hList != NULL, "failed to create listbox\n");
567 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
568 ok( id == 0, "item id wrong\n");
570 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
571 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
573 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
574 ok( r == 20, "get item data failed\n");
576 DestroyWindow( hList );
579 static void test_listbox_LB_DIR(void)
581 HWND hList;
582 int res, itemCount;
583 int itemCount_justFiles;
584 int itemCount_justDrives;
585 int itemCount_allFiles;
586 int itemCount_allDirs;
587 int i;
588 char pathBuffer[MAX_PATH];
589 char * p;
590 char driveletter;
591 const char *wildcard = "*";
592 HANDLE file;
594 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
595 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
596 CloseHandle( file );
598 /* NOTE: for this test to succeed, there must be no subdirectories
599 under the current directory. In addition, there must be at least
600 one file that fits the wildcard w*.c . Normally, the test
601 directory itself satisfies both conditions.
603 hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
604 1, 1, 600, 100, NULL, NULL, NULL, NULL );
605 assert(hList);
607 /* Test for standard usage */
609 /* This should list all the files in the test directory. */
610 strcpy(pathBuffer, wildcard);
611 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
612 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
613 if (res == -1) /* "*" wildcard doesn't work on win9x */
615 wildcard = "*.*";
616 strcpy(pathBuffer, wildcard);
617 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
619 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
621 /* There should be some content in the listbox */
622 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
623 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
624 itemCount_allFiles = itemCount;
625 ok(res + 1 == itemCount,
626 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
627 itemCount - 1, res);
629 /* This tests behavior when no files match the wildcard */
630 strcpy(pathBuffer, BAD_EXTENSION);
631 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
632 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
633 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
635 /* There should be NO content in the listbox */
636 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
637 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
640 /* This should list all the w*.c files in the test directory
641 * As of this writing, this includes win.c, winstation.c, wsprintf.c
643 strcpy(pathBuffer, "w*.c");
644 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
645 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
646 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
648 /* Path specification does NOT converted to uppercase */
649 ok (!strcmp(pathBuffer, "w*.c"),
650 "expected no change to pathBuffer, got %s\n", pathBuffer);
652 /* There should be some content in the listbox */
653 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
654 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
655 itemCount_justFiles = itemCount;
656 ok(res + 1 == itemCount,
657 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
658 itemCount - 1, res);
660 /* Every single item in the control should start with a w and end in .c */
661 for (i = 0; i < itemCount; i++) {
662 memset(pathBuffer, 0, MAX_PATH);
663 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
664 p = pathBuffer + strlen(pathBuffer);
665 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
666 (*(p-1) == 'c' || *(p-1) == 'C') &&
667 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
670 /* Test DDL_DIRECTORY */
671 strcpy(pathBuffer, wildcard);
672 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
673 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
674 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
676 /* There should be some content in the listbox.
677 * All files plus "[..]"
679 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
680 itemCount_allDirs = itemCount - itemCount_allFiles;
681 ok (itemCount > itemCount_allFiles,
682 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
683 itemCount, itemCount_allFiles);
684 ok(res + 1 == itemCount,
685 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
686 itemCount - 1, res);
688 /* This tests behavior when no files match the wildcard */
689 strcpy(pathBuffer, BAD_EXTENSION);
690 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
691 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
692 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
694 /* There should be NO content in the listbox */
695 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
696 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
699 /* Test DDL_DIRECTORY */
700 strcpy(pathBuffer, "w*.c");
701 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
702 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
703 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
705 /* There should be some content in the listbox. Since the parent directory does not
706 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
708 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
709 ok (itemCount == itemCount_justFiles,
710 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
711 itemCount, itemCount_justFiles);
712 ok(res + 1 == itemCount,
713 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
714 itemCount - 1, res);
716 /* Every single item in the control should start with a w and end in .c. */
717 for (i = 0; i < itemCount; i++) {
718 memset(pathBuffer, 0, MAX_PATH);
719 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
720 p = pathBuffer + strlen(pathBuffer);
722 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
723 (*(p-1) == 'c' || *(p-1) == 'C') &&
724 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
728 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
729 strcpy(pathBuffer, wildcard);
730 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
731 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
732 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
734 /* There should be some content in the listbox. In particular, there should
735 * be at least one element before, since the string "[-c-]" should
736 * have been added. Depending on the user setting, more drives might have
737 * been added.
739 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
740 ok (itemCount >= 1,
741 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
742 itemCount, 1);
743 itemCount_justDrives = itemCount;
744 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
746 /* Every single item in the control should fit the format [-c-] */
747 for (i = 0; i < itemCount; i++) {
748 memset(pathBuffer, 0, MAX_PATH);
749 driveletter = '\0';
750 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
751 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
752 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
753 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
754 if (!(driveletter >= 'a' && driveletter <= 'z')) {
755 /* Correct after invalid entry is found */
756 trace("removing count of invalid entry %s\n", pathBuffer);
757 itemCount_justDrives--;
761 /* This tests behavior when no files match the wildcard */
762 strcpy(pathBuffer, BAD_EXTENSION);
763 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
764 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
765 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
766 BAD_EXTENSION, res, itemCount_justDrives -1);
768 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
769 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
770 itemCount, itemCount_justDrives);
772 trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
773 itemCount_justFiles, itemCount_justDrives);
775 /* Test DDL_DRIVES. */
776 strcpy(pathBuffer, wildcard);
777 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
778 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
779 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
781 /* There should be some content in the listbox. In particular, there should
782 * be at least one element before, since the string "[-c-]" should
783 * have been added. Depending on the user setting, more drives might have
784 * been added.
786 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
787 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
788 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
789 itemCount, itemCount_justDrives + itemCount_allFiles);
790 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
792 /* This tests behavior when no files match the wildcard */
793 strcpy(pathBuffer, BAD_EXTENSION);
794 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
795 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
796 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
797 BAD_EXTENSION, res, itemCount_justDrives -1);
799 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
800 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
803 /* Test DDL_DRIVES. */
804 strcpy(pathBuffer, "w*.c");
805 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
806 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
807 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
809 /* There should be some content in the listbox. In particular, there should
810 * be at least one element before, since the string "[-c-]" should
811 * have been added. Depending on the user setting, more drives might have
812 * been added.
814 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
815 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
816 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
817 itemCount, itemCount_justDrives + itemCount_justFiles);
818 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
820 /* Every single item in the control should fit the format [-c-], or w*.c */
821 for (i = 0; i < itemCount; i++) {
822 memset(pathBuffer, 0, MAX_PATH);
823 driveletter = '\0';
824 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
825 p = pathBuffer + strlen(pathBuffer);
826 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
827 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
828 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
829 } else {
831 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
832 (*(p-1) == 'c' || *(p-1) == 'C') &&
833 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
838 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
839 strcpy(pathBuffer, wildcard);
840 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
841 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
842 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
844 /* There should be some content in the listbox. In particular, there should
845 * be exactly the number of plain files, plus the number of mapped drives.
847 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
848 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
849 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
850 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
851 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
853 /* Every single item in the control should start with a w and end in .c,
854 * except for the "[..]" string, which should appear exactly as it is,
855 * and the mapped drives in the format "[-X-]".
857 for (i = 0; i < itemCount; i++) {
858 memset(pathBuffer, 0, MAX_PATH);
859 driveletter = '\0';
860 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
861 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
862 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
866 /* This tests behavior when no files match the wildcard */
867 strcpy(pathBuffer, BAD_EXTENSION);
868 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
869 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
870 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
871 BAD_EXTENSION, res, itemCount_justDrives -1);
873 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
874 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
878 /* Test DDL_DIRECTORY|DDL_DRIVES. */
879 strcpy(pathBuffer, "w*.c");
880 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
881 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
882 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
884 /* There should be some content in the listbox. In particular, there should
885 * be exactly the number of plain files, plus the number of mapped drives.
887 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
888 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
889 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
890 itemCount, itemCount_justFiles + itemCount_justDrives);
891 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
893 /* Every single item in the control should start with a w and end in .c,
894 * except the mapped drives in the format "[-X-]". The "[..]" directory
895 * should not appear.
897 for (i = 0; i < itemCount; i++) {
898 memset(pathBuffer, 0, MAX_PATH);
899 driveletter = '\0';
900 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
901 p = pathBuffer + strlen(pathBuffer);
902 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
903 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
904 } else {
906 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
907 (*(p-1) == 'c' || *(p-1) == 'C') &&
908 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
912 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
913 strcpy(pathBuffer, wildcard);
914 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
915 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
916 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
918 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
919 ok (itemCount == itemCount_allDirs,
920 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
921 itemCount, itemCount_allDirs);
922 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
924 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
926 memset(pathBuffer, 0, MAX_PATH);
927 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
928 ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
931 /* This tests behavior when no files match the wildcard */
932 strcpy(pathBuffer, BAD_EXTENSION);
933 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
934 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
935 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
936 BAD_EXTENSION, res, -1);
938 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
939 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
942 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
943 strcpy(pathBuffer, "w*.c");
944 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
945 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
946 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
948 /* There should be no elements, since "[..]" does not fit w*.c */
949 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
950 ok (itemCount == 0,
951 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
952 itemCount, 0);
954 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
955 strcpy(pathBuffer, wildcard);
956 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
957 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
958 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
960 /* There should be no plain files on the listbox */
961 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
962 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
963 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
964 itemCount, itemCount_justDrives + itemCount_allDirs);
965 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
967 for (i = 0; i < itemCount; i++) {
968 memset(pathBuffer, 0, MAX_PATH);
969 driveletter = '\0';
970 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
971 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
972 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
973 } else {
974 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
975 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
979 /* This tests behavior when no files match the wildcard */
980 strcpy(pathBuffer, BAD_EXTENSION);
981 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
982 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
983 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
984 BAD_EXTENSION, res, itemCount_justDrives -1);
986 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
987 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
989 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
990 strcpy(pathBuffer, "w*.c");
991 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
992 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
993 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
995 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
996 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
997 ok (itemCount == itemCount_justDrives,
998 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
999 itemCount, itemCount_justDrives);
1000 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1002 for (i = 0; i < itemCount; i++) {
1003 memset(pathBuffer, 0, MAX_PATH);
1004 driveletter = '\0';
1005 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1006 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1007 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1009 DestroyWindow(hList);
1011 DeleteFileA( "wtest1.tmp.c" );
1014 static HWND g_listBox;
1015 static HWND g_label;
1017 #define ID_TEST_LABEL 1001
1018 #define ID_TEST_LISTBOX 1002
1020 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCTA lpcs)
1022 g_label = CreateWindowA(
1023 "Static",
1024 "Contents of static control before DlgDirList.",
1025 WS_CHILD | WS_VISIBLE,
1026 10, 10, 512, 32,
1027 hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1028 if (!g_label) return FALSE;
1029 g_listBox = CreateWindowA(
1030 "ListBox",
1031 "DlgDirList test",
1032 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1033 10, 60, 256, 256,
1034 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1035 if (!g_listBox) return FALSE;
1037 return TRUE;
1040 static LRESULT CALLBACK listbox_container_window_procA (
1041 HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1043 LRESULT result = 0;
1045 switch (uiMsg) {
1046 case WM_DESTROY:
1047 PostQuitMessage(0);
1048 break;
1049 case WM_CREATE:
1050 result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1051 ? 0 : (LRESULT)-1;
1052 break;
1053 default:
1054 result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1055 break;
1057 return result;
1060 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1062 WNDCLASSA cls;
1064 cls.style = 0;
1065 cls.cbClsExtra = 0;
1066 cls.cbWndExtra = 0;
1067 cls.hInstance = hInst;
1068 cls.hIcon = NULL;
1069 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1070 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1071 cls.lpszMenuName = NULL;
1072 cls.lpfnWndProc = listbox_container_window_procA;
1073 cls.lpszClassName = "ListboxContainerClass";
1074 if (!RegisterClassA (&cls)) return FALSE;
1076 return TRUE;
1079 static void test_listbox_dlgdir(void)
1081 HINSTANCE hInst;
1082 HWND hWnd;
1083 int res, itemCount;
1084 int itemCount_allDirs;
1085 int itemCount_justFiles;
1086 int itemCount_justDrives;
1087 int i;
1088 char pathBuffer[MAX_PATH];
1089 char itemBuffer[MAX_PATH];
1090 char tempBuffer[MAX_PATH];
1091 char * p;
1092 char driveletter;
1093 HANDLE file;
1095 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1096 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1097 CloseHandle( file );
1099 /* NOTE: for this test to succeed, there must be no subdirectories
1100 under the current directory. In addition, there must be at least
1101 one file that fits the wildcard w*.c . Normally, the test
1102 directory itself satisfies both conditions.
1105 hInst = GetModuleHandleA(0);
1106 if (!RegisterListboxWindowClass(hInst)) assert(0);
1107 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1108 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1109 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1110 NULL, NULL, hInst, 0);
1111 assert(hWnd);
1113 /* Test for standard usage */
1115 /* The following should be overwritten by the directory path */
1116 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1118 /* This should list all the w*.c files in the test directory
1119 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1121 strcpy(pathBuffer, "w*.c");
1122 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1123 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1125 /* Path specification gets converted to uppercase */
1126 ok (!strcmp(pathBuffer, "W*.C"),
1127 "expected conversion to uppercase, got %s\n", pathBuffer);
1129 /* Loaded path should have overwritten the label text */
1130 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1131 trace("Static control after DlgDirList: %s\n", pathBuffer);
1132 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1134 /* There should be some content in the listbox */
1135 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1136 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1137 itemCount_justFiles = itemCount;
1139 /* Every single item in the control should start with a w and end in .c */
1140 for (i = 0; i < itemCount; i++) {
1141 memset(pathBuffer, 0, MAX_PATH);
1142 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1143 p = pathBuffer + strlen(pathBuffer);
1144 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1145 (*(p-1) == 'c' || *(p-1) == 'C') &&
1146 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1149 /* Test behavior when no files match the wildcard */
1150 strcpy(pathBuffer, BAD_EXTENSION);
1151 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1152 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1154 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1155 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1157 /* Test DDL_DIRECTORY */
1158 strcpy(pathBuffer, "w*.c");
1159 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1160 DDL_DIRECTORY);
1161 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1163 /* There should be some content in the listbox. In particular, there should
1164 * be exactly more elements than before, since the directories should
1165 * have been added.
1167 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1168 itemCount_allDirs = itemCount - itemCount_justFiles;
1169 ok (itemCount >= itemCount_justFiles,
1170 "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1171 itemCount, itemCount_justFiles);
1173 /* Every single item in the control should start with a w and end in .c,
1174 * except for the "[..]" string, which should appear exactly as it is.
1176 for (i = 0; i < itemCount; i++) {
1177 memset(pathBuffer, 0, MAX_PATH);
1178 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1179 p = pathBuffer + strlen(pathBuffer);
1180 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1181 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1182 (*(p-1) == 'c' || *(p-1) == 'C') &&
1183 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1186 /* Test behavior when no files match the wildcard */
1187 strcpy(pathBuffer, BAD_EXTENSION);
1188 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1189 DDL_DIRECTORY);
1190 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1192 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1193 ok (itemCount == itemCount_allDirs,
1194 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1195 itemCount_allDirs, itemCount);
1196 for (i = 0; i < itemCount; i++) {
1197 memset(pathBuffer, 0, MAX_PATH);
1198 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1199 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1200 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1204 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1205 strcpy(pathBuffer, "w*.c");
1206 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1207 DDL_DRIVES);
1208 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) 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(g_listBox, LB_GETCOUNT, 0, 0);
1216 ok (itemCount >= 1,
1217 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1218 itemCount, 1);
1219 itemCount_justDrives = itemCount;
1221 /* Every single item in the control should fit the format [-c-] */
1222 for (i = 0; i < itemCount; i++) {
1223 memset(pathBuffer, 0, MAX_PATH);
1224 driveletter = '\0';
1225 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1226 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1227 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1228 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1229 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1230 /* Correct after invalid entry is found */
1231 trace("removing count of invalid entry %s\n", pathBuffer);
1232 itemCount_justDrives--;
1236 /* Test behavior when no files match the wildcard */
1237 strcpy(pathBuffer, BAD_EXTENSION);
1238 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1239 DDL_DRIVES);
1240 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1242 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1243 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1246 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1247 strcpy(pathBuffer, "w*.c");
1248 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1249 DDL_DIRECTORY|DDL_DRIVES);
1250 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1252 /* There should be some content in the listbox. In particular, there should
1253 * be exactly the number of plain files, plus the number of mapped drives,
1254 * plus one "[..]"
1256 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1257 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1258 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1259 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1261 /* Every single item in the control should start with a w and end in .c,
1262 * except for the "[..]" string, which should appear exactly as it is,
1263 * and the mapped drives in the format "[-X-]".
1265 for (i = 0; i < itemCount; i++) {
1266 memset(pathBuffer, 0, MAX_PATH);
1267 driveletter = '\0';
1268 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1269 p = pathBuffer + strlen(pathBuffer);
1270 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1271 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1272 } else {
1273 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1274 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1275 (*(p-1) == 'c' || *(p-1) == 'C') &&
1276 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1280 /* Test behavior when no files match the wildcard */
1281 strcpy(pathBuffer, BAD_EXTENSION);
1282 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1283 DDL_DIRECTORY|DDL_DRIVES);
1284 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1286 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1287 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1288 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1289 itemCount_justDrives + itemCount_allDirs, itemCount);
1293 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1294 strcpy(pathBuffer, "w*.c");
1295 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1296 DDL_DIRECTORY|DDL_EXCLUSIVE);
1297 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1299 /* There should be exactly one element: "[..]" */
1300 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1301 ok (itemCount == itemCount_allDirs,
1302 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1303 itemCount, itemCount_allDirs);
1305 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1307 memset(pathBuffer, 0, MAX_PATH);
1308 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1309 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1312 /* Test behavior when no files match the wildcard */
1313 strcpy(pathBuffer, BAD_EXTENSION);
1314 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1315 DDL_DIRECTORY|DDL_EXCLUSIVE);
1316 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1318 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1319 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1322 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1323 strcpy(pathBuffer, "w*.c");
1324 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1325 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1326 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1328 /* There should be no plain files on the listbox */
1329 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1330 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1331 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1332 itemCount, itemCount_justDrives + itemCount_allDirs);
1334 for (i = 0; i < itemCount; i++) {
1335 memset(pathBuffer, 0, MAX_PATH);
1336 driveletter = '\0';
1337 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1338 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1339 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1340 } else {
1341 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1342 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1346 /* Test behavior when no files match the wildcard */
1347 strcpy(pathBuffer, BAD_EXTENSION);
1348 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1349 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1350 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1352 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1353 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1354 "DlgDirList() incorrectly filled the listbox!\n");
1356 /* Now test DlgDirSelectEx() in normal operation */
1357 /* Fill with everything - drives, directory and all plain files. */
1358 strcpy(pathBuffer, "*");
1359 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1360 DDL_DIRECTORY|DDL_DRIVES);
1361 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1363 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1364 memset(pathBuffer, 0, MAX_PATH);
1365 SetLastError(0xdeadbeef);
1366 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1367 ok (GetLastError() == 0xdeadbeef,
1368 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1369 GetLastError());
1370 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1371 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1373 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1375 /* Test proper drive/dir/file recognition */
1376 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1377 for (i = 0; i < itemCount; i++) {
1378 memset(itemBuffer, 0, MAX_PATH);
1379 memset(pathBuffer, 0, MAX_PATH);
1380 memset(tempBuffer, 0, MAX_PATH);
1381 driveletter = '\0';
1382 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1383 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1384 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1385 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1386 /* Current item is a drive letter */
1387 SetLastError(0xdeadbeef);
1388 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1389 ok (GetLastError() == 0xdeadbeef,
1390 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1391 i, GetLastError());
1392 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1394 /* For drive letters, DlgDirSelectEx tacks on a colon */
1395 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1396 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1397 } else if (itemBuffer[0] == '[') {
1398 /* Current item is the parent directory */
1399 SetLastError(0xdeadbeef);
1400 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1401 ok (GetLastError() == 0xdeadbeef,
1402 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1403 i, GetLastError());
1404 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1406 /* For directories, DlgDirSelectEx tacks on a backslash */
1407 p = pathBuffer + strlen(pathBuffer);
1408 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1410 tempBuffer[0] = '[';
1411 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1412 strcat(tempBuffer, "]");
1413 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1414 } else {
1415 /* Current item is a plain file */
1416 SetLastError(0xdeadbeef);
1417 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1418 ok (GetLastError() == 0xdeadbeef,
1419 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1420 i, GetLastError());
1421 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1423 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1424 * for example, "Makefile", which gets reported as "Makefile."
1426 strcpy(tempBuffer, itemBuffer);
1427 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1428 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1432 DeleteFileA( "wtest1.tmp.c" );
1434 /* Now test DlgDirSelectEx() in abnormal operation */
1435 /* Fill list with bogus entries, that look somewhat valid */
1436 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1437 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1438 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1439 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1440 for (i = 0; i < itemCount; i++) {
1441 memset(itemBuffer, 0, MAX_PATH);
1442 memset(pathBuffer, 0, MAX_PATH);
1443 memset(tempBuffer, 0, MAX_PATH);
1444 driveletter = '\0';
1445 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1446 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1447 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1448 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1449 /* Current item is a drive letter */
1450 SetLastError(0xdeadbeef);
1451 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1452 ok (GetLastError() == 0xdeadbeef,
1453 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1454 i, GetLastError());
1455 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1457 /* For drive letters, DlgDirSelectEx tacks on a colon */
1458 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1459 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1460 } else if (itemBuffer[0] == '[') {
1461 /* Current item is the parent directory */
1462 SetLastError(0xdeadbeef);
1463 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1464 ok (GetLastError() == 0xdeadbeef,
1465 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1466 i, GetLastError());
1467 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1469 /* For directories, DlgDirSelectEx tacks on a backslash */
1470 p = pathBuffer + strlen(pathBuffer);
1471 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1473 tempBuffer[0] = '[';
1474 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1475 strcat(tempBuffer, "]");
1476 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1477 } else {
1478 /* Current item is a plain file */
1479 SetLastError(0xdeadbeef);
1480 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1481 ok (GetLastError() == 0xdeadbeef,
1482 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1483 i, GetLastError());
1484 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1486 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1487 * This affects for example, "Makefile", which gets reported as "Makefile."
1489 strcpy(tempBuffer, itemBuffer);
1490 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1491 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1495 /* Test behavior when loading folders from root with and without wildcard */
1496 strcpy(pathBuffer, "C:\\");
1497 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1498 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1499 todo_wine ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1500 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1502 strcpy(pathBuffer, "C:\\*");
1503 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1504 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\* folders\n");
1505 ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1506 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1508 /* Try loading files from an invalid folder */
1509 SetLastError(0xdeadbeef);
1510 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1511 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1512 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1513 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1514 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1516 DestroyWindow(hWnd);
1519 static void test_set_count( void )
1521 HWND parent, listbox;
1522 LONG ret;
1523 RECT r;
1525 parent = create_parent();
1526 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1528 UpdateWindow( listbox );
1529 GetUpdateRect( listbox, &r, TRUE );
1530 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1532 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1533 ok( ret == 0, "got %d\n", ret );
1534 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1535 ok( ret == 100, "got %d\n", ret );
1537 GetUpdateRect( listbox, &r, TRUE );
1538 ok( !IsRectEmpty( &r ), "got empty rect\n");
1540 ValidateRect( listbox, NULL );
1541 GetUpdateRect( listbox, &r, TRUE );
1542 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1544 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1545 ok( ret == 0, "got %d\n", ret );
1547 GetUpdateRect( listbox, &r, TRUE );
1548 ok( !IsRectEmpty( &r ), "got empty rect\n");
1550 DestroyWindow( listbox );
1551 DestroyWindow( parent );
1554 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1555 static int lb_getlistboxinfo;
1557 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1559 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1561 if (message == LB_GETLISTBOXINFO)
1562 lb_getlistboxinfo++;
1564 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1567 static void test_GetListBoxInfo(void)
1569 HWND listbox, parent;
1570 WNDPROC oldproc;
1571 DWORD ret;
1573 pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetListBoxInfo");
1575 if (!pGetListBoxInfo)
1577 win_skip("GetListBoxInfo() not available\n");
1578 return;
1581 parent = create_parent();
1582 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1584 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1585 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1587 lb_getlistboxinfo = 0;
1588 ret = pGetListBoxInfo(listbox);
1589 ok(ret > 0, "got %d\n", ret);
1590 todo_wine
1591 ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
1593 DestroyWindow(listbox);
1594 DestroyWindow(parent);
1597 static void test_missing_lbuttonup( void )
1599 HWND listbox, parent, capture;
1601 parent = create_parent();
1602 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1604 /* Send button down without a corresponding button up */
1605 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10,10));
1606 capture = GetCapture();
1607 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1609 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1610 got_selchange = 0;
1611 SetFocus(NULL);
1612 capture = GetCapture();
1613 ok(capture == NULL, "got %p\n", capture);
1614 ok(got_selchange, "got %d\n", got_selchange);
1616 DestroyWindow(listbox);
1617 DestroyWindow(parent);
1620 static void test_extents(void)
1622 HWND listbox, parent;
1623 DWORD res;
1624 SCROLLINFO sinfo;
1625 BOOL br;
1627 parent = create_parent();
1629 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1631 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1632 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1634 sinfo.cbSize = sizeof(sinfo);
1635 sinfo.fMask = SIF_RANGE;
1636 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1637 ok(br == TRUE, "GetScrollInfo failed\n");
1638 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1639 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1641 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1643 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1644 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1646 sinfo.cbSize = sizeof(sinfo);
1647 sinfo.fMask = SIF_RANGE;
1648 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1649 ok(br == TRUE, "GetScrollInfo failed\n");
1650 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1651 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1653 DestroyWindow(listbox);
1656 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1658 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1659 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1661 sinfo.cbSize = sizeof(sinfo);
1662 sinfo.fMask = SIF_RANGE;
1663 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1664 ok(br == TRUE, "GetScrollInfo failed\n");
1665 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1666 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1668 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1670 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1671 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1673 sinfo.cbSize = sizeof(sinfo);
1674 sinfo.fMask = SIF_RANGE;
1675 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1676 ok(br == TRUE, "GetScrollInfo failed\n");
1677 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1678 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1680 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1682 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1683 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1685 sinfo.cbSize = sizeof(sinfo);
1686 sinfo.fMask = SIF_RANGE;
1687 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1688 ok(br == TRUE, "GetScrollInfo failed\n");
1689 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1690 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1692 DestroyWindow(listbox);
1694 DestroyWindow(parent);
1697 START_TEST(listbox)
1699 const struct listbox_test SS =
1700 /* {add_style} */
1701 {{0},
1702 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1703 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1704 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1705 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1706 /* {selected, anchor, caret, selcount}{TODO fields} */
1707 const struct listbox_test SS_NS =
1708 {{LBS_NOSEL},
1709 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1710 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1711 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1712 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1713 const struct listbox_test MS =
1714 {{LBS_MULTIPLESEL},
1715 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1716 { 1, 1, 1, 1}, {0,0,0,0},
1717 { 2, 1, 2, 1}, {0,0,0,0},
1718 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1719 const struct listbox_test MS_NS =
1720 {{LBS_MULTIPLESEL | LBS_NOSEL},
1721 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1722 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1723 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1724 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1725 const struct listbox_test ES =
1726 {{LBS_EXTENDEDSEL},
1727 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1728 { 1, 1, 1, 1}, {0,0,0,0},
1729 { 2, 2, 2, 1}, {0,0,0,0},
1730 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1731 const struct listbox_test ES_NS =
1732 {{LBS_EXTENDEDSEL | LBS_NOSEL},
1733 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1734 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1735 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1736 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1737 const struct listbox_test EMS =
1738 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
1739 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1740 { 1, 1, 1, 1}, {0,0,0,0},
1741 { 2, 2, 2, 1}, {0,0,0,0},
1742 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1743 const struct listbox_test EMS_NS =
1744 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
1745 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1746 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1747 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1748 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1750 trace (" Testing single selection...\n");
1751 check (SS);
1752 trace (" ... with NOSEL\n");
1753 check (SS_NS);
1754 trace (" Testing multiple selection...\n");
1755 check (MS);
1756 trace (" ... with NOSEL\n");
1757 check (MS_NS);
1758 trace (" Testing extended selection...\n");
1759 check (ES);
1760 trace (" ... with NOSEL\n");
1761 check (ES_NS);
1762 trace (" Testing extended and multiple selection...\n");
1763 check (EMS);
1764 trace (" ... with NOSEL\n");
1765 check (EMS_NS);
1767 check_item_height();
1768 test_ownerdraw();
1769 test_selection();
1770 test_listbox_height();
1771 test_itemfrompoint();
1772 test_listbox_item_data();
1773 test_listbox_LB_DIR();
1774 test_listbox_dlgdir();
1775 test_set_count();
1776 test_GetListBoxInfo();
1777 test_missing_lbuttonup();
1778 test_extents();