winemac: Activate an app if it sets focus on a window shortly after a hot key is...
[wine.git] / dlls / user32 / tests / listbox.c
blob0a000ccd7721839c76e37d536130ec31afabd87b
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=CreateWindow ("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 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
63 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
64 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
65 SendMessage (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 = SendMessage (handle, LB_GETCURSEL, 0, 0);
95 results->anchor = SendMessage (handle, LB_GETANCHORINDEX, 0, 0);
96 results->caret = SendMessage (handle, LB_GETCARETINDEX, 0, 0);
97 results->selcount = SendMessage (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 SendMessage (handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
107 SendMessage (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 SendMessage (handle, WM_KEYDOWN, keycode, lp);
118 SendMessage (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 SendMessage (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 SendMessage (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 = SendMessage (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 = SendMessage (hLB, LB_GETCOUNT, 0, 0);
193 ok((res==4), "Expected 4 items, got %d\n", res);
194 res = SendMessage (hLB, LB_DELETESTRING, -1, 0);
195 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
196 res = SendMessage (hLB, LB_DELETESTRING, 4, 0);
197 ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
198 res = SendMessage (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 TEXTMETRIC 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 (GetTextMetrics( hdc, &tm ), "Can't read font metrics\n");
217 ReleaseDC( hLB, hdc);
219 ok (SendMessage(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
221 itemHeight = SendMessage(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 = CreateWindow ("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE,
227 0, 0, 100, 100, NULL, NULL, NULL, 0);
228 itemHeight = SendMessage(hLB, LB_GETITEMHEIGHT, 0, 0);
229 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
230 itemHeight = SendMessage(hLB, LB_GETITEMHEIGHT, 5, 0);
231 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
232 itemHeight = SendMessage(hLB, LB_GETITEMHEIGHT, -5, 0);
233 ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
234 DestroyWindow (hLB);
237 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
239 switch (msg)
241 case WM_DRAWITEM:
243 RECT rc_item, rc_client, rc_clip;
244 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
246 trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam);
248 ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n",
249 wparam, dis->CtlID);
250 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
252 GetClientRect(dis->hwndItem, &rc_client);
253 trace("hwndItem %p client rect (%d,%d-%d,%d)\n", dis->hwndItem,
254 rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
255 GetClipBox(dis->hDC, &rc_clip);
256 trace("clip rect (%d,%d-%d,%d)\n", rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
257 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
258 "client rect of the listbox should be equal to the clip box,"
259 "or the clip box should be empty\n");
261 trace("rcItem (%d,%d-%d,%d)\n", dis->rcItem.left, dis->rcItem.top,
262 dis->rcItem.right, dis->rcItem.bottom);
263 SendMessage(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
264 trace("item rect (%d,%d-%d,%d)\n", rc_item.left, rc_item.top, rc_item.right, rc_item.bottom);
265 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
267 break;
270 default:
271 break;
274 return DefWindowProc(hwnd, msg, wparam, lparam);
277 static HWND create_parent( void )
279 WNDCLASS cls;
280 HWND parent;
281 static ATOM class;
283 if (!class)
285 cls.style = 0;
286 cls.lpfnWndProc = main_window_proc;
287 cls.cbClsExtra = 0;
288 cls.cbWndExtra = 0;
289 cls.hInstance = GetModuleHandle(0);
290 cls.hIcon = 0;
291 cls.hCursor = LoadCursor(0, IDC_ARROW);
292 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
293 cls.lpszMenuName = NULL;
294 cls.lpszClassName = "main_window_class";
295 class = RegisterClass( &cls );
298 parent = CreateWindowEx(0, "main_window_class", NULL,
299 WS_POPUP | WS_VISIBLE,
300 100, 100, 400, 400,
301 GetDesktopWindow(), 0,
302 GetModuleHandle(0), NULL);
303 return parent;
306 static void test_ownerdraw(void)
308 HWND parent, hLB;
309 INT ret;
310 RECT rc;
312 parent = create_parent();
313 assert(parent);
315 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
316 assert(hLB);
318 SetForegroundWindow(hLB);
319 UpdateWindow(hLB);
321 /* make height short enough */
322 SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
323 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
324 SWP_NOZORDER | SWP_NOMOVE);
326 /* make 0 item invisible */
327 SendMessage(hLB, LB_SETTOPINDEX, 1, 0);
328 ret = SendMessage(hLB, LB_GETTOPINDEX, 0, 0);
329 ok(ret == 1, "wrong top index %d\n", ret);
331 SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
332 trace("item 0 rect (%d,%d-%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
333 ok(!IsRectEmpty(&rc), "empty item rect\n");
334 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
336 DestroyWindow(hLB);
337 DestroyWindow(parent);
340 #define listbox_test_query(exp, got) \
341 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
342 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
343 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
344 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
346 static void test_selection(void)
348 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
349 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
350 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
351 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
352 HWND hLB;
353 struct listbox_stat answer;
354 INT ret;
356 trace("testing LB_SELITEMRANGE\n");
358 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
359 assert(hLB);
361 listbox_query(hLB, &answer);
362 listbox_test_query(test_nosel, answer);
364 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
365 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
366 listbox_query(hLB, &answer);
367 listbox_test_query(test_1, answer);
369 SendMessage(hLB, LB_SETSEL, FALSE, -1);
370 listbox_query(hLB, &answer);
371 listbox_test_query(test_nosel, answer);
373 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
374 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
375 listbox_query(hLB, &answer);
376 listbox_test_query(test_3, answer);
378 SendMessage(hLB, LB_SETSEL, FALSE, -1);
379 listbox_query(hLB, &answer);
380 listbox_test_query(test_nosel, answer);
382 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
383 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
384 listbox_query(hLB, &answer);
385 listbox_test_query(test_nosel, answer);
387 SendMessage(hLB, LB_SETSEL, FALSE, -1);
388 listbox_query(hLB, &answer);
389 listbox_test_query(test_nosel, answer);
391 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
392 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
393 listbox_query(hLB, &answer);
394 listbox_test_query(test_1, answer);
396 SendMessage(hLB, LB_SETSEL, FALSE, -1);
397 listbox_query(hLB, &answer);
398 listbox_test_query(test_nosel, answer);
400 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
401 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
402 listbox_query(hLB, &answer);
403 listbox_test_query(test_nosel, answer);
405 SendMessage(hLB, LB_SETSEL, FALSE, -1);
406 listbox_query(hLB, &answer);
407 listbox_test_query(test_nosel, answer);
409 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
410 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
411 listbox_query(hLB, &answer);
412 listbox_test_query(test_2, answer);
414 SendMessage(hLB, LB_SETSEL, FALSE, -1);
415 listbox_query(hLB, &answer);
416 listbox_test_query(test_nosel, answer);
418 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
419 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
420 listbox_query(hLB, &answer);
421 listbox_test_query(test_2, answer);
423 DestroyWindow(hLB);
426 static void test_listbox_height(void)
428 HWND hList;
429 int r, id;
431 hList = CreateWindow( "ListBox", "list test", 0,
432 1, 1, 600, 100, NULL, NULL, NULL, NULL );
433 ok( hList != NULL, "failed to create listbox\n");
435 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
436 ok( id == 0, "item id wrong\n");
438 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
439 ok( r == 0, "send message failed\n");
441 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
442 ok( r == 20, "height wrong\n");
444 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
445 ok( r == -1, "send message failed\n");
447 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
448 ok( r == 20, "height wrong\n");
450 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
451 ok( r == -1, "send message failed\n");
453 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
454 ok( r == 20, "height wrong\n");
456 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
457 ok( r == 0, "send message failed\n");
459 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
460 ok( r == 0xff, "height wrong\n");
462 DestroyWindow( hList );
465 static void test_itemfrompoint(void)
467 /* WS_POPUP is required in order to have a more accurate size calculation (
468 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
469 behavior of partially-displayed item.
471 HWND hList = CreateWindow( "ListBox", "list test",
472 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
473 1, 1, 600, 100, NULL, NULL, NULL, NULL );
474 ULONG r, id;
475 RECT rc;
477 /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
478 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
479 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
481 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
482 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
484 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
485 ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
487 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
488 ok( id == 0, "item id wrong\n");
489 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
490 ok( id == 1, "item id wrong\n");
492 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
493 ok( r == 0x1, "ret %x\n", r );
495 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
496 ok( r == 0x10001 || broken(r == 1), /* nt4 */
497 "ret %x\n", r );
499 /* Resize control so that below assertions about sizes are valid */
500 r = SendMessage( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
501 ok( r == 1, "ret %x\n", r);
502 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
503 ok( r != 0, "ret %x\n", r);
505 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
506 ok( id == 2, "item id wrong\n");
507 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
508 ok( id == 3, "item id wrong\n");
509 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
510 ok( id == 4, "item id wrong\n");
511 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
512 ok( id == 5, "item id wrong\n");
513 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
514 ok( id == 6, "item id wrong\n");
515 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
516 ok( id == 7, "item id wrong\n");
518 /* Set the listbox up so that id 1 is at the top, this leaves 5
519 partially visible at the bottom and 6, 7 are invisible */
521 SendMessage( hList, LB_SETTOPINDEX, 1, 0);
522 r = SendMessage( hList, LB_GETTOPINDEX, 0, 0);
523 ok( r == 1, "top %d\n", r);
525 r = SendMessage( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
526 ok( r == 1, "ret %x\n", r);
527 r = SendMessage( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
528 ok( r == 0, "ret %x\n", r);
530 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
531 ok( r == 1, "ret %x\n", r);
533 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
534 ok( r == 0x10001 || broken(r == 1), /* nt4 */
535 "ret %x\n", r );
537 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
538 ok( r == 0x10001 || broken(r == 1), /* nt4 */
539 "ret %x\n", r );
541 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
542 ok( r == 0x10005 || broken(r == 5), /* nt4 */
543 "item %x\n", r );
545 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
546 ok( r == 0x10005 || broken(r == 5), /* nt4 */
547 "item %x\n", r );
549 DestroyWindow( hList );
552 static void test_listbox_item_data(void)
554 HWND hList;
555 int r, id;
557 hList = CreateWindow( "ListBox", "list test", 0,
558 1, 1, 600, 100, NULL, NULL, NULL, NULL );
559 ok( hList != NULL, "failed to create listbox\n");
561 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
562 ok( id == 0, "item id wrong\n");
564 r = SendMessage( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
565 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
567 r = SendMessage( hList, LB_GETITEMDATA, 0, 0);
568 ok( r == 20, "get item data failed\n");
570 DestroyWindow( hList );
573 static void test_listbox_LB_DIR(void)
575 HWND hList;
576 int res, itemCount;
577 int itemCount_justFiles;
578 int itemCount_justDrives;
579 int itemCount_allFiles;
580 int itemCount_allDirs;
581 int i;
582 char pathBuffer[MAX_PATH];
583 char * p;
584 char driveletter;
585 const char *wildcard = "*";
586 HANDLE file;
588 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
589 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
590 CloseHandle( file );
592 /* NOTE: for this test to succeed, there must be no subdirectories
593 under the current directory. In addition, there must be at least
594 one file that fits the wildcard w*.c . Normally, the test
595 directory itself satisfies both conditions.
597 hList = CreateWindow( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
598 1, 1, 600, 100, NULL, NULL, NULL, NULL );
599 assert(hList);
601 /* Test for standard usage */
603 /* This should list all the files in the test directory. */
604 strcpy(pathBuffer, wildcard);
605 SendMessage(hList, LB_RESETCONTENT, 0, 0);
606 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
607 if (res == -1) /* "*" wildcard doesn't work on win9x */
609 wildcard = "*.*";
610 strcpy(pathBuffer, wildcard);
611 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
613 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
615 /* There should be some content in the listbox */
616 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
617 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
618 itemCount_allFiles = itemCount;
619 ok(res + 1 == itemCount,
620 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
621 itemCount - 1, res);
623 /* This tests behavior when no files match the wildcard */
624 strcpy(pathBuffer, BAD_EXTENSION);
625 SendMessage(hList, LB_RESETCONTENT, 0, 0);
626 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
627 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
629 /* There should be NO content in the listbox */
630 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
631 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
634 /* This should list all the w*.c files in the test directory
635 * As of this writing, this includes win.c, winstation.c, wsprintf.c
637 strcpy(pathBuffer, "w*.c");
638 SendMessage(hList, LB_RESETCONTENT, 0, 0);
639 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
640 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
642 /* Path specification does NOT converted to uppercase */
643 ok (!strcmp(pathBuffer, "w*.c"),
644 "expected no change to pathBuffer, got %s\n", pathBuffer);
646 /* There should be some content in the listbox */
647 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
648 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
649 itemCount_justFiles = itemCount;
650 ok(res + 1 == itemCount,
651 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
652 itemCount - 1, res);
654 /* Every single item in the control should start with a w and end in .c */
655 for (i = 0; i < itemCount; i++) {
656 memset(pathBuffer, 0, MAX_PATH);
657 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
658 p = pathBuffer + strlen(pathBuffer);
659 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
660 (*(p-1) == 'c' || *(p-1) == 'C') &&
661 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
664 /* Test DDL_DIRECTORY */
665 strcpy(pathBuffer, wildcard);
666 SendMessage(hList, LB_RESETCONTENT, 0, 0);
667 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
668 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
670 /* There should be some content in the listbox.
671 * All files plus "[..]"
673 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
674 itemCount_allDirs = itemCount - itemCount_allFiles;
675 ok (itemCount > itemCount_allFiles,
676 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
677 itemCount, itemCount_allFiles);
678 ok(res + 1 == itemCount,
679 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
680 itemCount - 1, res);
682 /* This tests behavior when no files match the wildcard */
683 strcpy(pathBuffer, BAD_EXTENSION);
684 SendMessage(hList, LB_RESETCONTENT, 0, 0);
685 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
686 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
688 /* There should be NO content in the listbox */
689 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
690 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
693 /* Test DDL_DIRECTORY */
694 strcpy(pathBuffer, "w*.c");
695 SendMessage(hList, LB_RESETCONTENT, 0, 0);
696 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
697 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
699 /* There should be some content in the listbox. Since the parent directory does not
700 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
702 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
703 ok (itemCount == itemCount_justFiles,
704 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
705 itemCount, itemCount_justFiles);
706 ok(res + 1 == itemCount,
707 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
708 itemCount - 1, res);
710 /* Every single item in the control should start with a w and end in .c. */
711 for (i = 0; i < itemCount; i++) {
712 memset(pathBuffer, 0, MAX_PATH);
713 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
714 p = pathBuffer + strlen(pathBuffer);
716 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
717 (*(p-1) == 'c' || *(p-1) == 'C') &&
718 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
722 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
723 strcpy(pathBuffer, wildcard);
724 SendMessage(hList, LB_RESETCONTENT, 0, 0);
725 res = SendMessage(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
726 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
728 /* There should be some content in the listbox. In particular, there should
729 * be at least one element before, since the string "[-c-]" should
730 * have been added. Depending on the user setting, more drives might have
731 * been added.
733 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
734 ok (itemCount >= 1,
735 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
736 itemCount, 1);
737 itemCount_justDrives = itemCount;
738 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
740 /* Every single item in the control should fit the format [-c-] */
741 for (i = 0; i < itemCount; i++) {
742 memset(pathBuffer, 0, MAX_PATH);
743 driveletter = '\0';
744 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
745 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
746 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
747 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
748 if (!(driveletter >= 'a' && driveletter <= 'z')) {
749 /* Correct after invalid entry is found */
750 trace("removing count of invalid entry %s\n", pathBuffer);
751 itemCount_justDrives--;
755 /* This tests behavior when no files match the wildcard */
756 strcpy(pathBuffer, BAD_EXTENSION);
757 SendMessage(hList, LB_RESETCONTENT, 0, 0);
758 res = SendMessage(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
759 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
760 BAD_EXTENSION, res, itemCount_justDrives -1);
762 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
763 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
764 itemCount, itemCount_justDrives);
766 trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
767 itemCount_justFiles, itemCount_justDrives);
769 /* Test DDL_DRIVES. */
770 strcpy(pathBuffer, wildcard);
771 SendMessage(hList, LB_RESETCONTENT, 0, 0);
772 res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
773 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
775 /* There should be some content in the listbox. In particular, there should
776 * be at least one element before, since the string "[-c-]" should
777 * have been added. Depending on the user setting, more drives might have
778 * been added.
780 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
781 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
782 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
783 itemCount, itemCount_justDrives + itemCount_allFiles);
784 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
786 /* This tests behavior when no files match the wildcard */
787 strcpy(pathBuffer, BAD_EXTENSION);
788 SendMessage(hList, LB_RESETCONTENT, 0, 0);
789 res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
790 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
791 BAD_EXTENSION, res, itemCount_justDrives -1);
793 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
794 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
797 /* Test DDL_DRIVES. */
798 strcpy(pathBuffer, "w*.c");
799 SendMessage(hList, LB_RESETCONTENT, 0, 0);
800 res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
801 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
803 /* There should be some content in the listbox. In particular, there should
804 * be at least one element before, since the string "[-c-]" should
805 * have been added. Depending on the user setting, more drives might have
806 * been added.
808 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
809 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
810 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
811 itemCount, itemCount_justDrives + itemCount_justFiles);
812 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
814 /* Every single item in the control should fit the format [-c-], or w*.c */
815 for (i = 0; i < itemCount; i++) {
816 memset(pathBuffer, 0, MAX_PATH);
817 driveletter = '\0';
818 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
819 p = pathBuffer + strlen(pathBuffer);
820 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
821 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
822 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
823 } else {
825 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
826 (*(p-1) == 'c' || *(p-1) == 'C') &&
827 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
832 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
833 strcpy(pathBuffer, wildcard);
834 SendMessage(hList, LB_RESETCONTENT, 0, 0);
835 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
836 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
838 /* There should be some content in the listbox. In particular, there should
839 * be exactly the number of plain files, plus the number of mapped drives.
841 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
842 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
843 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
844 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
845 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
847 /* Every single item in the control should start with a w and end in .c,
848 * except for the "[..]" string, which should appear exactly as it is,
849 * and the mapped drives in the format "[-X-]".
851 for (i = 0; i < itemCount; i++) {
852 memset(pathBuffer, 0, MAX_PATH);
853 driveletter = '\0';
854 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
855 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
856 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
860 /* This tests behavior when no files match the wildcard */
861 strcpy(pathBuffer, BAD_EXTENSION);
862 SendMessage(hList, LB_RESETCONTENT, 0, 0);
863 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
864 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
865 BAD_EXTENSION, res, itemCount_justDrives -1);
867 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
868 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
872 /* Test DDL_DIRECTORY|DDL_DRIVES. */
873 strcpy(pathBuffer, "w*.c");
874 SendMessage(hList, LB_RESETCONTENT, 0, 0);
875 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
876 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
878 /* There should be some content in the listbox. In particular, there should
879 * be exactly the number of plain files, plus the number of mapped drives.
881 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
882 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
883 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
884 itemCount, itemCount_justFiles + itemCount_justDrives);
885 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
887 /* Every single item in the control should start with a w and end in .c,
888 * except the mapped drives in the format "[-X-]". The "[..]" directory
889 * should not appear.
891 for (i = 0; i < itemCount; i++) {
892 memset(pathBuffer, 0, MAX_PATH);
893 driveletter = '\0';
894 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
895 p = pathBuffer + strlen(pathBuffer);
896 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
897 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
898 } else {
900 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
901 (*(p-1) == 'c' || *(p-1) == 'C') &&
902 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
906 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
907 strcpy(pathBuffer, wildcard);
908 SendMessage(hList, LB_RESETCONTENT, 0, 0);
909 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
910 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
912 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
913 ok (itemCount == itemCount_allDirs,
914 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
915 itemCount, itemCount_allDirs);
916 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
918 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
920 memset(pathBuffer, 0, MAX_PATH);
921 SendMessage(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
922 ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
925 /* This tests behavior when no files match the wildcard */
926 strcpy(pathBuffer, BAD_EXTENSION);
927 SendMessage(hList, LB_RESETCONTENT, 0, 0);
928 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
929 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
930 BAD_EXTENSION, res, -1);
932 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
933 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
936 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
937 strcpy(pathBuffer, "w*.c");
938 SendMessage(hList, LB_RESETCONTENT, 0, 0);
939 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
940 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
942 /* There should be no elements, since "[..]" does not fit w*.c */
943 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
944 ok (itemCount == 0,
945 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
946 itemCount, 0);
948 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
949 strcpy(pathBuffer, wildcard);
950 SendMessage(hList, LB_RESETCONTENT, 0, 0);
951 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
952 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
954 /* There should be no plain files on the listbox */
955 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
956 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
957 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
958 itemCount, itemCount_justDrives + itemCount_allDirs);
959 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
961 for (i = 0; i < itemCount; i++) {
962 memset(pathBuffer, 0, MAX_PATH);
963 driveletter = '\0';
964 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
965 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
966 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
967 } else {
968 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
969 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
973 /* This tests behavior when no files match the wildcard */
974 strcpy(pathBuffer, BAD_EXTENSION);
975 SendMessage(hList, LB_RESETCONTENT, 0, 0);
976 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
977 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
978 BAD_EXTENSION, res, itemCount_justDrives -1);
980 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
981 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
983 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
984 strcpy(pathBuffer, "w*.c");
985 SendMessage(hList, LB_RESETCONTENT, 0, 0);
986 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
987 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
989 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
990 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
991 ok (itemCount == itemCount_justDrives,
992 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
993 itemCount, itemCount_justDrives);
994 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
996 for (i = 0; i < itemCount; i++) {
997 memset(pathBuffer, 0, MAX_PATH);
998 driveletter = '\0';
999 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1000 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1001 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1003 DestroyWindow(hList);
1005 DeleteFileA( "wtest1.tmp.c" );
1008 static HWND g_listBox;
1009 static HWND g_label;
1011 #define ID_TEST_LABEL 1001
1012 #define ID_TEST_LISTBOX 1002
1014 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCT lpcs)
1016 g_label = CreateWindow(
1017 "Static",
1018 "Contents of static control before DlgDirList.",
1019 WS_CHILD | WS_VISIBLE,
1020 10, 10, 512, 32,
1021 hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1022 if (!g_label) return FALSE;
1023 g_listBox = CreateWindow(
1024 "ListBox",
1025 "DlgDirList test",
1026 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1027 10, 60, 256, 256,
1028 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1029 if (!g_listBox) return FALSE;
1031 return TRUE;
1034 static LRESULT CALLBACK listbox_container_window_procA (
1035 HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1037 LRESULT result = 0;
1039 switch (uiMsg) {
1040 case WM_DESTROY:
1041 PostQuitMessage(0);
1042 break;
1043 case WM_CREATE:
1044 result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1045 ? 0 : (LRESULT)-1;
1046 break;
1047 default:
1048 result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1049 break;
1051 return result;
1054 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1056 WNDCLASSA cls;
1058 cls.style = 0;
1059 cls.cbClsExtra = 0;
1060 cls.cbWndExtra = 0;
1061 cls.hInstance = hInst;
1062 cls.hIcon = NULL;
1063 cls.hCursor = LoadCursorA (NULL, IDC_ARROW);
1064 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1065 cls.lpszMenuName = NULL;
1066 cls.lpfnWndProc = listbox_container_window_procA;
1067 cls.lpszClassName = "ListboxContainerClass";
1068 if (!RegisterClassA (&cls)) return FALSE;
1070 return TRUE;
1073 static void test_listbox_dlgdir(void)
1075 HINSTANCE hInst;
1076 HWND hWnd;
1077 int res, itemCount;
1078 int itemCount_allDirs;
1079 int itemCount_justFiles;
1080 int itemCount_justDrives;
1081 int i;
1082 char pathBuffer[MAX_PATH];
1083 char itemBuffer[MAX_PATH];
1084 char tempBuffer[MAX_PATH];
1085 char * p;
1086 char driveletter;
1087 HANDLE file;
1089 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1090 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1091 CloseHandle( file );
1093 /* NOTE: for this test to succeed, there must be no subdirectories
1094 under the current directory. In addition, there must be at least
1095 one file that fits the wildcard w*.c . Normally, the test
1096 directory itself satisfies both conditions.
1099 hInst = GetModuleHandleA(0);
1100 if (!RegisterListboxWindowClass(hInst)) assert(0);
1101 hWnd = CreateWindow("ListboxContainerClass", "ListboxContainerClass",
1102 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1103 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1104 NULL, NULL, hInst, 0);
1105 assert(hWnd);
1107 /* Test for standard usage */
1109 /* The following should be overwritten by the directory path */
1110 SendMessage(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1112 /* This should list all the w*.c files in the test directory
1113 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1115 strcpy(pathBuffer, "w*.c");
1116 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1117 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1119 /* Path specification gets converted to uppercase */
1120 ok (!strcmp(pathBuffer, "W*.C"),
1121 "expected conversion to uppercase, got %s\n", pathBuffer);
1123 /* Loaded path should have overwritten the label text */
1124 SendMessage(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1125 trace("Static control after DlgDirList: %s\n", pathBuffer);
1126 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1128 /* There should be some content in the listbox */
1129 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1130 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1131 itemCount_justFiles = itemCount;
1133 /* Every single item in the control should start with a w and end in .c */
1134 for (i = 0; i < itemCount; i++) {
1135 memset(pathBuffer, 0, MAX_PATH);
1136 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1137 p = pathBuffer + strlen(pathBuffer);
1138 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1139 (*(p-1) == 'c' || *(p-1) == 'C') &&
1140 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1143 /* Test behavior when no files match the wildcard */
1144 strcpy(pathBuffer, BAD_EXTENSION);
1145 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1146 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1148 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1149 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1151 /* Test DDL_DIRECTORY */
1152 strcpy(pathBuffer, "w*.c");
1153 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1154 DDL_DIRECTORY);
1155 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1157 /* There should be some content in the listbox. In particular, there should
1158 * be exactly more elements than before, since the directories should
1159 * have been added.
1161 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1162 itemCount_allDirs = itemCount - itemCount_justFiles;
1163 ok (itemCount >= itemCount_justFiles,
1164 "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1165 itemCount, itemCount_justFiles);
1167 /* Every single item in the control should start with a w and end in .c,
1168 * except for the "[..]" string, which should appear exactly as it is.
1170 for (i = 0; i < itemCount; i++) {
1171 memset(pathBuffer, 0, MAX_PATH);
1172 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1173 p = pathBuffer + strlen(pathBuffer);
1174 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1175 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1176 (*(p-1) == 'c' || *(p-1) == 'C') &&
1177 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1180 /* Test behavior when no files match the wildcard */
1181 strcpy(pathBuffer, BAD_EXTENSION);
1182 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1183 DDL_DIRECTORY);
1184 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1186 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1187 ok (itemCount == itemCount_allDirs,
1188 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1189 itemCount_allDirs, itemCount);
1190 for (i = 0; i < itemCount; i++) {
1191 memset(pathBuffer, 0, MAX_PATH);
1192 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1193 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1194 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1198 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1199 strcpy(pathBuffer, "w*.c");
1200 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1201 DDL_DRIVES);
1202 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1204 /* There should be some content in the listbox. In particular, there should
1205 * be at least one element before, since the string "[-c-]" should
1206 * have been added. Depending on the user setting, more drives might have
1207 * been added.
1209 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1210 ok (itemCount >= 1,
1211 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1212 itemCount, 1);
1213 itemCount_justDrives = itemCount;
1215 /* Every single item in the control should fit the format [-c-] */
1216 for (i = 0; i < itemCount; i++) {
1217 memset(pathBuffer, 0, MAX_PATH);
1218 driveletter = '\0';
1219 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1220 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1221 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1222 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1223 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1224 /* Correct after invalid entry is found */
1225 trace("removing count of invalid entry %s\n", pathBuffer);
1226 itemCount_justDrives--;
1230 /* Test behavior when no files match the wildcard */
1231 strcpy(pathBuffer, BAD_EXTENSION);
1232 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1233 DDL_DRIVES);
1234 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1236 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1237 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1240 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1241 strcpy(pathBuffer, "w*.c");
1242 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1243 DDL_DIRECTORY|DDL_DRIVES);
1244 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1246 /* There should be some content in the listbox. In particular, there should
1247 * be exactly the number of plain files, plus the number of mapped drives,
1248 * plus one "[..]"
1250 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1251 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1252 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1253 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1255 /* Every single item in the control should start with a w and end in .c,
1256 * except for the "[..]" string, which should appear exactly as it is,
1257 * and the mapped drives in the format "[-X-]".
1259 for (i = 0; i < itemCount; i++) {
1260 memset(pathBuffer, 0, MAX_PATH);
1261 driveletter = '\0';
1262 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1263 p = pathBuffer + strlen(pathBuffer);
1264 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1265 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1266 } else {
1267 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1268 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1269 (*(p-1) == 'c' || *(p-1) == 'C') &&
1270 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1274 /* Test behavior when no files match the wildcard */
1275 strcpy(pathBuffer, BAD_EXTENSION);
1276 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1277 DDL_DIRECTORY|DDL_DRIVES);
1278 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1280 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1281 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1282 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1283 itemCount_justDrives + itemCount_allDirs, itemCount);
1287 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1288 strcpy(pathBuffer, "w*.c");
1289 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1290 DDL_DIRECTORY|DDL_EXCLUSIVE);
1291 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1293 /* There should be exactly one element: "[..]" */
1294 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1295 ok (itemCount == itemCount_allDirs,
1296 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1297 itemCount, itemCount_allDirs);
1299 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1301 memset(pathBuffer, 0, MAX_PATH);
1302 SendMessage(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1303 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1306 /* Test behavior when no files match the wildcard */
1307 strcpy(pathBuffer, BAD_EXTENSION);
1308 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1309 DDL_DIRECTORY|DDL_EXCLUSIVE);
1310 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1312 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1313 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1316 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1317 strcpy(pathBuffer, "w*.c");
1318 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1319 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1320 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1322 /* There should be no plain files on the listbox */
1323 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1324 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1325 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1326 itemCount, itemCount_justDrives + itemCount_allDirs);
1328 for (i = 0; i < itemCount; i++) {
1329 memset(pathBuffer, 0, MAX_PATH);
1330 driveletter = '\0';
1331 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1332 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1333 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1334 } else {
1335 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1336 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1340 /* Test behavior when no files match the wildcard */
1341 strcpy(pathBuffer, BAD_EXTENSION);
1342 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1343 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1344 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1346 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1347 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1348 "DlgDirList() incorrectly filled the listbox!\n");
1350 /* Now test DlgDirSelectEx() in normal operation */
1351 /* Fill with everything - drives, directory and all plain files. */
1352 strcpy(pathBuffer, "*");
1353 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1354 DDL_DIRECTORY|DDL_DRIVES);
1355 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1357 SendMessage(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1358 memset(pathBuffer, 0, MAX_PATH);
1359 SetLastError(0xdeadbeef);
1360 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1361 ok (GetLastError() == 0xdeadbeef,
1362 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1363 GetLastError());
1364 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1365 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1367 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1369 /* Test proper drive/dir/file recognition */
1370 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1371 for (i = 0; i < itemCount; i++) {
1372 memset(itemBuffer, 0, MAX_PATH);
1373 memset(pathBuffer, 0, MAX_PATH);
1374 memset(tempBuffer, 0, MAX_PATH);
1375 driveletter = '\0';
1376 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1377 res = SendMessage(g_listBox, LB_SETCURSEL, i, 0);
1378 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1379 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1380 /* Current item is a drive letter */
1381 SetLastError(0xdeadbeef);
1382 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1383 ok (GetLastError() == 0xdeadbeef,
1384 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1385 i, GetLastError());
1386 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1388 /* For drive letters, DlgDirSelectEx tacks on a colon */
1389 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1390 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1391 } else if (itemBuffer[0] == '[') {
1392 /* Current item is the parent directory */
1393 SetLastError(0xdeadbeef);
1394 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1395 ok (GetLastError() == 0xdeadbeef,
1396 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1397 i, GetLastError());
1398 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1400 /* For directories, DlgDirSelectEx tacks on a backslash */
1401 p = pathBuffer + strlen(pathBuffer);
1402 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1404 tempBuffer[0] = '[';
1405 strncpy(tempBuffer + 1, pathBuffer, strlen(pathBuffer) - 1);
1406 strcat(tempBuffer, "]");
1407 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1408 } else {
1409 /* Current item is a plain file */
1410 SetLastError(0xdeadbeef);
1411 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1412 ok (GetLastError() == 0xdeadbeef,
1413 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1414 i, GetLastError());
1415 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1417 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1418 * for example, "Makefile", which gets reported as "Makefile."
1420 strcpy(tempBuffer, itemBuffer);
1421 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1422 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1426 DeleteFileA( "wtest1.tmp.c" );
1428 /* Now test DlgDirSelectEx() in abnormal operation */
1429 /* Fill list with bogus entries, that look somewhat valid */
1430 SendMessage(g_listBox, LB_RESETCONTENT, 0, 0);
1431 SendMessage(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1432 SendMessage(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1433 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1434 for (i = 0; i < itemCount; i++) {
1435 memset(itemBuffer, 0, MAX_PATH);
1436 memset(pathBuffer, 0, MAX_PATH);
1437 memset(tempBuffer, 0, MAX_PATH);
1438 driveletter = '\0';
1439 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1440 res = SendMessage(g_listBox, LB_SETCURSEL, i, 0);
1441 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1442 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1443 /* Current item is a drive letter */
1444 SetLastError(0xdeadbeef);
1445 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1446 ok (GetLastError() == 0xdeadbeef,
1447 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1448 i, GetLastError());
1449 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1451 /* For drive letters, DlgDirSelectEx tacks on a colon */
1452 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1453 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1454 } else if (itemBuffer[0] == '[') {
1455 /* Current item is the parent directory */
1456 SetLastError(0xdeadbeef);
1457 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1458 ok (GetLastError() == 0xdeadbeef,
1459 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1460 i, GetLastError());
1461 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1463 /* For directories, DlgDirSelectEx tacks on a backslash */
1464 p = pathBuffer + strlen(pathBuffer);
1465 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1467 tempBuffer[0] = '[';
1468 strncpy(tempBuffer + 1, pathBuffer, strlen(pathBuffer) - 1);
1469 strcat(tempBuffer, "]");
1470 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1471 } else {
1472 /* Current item is a plain file */
1473 SetLastError(0xdeadbeef);
1474 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1475 ok (GetLastError() == 0xdeadbeef,
1476 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1477 i, GetLastError());
1478 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1480 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1481 * This affects for example, "Makefile", which gets reported as "Makefile."
1483 strcpy(tempBuffer, itemBuffer);
1484 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1485 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1489 /* Test behavior when loading folders from root with and without wildcard */
1490 strcpy(pathBuffer, "C:\\");
1491 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1492 ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1493 todo_wine ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1494 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1496 strcpy(pathBuffer, "C:\\*");
1497 res = DlgDirList(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 ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1500 "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1502 /* Try loading files from an invalid folder */
1503 SetLastError(0xdeadbeef);
1504 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1505 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1506 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1507 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1508 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1510 DestroyWindow(hWnd);
1513 static void test_set_count( void )
1515 HWND parent, listbox;
1516 LONG ret;
1517 RECT r;
1519 parent = create_parent();
1520 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1522 UpdateWindow( listbox );
1523 GetUpdateRect( listbox, &r, TRUE );
1524 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1526 ret = SendMessage( listbox, LB_SETCOUNT, 100, 0 );
1527 ok( ret == 0, "got %d\n", ret );
1528 ret = SendMessage( listbox, LB_GETCOUNT, 0, 0 );
1529 ok( ret == 100, "got %d\n", ret );
1531 GetUpdateRect( listbox, &r, TRUE );
1532 ok( !IsRectEmpty( &r ), "got empty rect\n");
1534 ValidateRect( listbox, NULL );
1535 GetUpdateRect( listbox, &r, TRUE );
1536 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1538 ret = SendMessage( listbox, LB_SETCOUNT, 99, 0 );
1539 ok( ret == 0, "got %d\n", ret );
1541 GetUpdateRect( listbox, &r, TRUE );
1542 ok( !IsRectEmpty( &r ), "got empty rect\n");
1544 DestroyWindow( listbox );
1545 DestroyWindow( parent );
1548 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1549 static int lb_getlistboxinfo;
1551 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1553 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1555 if (message == LB_GETLISTBOXINFO)
1556 lb_getlistboxinfo++;
1558 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1561 static void test_GetListBoxInfo(void)
1563 HWND listbox, parent;
1564 WNDPROC oldproc;
1565 DWORD ret;
1567 pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandle("user32"), "GetListBoxInfo");
1569 if (!pGetListBoxInfo)
1571 win_skip("GetListBoxInfo() not available\n");
1572 return;
1575 parent = create_parent();
1576 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1578 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1579 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1581 lb_getlistboxinfo = 0;
1582 ret = pGetListBoxInfo(listbox);
1583 ok(ret > 0, "got %d\n", ret);
1584 todo_wine
1585 ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
1587 DestroyWindow(listbox);
1588 DestroyWindow(parent);
1591 START_TEST(listbox)
1593 const struct listbox_test SS =
1594 /* {add_style} */
1595 {{0},
1596 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1597 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1598 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1599 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1600 /* {selected, anchor, caret, selcount}{TODO fields} */
1601 const struct listbox_test SS_NS =
1602 {{LBS_NOSEL},
1603 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1604 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1605 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1606 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1607 const struct listbox_test MS =
1608 {{LBS_MULTIPLESEL},
1609 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1610 { 1, 1, 1, 1}, {0,0,0,0},
1611 { 2, 1, 2, 1}, {0,0,0,0},
1612 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1613 const struct listbox_test MS_NS =
1614 {{LBS_MULTIPLESEL | LBS_NOSEL},
1615 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1616 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1617 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1618 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1619 const struct listbox_test ES =
1620 {{LBS_EXTENDEDSEL},
1621 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1622 { 1, 1, 1, 1}, {0,0,0,0},
1623 { 2, 2, 2, 1}, {0,0,0,0},
1624 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1625 const struct listbox_test ES_NS =
1626 {{LBS_EXTENDEDSEL | LBS_NOSEL},
1627 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1628 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1629 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1630 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1631 const struct listbox_test EMS =
1632 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
1633 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1634 { 1, 1, 1, 1}, {0,0,0,0},
1635 { 2, 2, 2, 1}, {0,0,0,0},
1636 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1637 const struct listbox_test EMS_NS =
1638 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
1639 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1640 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1641 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1642 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1644 trace (" Testing single selection...\n");
1645 check (SS);
1646 trace (" ... with NOSEL\n");
1647 check (SS_NS);
1648 trace (" Testing multiple selection...\n");
1649 check (MS);
1650 trace (" ... with NOSEL\n");
1651 check (MS_NS);
1652 trace (" Testing extended selection...\n");
1653 check (ES);
1654 trace (" ... with NOSEL\n");
1655 check (ES_NS);
1656 trace (" Testing extended and multiple selection...\n");
1657 check (EMS);
1658 trace (" ... with NOSEL\n");
1659 check (EMS_NS);
1661 check_item_height();
1662 test_ownerdraw();
1663 test_selection();
1664 test_listbox_height();
1665 test_itemfrompoint();
1666 test_listbox_item_data();
1667 test_listbox_LB_DIR();
1668 test_listbox_dlgdir();
1669 test_set_count();
1670 test_GetListBoxInfo();