push 97f44e0adb27fff75ba63d8fb97c65db9edfbe82
[wine/hacks.git] / dlls / user32 / tests / listbox.c
blob529e2c001e1e5136970947bc4b4fd91fcb551e04
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 HWND
48 create_listbox (DWORD add_style, HWND parent)
50 HWND handle;
51 int ctl_id=0;
52 if (parent)
53 ctl_id=1;
54 handle=CreateWindow ("LISTBOX", "TestList",
55 (LBS_STANDARD & ~LBS_SORT) | add_style,
56 0, 0, 100, 100,
57 parent, (HMENU)ctl_id, NULL, 0);
59 assert (handle);
60 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[0]);
61 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[1]);
62 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[2]);
63 SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[3]);
65 #ifdef VISIBLE
66 ShowWindow (handle, SW_SHOW);
67 #endif
68 REDRAW;
70 return handle;
73 struct listbox_prop {
74 DWORD add_style;
77 struct listbox_stat {
78 int selected, anchor, caret, selcount;
81 struct listbox_test {
82 struct listbox_prop prop;
83 struct listbox_stat init, init_todo;
84 struct listbox_stat click, click_todo;
85 struct listbox_stat step, step_todo;
86 struct listbox_stat sel, sel_todo;
89 static void
90 listbox_query (HWND handle, struct listbox_stat *results)
92 results->selected = SendMessage (handle, LB_GETCURSEL, 0, 0);
93 results->anchor = SendMessage (handle, LB_GETANCHORINDEX, 0, 0);
94 results->caret = SendMessage (handle, LB_GETCARETINDEX, 0, 0);
95 results->selcount = SendMessage (handle, LB_GETSELCOUNT, 0, 0);
98 static void
99 buttonpress (HWND handle, WORD x, WORD y)
101 LPARAM lp=x+(y<<16);
103 WAIT;
104 SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp);
105 SendMessage (handle, WM_LBUTTONUP , (WPARAM) 0 , lp);
106 REDRAW;
109 static void
110 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
112 LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
114 WAIT;
115 SendMessage (handle, WM_KEYDOWN, keycode, lp);
116 SendMessage (handle, WM_KEYUP , keycode, lp | 0xc000000);
117 REDRAW;
120 #define listbox_field_ok(t, s, f, got) \
121 ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
122 ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
123 t.s.f, got.f)
125 #define listbox_todo_field_ok(t, s, f, got) \
126 if (t.s##_todo.f) todo_wine { listbox_field_ok(t, s, f, got); } \
127 else listbox_field_ok(t, s, f, got)
129 #define listbox_ok(t, s, got) \
130 listbox_todo_field_ok(t, s, selected, got); \
131 listbox_todo_field_ok(t, s, anchor, got); \
132 listbox_todo_field_ok(t, s, caret, got); \
133 listbox_todo_field_ok(t, s, selcount, got)
135 static void
136 check (const struct listbox_test test)
138 struct listbox_stat answer;
139 HWND hLB=create_listbox (test.prop.add_style, 0);
140 RECT second_item;
141 int i;
142 int res;
144 listbox_query (hLB, &answer);
145 listbox_ok (test, init, answer);
147 SendMessage (hLB, LB_GETITEMRECT, (WPARAM) 1, (LPARAM) &second_item);
148 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
150 listbox_query (hLB, &answer);
151 listbox_ok (test, click, answer);
153 keypress (hLB, VK_DOWN, 0x50, TRUE);
155 listbox_query (hLB, &answer);
156 listbox_ok (test, step, answer);
158 DestroyWindow (hLB);
159 hLB=create_listbox (test.prop.add_style, 0);
161 SendMessage (hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
162 listbox_query (hLB, &answer);
163 listbox_ok (test, sel, answer);
165 for (i=0;i<4;i++) {
166 DWORD size = SendMessage (hLB, LB_GETTEXTLEN, i, 0);
167 CHAR *txt;
168 WCHAR *txtw;
169 int resA, resW;
171 txt = HeapAlloc (GetProcessHeap(), 0, size+1);
172 memset(txt, 0, size+1);
173 resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
174 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
176 txtw = HeapAlloc (GetProcessHeap(), 0, 2*size+2);
177 memset(txtw, 0, 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), "client rect of the listbox should be equal to the clip box\n");
259 trace("rcItem (%d,%d-%d,%d)\n", dis->rcItem.left, dis->rcItem.top,
260 dis->rcItem.right, dis->rcItem.bottom);
261 SendMessage(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
262 trace("item rect (%d,%d-%d,%d)\n", rc_item.left, rc_item.top, rc_item.right, rc_item.bottom);
263 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
265 break;
268 default:
269 break;
272 return DefWindowProc(hwnd, msg, wparam, lparam);
275 static void test_ownerdraw(void)
277 WNDCLASS cls;
278 HWND parent, hLB;
279 INT ret;
280 RECT rc;
282 cls.style = 0;
283 cls.lpfnWndProc = main_window_proc;
284 cls.cbClsExtra = 0;
285 cls.cbWndExtra = 0;
286 cls.hInstance = GetModuleHandle(0);
287 cls.hIcon = 0;
288 cls.hCursor = LoadCursor(0, (LPSTR)IDC_ARROW);
289 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
290 cls.lpszMenuName = NULL;
291 cls.lpszClassName = "main_window_class";
292 assert(RegisterClass(&cls));
294 parent = CreateWindowEx(0, "main_window_class", NULL,
295 WS_POPUP | WS_VISIBLE,
296 100, 100, 400, 400,
297 GetDesktopWindow(), 0,
298 GetModuleHandle(0), NULL);
299 assert(parent);
301 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
302 assert(hLB);
304 UpdateWindow(hLB);
306 /* make height short enough */
307 SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
308 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
309 SWP_NOZORDER | SWP_NOMOVE);
311 /* make 0 item invisible */
312 SendMessage(hLB, LB_SETTOPINDEX, 1, 0);
313 ret = SendMessage(hLB, LB_GETTOPINDEX, 0, 0);
314 ok(ret == 1, "wrong top index %d\n", ret);
316 SendMessage(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
317 trace("item 0 rect (%d,%d-%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
318 ok(!IsRectEmpty(&rc), "empty item rect\n");
319 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
321 DestroyWindow(hLB);
322 DestroyWindow(parent);
325 #define listbox_test_query(exp, got) \
326 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
327 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
328 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
329 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
331 static void test_selection(void)
333 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
334 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
335 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
336 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
337 HWND hLB;
338 struct listbox_stat answer;
339 INT ret;
341 trace("testing LB_SELITEMRANGE\n");
343 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
344 assert(hLB);
346 listbox_query(hLB, &answer);
347 listbox_test_query(test_nosel, answer);
349 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
350 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
351 listbox_query(hLB, &answer);
352 listbox_test_query(test_1, answer);
354 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
355 listbox_query(hLB, &answer);
356 listbox_test_query(test_nosel, answer);
358 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
359 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
360 listbox_query(hLB, &answer);
361 listbox_test_query(test_3, answer);
363 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
364 listbox_query(hLB, &answer);
365 listbox_test_query(test_nosel, answer);
367 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
368 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
369 listbox_query(hLB, &answer);
370 listbox_test_query(test_nosel, answer);
372 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
373 listbox_query(hLB, &answer);
374 listbox_test_query(test_nosel, answer);
376 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
377 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
378 listbox_query(hLB, &answer);
379 listbox_test_query(test_1, answer);
381 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
382 listbox_query(hLB, &answer);
383 listbox_test_query(test_nosel, answer);
385 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
386 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
387 listbox_query(hLB, &answer);
388 listbox_test_query(test_nosel, answer);
390 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
391 listbox_query(hLB, &answer);
392 listbox_test_query(test_nosel, answer);
394 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
395 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
396 listbox_query(hLB, &answer);
397 listbox_test_query(test_2, answer);
399 SendMessage(hLB, LB_SETSEL, FALSE, (LPARAM)-1);
400 listbox_query(hLB, &answer);
401 listbox_test_query(test_nosel, answer);
403 ret = SendMessage(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
404 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
405 listbox_query(hLB, &answer);
406 listbox_test_query(test_2, answer);
408 DestroyWindow(hLB);
411 static void test_listbox_height(void)
413 HWND hList;
414 int r, id;
416 hList = CreateWindow( "ListBox", "list test", 0,
417 1, 1, 600, 100, NULL, NULL, NULL, NULL );
418 ok( hList != NULL, "failed to create listbox\n");
420 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
421 ok( id == 0, "item id wrong\n");
423 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
424 ok( r == 0, "send message failed\n");
426 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
427 ok( r == 20, "height wrong\n");
429 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
430 ok( r == -1, "send message failed\n");
432 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
433 ok( r == 20, "height wrong\n");
435 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
436 ok( r == -1, "send message failed\n");
438 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
439 ok( r == 20, "height wrong\n");
441 r = SendMessage( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
442 ok( r == 0, "send message failed\n");
444 r = SendMessage(hList, LB_GETITEMHEIGHT, 0, 0 );
445 ok( r == 0xff, "height wrong\n");
447 DestroyWindow( hList );
450 static void test_itemfrompoint(void)
452 /* WS_POPUP is required in order to have a more accurate size calculation (
453 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
454 behavior of partially-displayed item.
456 HWND hList = CreateWindow( "ListBox", "list test",
457 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
458 1, 1, 600, 100, NULL, NULL, NULL, NULL );
459 LONG r, id;
460 RECT rc;
462 /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000 */
463 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
464 ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
466 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
467 ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
469 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
470 ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
472 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
473 ok( id == 0, "item id wrong\n");
474 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
475 ok( id == 1, "item id wrong\n");
477 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
478 ok( r == 0x1, "ret %x\n", r );
480 r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
481 ok( r == 0x10001, "ret %x\n", r );
483 /* Resize control so that below assertions about sizes are valid */
484 r = SendMessage( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
485 ok( r == 1, "ret %x\n", r);
486 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
487 ok( r != 0, "ret %x\n", r);
489 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
490 ok( id == 2, "item id wrong\n");
491 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
492 ok( id == 3, "item id wrong\n");
493 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
494 ok( id == 4, "item id wrong\n");
495 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
496 ok( id == 5, "item id wrong\n");
497 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
498 ok( id == 6, "item id wrong\n");
499 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
500 ok( id == 7, "item id wrong\n");
502 /* Set the listbox up so that id 1 is at the top, this leaves 5
503 partially visible at the bottom and 6, 7 are invisible */
505 SendMessage( hList, LB_SETTOPINDEX, 1, 0);
506 r = SendMessage( hList, LB_GETTOPINDEX, 0, 0);
507 ok( r == 1, "top %d\n", r);
509 r = SendMessage( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
510 ok( r == 1, "ret %x\n", r);
511 r = SendMessage( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
512 ok( r == 0, "ret %x\n", r);
514 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
515 ok( r == 1, "ret %x\n", r);
517 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
518 ok( r == 0x10001, "ret %x\n", r );
520 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
521 ok( r == 0x10001, "ret %x\n", r );
523 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
524 ok( r == 0x10005, "item %x\n", r );
526 r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
527 ok( r == 0x10005, "item %x\n", r );
529 DestroyWindow( hList );
532 static void test_listbox_item_data(void)
534 HWND hList;
535 int r, id;
537 hList = CreateWindow( "ListBox", "list test", 0,
538 1, 1, 600, 100, NULL, NULL, NULL, NULL );
539 ok( hList != NULL, "failed to create listbox\n");
541 id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
542 ok( id == 0, "item id wrong\n");
544 r = SendMessage( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
545 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
547 r = SendMessage( hList, LB_GETITEMDATA, 0, 0);
548 ok( r == 20, "get item data failed\n");
550 DestroyWindow( hList );
553 static void test_listbox_LB_DIR()
555 HWND hList;
556 int res, itemCount;
557 int itemCount_justFiles;
558 int itemCount_justDrives;
559 int itemCount_allFiles;
560 int i;
561 char pathBuffer[MAX_PATH];
562 char * p;
563 char driveletter;
565 /* NOTE: for this test to succeed, there must be no subdirectories
566 under the current directory. In addition, there must be at least
567 one file that fits the wildcard w*.c . Normally, the test
568 directory itself satisfies both conditions.
570 hList = CreateWindow( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
571 1, 1, 600, 100, NULL, NULL, NULL, NULL );
572 assert(hList);
574 /* Test for standard usage */
576 /* This should list all the files in the test directory. */
577 strcpy(pathBuffer, "*");
578 SendMessage(hList, LB_RESETCONTENT, 0, 0);
579 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
580 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
582 /* There should be some content in the listbox */
583 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
584 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
585 itemCount_allFiles = itemCount;
586 ok(res + 1 == itemCount,
587 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
588 itemCount - 1, res);
591 /* This should list all the w*.c files in the test directory
592 * As of this writing, this includes win.c, winstation.c, wsprintf.c
594 strcpy(pathBuffer, "w*.c");
595 SendMessage(hList, LB_RESETCONTENT, 0, 0);
596 res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
597 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
599 /* Path specification does NOT converted to uppercase */
600 ok (!strcmp(pathBuffer, "w*.c"),
601 "expected no change to pathBuffer, got %s\n", pathBuffer);
603 /* There should be some content in the listbox */
604 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
605 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
606 itemCount_justFiles = itemCount;
607 ok(res + 1 == itemCount,
608 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
609 itemCount - 1, res);
611 /* Every single item in the control should start with a w and end in .c */
612 for (i = 0; i < itemCount; i++) {
613 memset(pathBuffer, 0, MAX_PATH);
614 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
615 p = pathBuffer + strlen(pathBuffer);
616 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
617 (*(p-1) == 'c' || *(p-1) == 'C') &&
618 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
621 /* Test DDL_DIRECTORY */
622 strcpy(pathBuffer, "*");
623 SendMessage(hList, LB_RESETCONTENT, 0, 0);
624 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
625 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
627 /* There should be some content in the listbox.
628 * All files plus "[..]"
630 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
631 ok (itemCount == itemCount_allFiles + 1,
632 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected %d\n",
633 itemCount, itemCount_allFiles + 1);
634 ok(res + 1 == itemCount,
635 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
636 itemCount - 1, res);
639 /* Test DDL_DIRECTORY */
640 strcpy(pathBuffer, "w*.c");
641 SendMessage(hList, LB_RESETCONTENT, 0, 0);
642 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
643 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
645 /* There should be some content in the listbox. Since the parent directory does not
646 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
648 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
649 ok (itemCount == itemCount_justFiles,
650 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
651 itemCount, itemCount_justFiles);
652 ok(res + 1 == itemCount,
653 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
654 itemCount - 1, res);
656 /* Every single item in the control should start with a w and end in .c. */
657 for (i = 0; i < itemCount; i++) {
658 memset(pathBuffer, 0, MAX_PATH);
659 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
660 p = pathBuffer + strlen(pathBuffer);
662 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
663 (*(p-1) == 'c' || *(p-1) == 'C') &&
664 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
668 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
669 strcpy(pathBuffer, "*");
670 SendMessage(hList, LB_RESETCONTENT, 0, 0);
671 res = SendMessage(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
672 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
674 /* There should be some content in the listbox. In particular, there should
675 * be at least one element before, since the string "[-c-]" should
676 * have been added. Depending on the user setting, more drives might have
677 * been added.
679 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
680 ok (itemCount >= 1,
681 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
682 itemCount, 1);
683 itemCount_justDrives = itemCount;
684 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
686 /* Every single item in the control should fit the format [-c-] */
687 for (i = 0; i < itemCount; i++) {
688 memset(pathBuffer, 0, MAX_PATH);
689 driveletter = '\0';
690 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
691 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
692 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
693 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
694 if (!(driveletter >= 'a' && driveletter <= 'z')) {
695 /* Correct after invalid entry is found */
696 trace("removing count of invalid entry %s\n", pathBuffer);
697 itemCount_justDrives--;
702 trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
703 itemCount_justFiles, itemCount_justDrives);
705 /* Test DDL_DRIVES. */
706 strcpy(pathBuffer, "*");
707 SendMessage(hList, LB_RESETCONTENT, 0, 0);
708 res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
709 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
711 /* There should be some content in the listbox. In particular, there should
712 * be at least one element before, since the string "[-c-]" should
713 * have been added. Depending on the user setting, more drives might have
714 * been added.
716 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
717 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
718 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
719 itemCount, itemCount_justDrives + itemCount_allFiles);
720 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
723 /* Test DDL_DRIVES. */
724 strcpy(pathBuffer, "w*.c");
725 SendMessage(hList, LB_RESETCONTENT, 0, 0);
726 res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
727 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
729 /* There should be some content in the listbox. In particular, there should
730 * be at least one element before, since the string "[-c-]" should
731 * have been added. Depending on the user setting, more drives might have
732 * been added.
734 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
735 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
736 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
737 itemCount, itemCount_justDrives + itemCount_justFiles);
738 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
740 /* Every single item in the control should fit the format [-c-], or w*.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 p = pathBuffer + strlen(pathBuffer);
746 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
747 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
748 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
749 } else {
751 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
752 (*(p-1) == 'c' || *(p-1) == 'C') &&
753 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
758 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
759 strcpy(pathBuffer, "*");
760 SendMessage(hList, LB_RESETCONTENT, 0, 0);
761 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
762 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
764 /* There should be some content in the listbox. In particular, there should
765 * be exactly the number of plain files, plus the number of mapped drives.
767 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
768 ok (itemCount == itemCount_allFiles + itemCount_justDrives + 1,
769 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
770 itemCount, itemCount_allFiles + itemCount_justDrives + 1);
771 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
773 /* Every single item in the control should start with a w and end in .c,
774 * except for the "[..]" string, which should appear exactly as it is,
775 * and the mapped drives in the format "[-X-]".
777 for (i = 0; i < itemCount; i++) {
778 memset(pathBuffer, 0, MAX_PATH);
779 driveletter = '\0';
780 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
781 p = pathBuffer + strlen(pathBuffer);
782 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
783 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
788 /* Test DDL_DIRECTORY|DDL_DRIVES. */
789 strcpy(pathBuffer, "w*.c");
790 SendMessage(hList, LB_RESETCONTENT, 0, 0);
791 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
792 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
794 /* There should be some content in the listbox. In particular, there should
795 * be exactly the number of plain files, plus the number of mapped drives.
797 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
798 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
799 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
800 itemCount, itemCount_justFiles + itemCount_justDrives);
801 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
803 /* Every single item in the control should start with a w and end in .c,
804 * except the mapped drives in the format "[-X-]". The "[..]" directory
805 * should not appear.
807 for (i = 0; i < itemCount; i++) {
808 memset(pathBuffer, 0, MAX_PATH);
809 driveletter = '\0';
810 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
811 p = pathBuffer + strlen(pathBuffer);
812 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
813 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
814 } else {
816 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
817 (*(p-1) == 'c' || *(p-1) == 'C') &&
818 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
822 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
823 strcpy(pathBuffer, "*");
824 SendMessage(hList, LB_RESETCONTENT, 0, 0);
825 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
826 ok (res == 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
828 /* There should be exactly one element: "[..]" */
829 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
830 ok (itemCount == 1,
831 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
832 itemCount, 1);
833 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
835 memset(pathBuffer, 0, MAX_PATH);
836 SendMessage(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
837 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
839 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
840 strcpy(pathBuffer, "w*.c");
841 SendMessage(hList, LB_RESETCONTENT, 0, 0);
842 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
843 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
845 /* There should be no elements, since "[..]" does not fit w*.c */
846 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
847 ok (itemCount == 0,
848 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
849 itemCount, 0);
851 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
852 strcpy(pathBuffer, "*");
853 SendMessage(hList, LB_RESETCONTENT, 0, 0);
854 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
855 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
857 /* There should be no plain files on the listbox */
858 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
859 ok (itemCount == itemCount_justDrives + 1,
860 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
861 itemCount, itemCount_justDrives + 1);
862 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
864 for (i = 0; i < itemCount; i++) {
865 memset(pathBuffer, 0, MAX_PATH);
866 driveletter = '\0';
867 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
868 p = pathBuffer + strlen(pathBuffer);
869 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
870 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
871 } else {
872 ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer);
877 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
878 strcpy(pathBuffer, "w*.c");
879 SendMessage(hList, LB_RESETCONTENT, 0, 0);
880 res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
881 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
883 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
884 itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
885 ok (itemCount == itemCount_justDrives,
886 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
887 itemCount, itemCount_justDrives);
888 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
890 for (i = 0; i < itemCount; i++) {
891 memset(pathBuffer, 0, MAX_PATH);
892 driveletter = '\0';
893 SendMessage(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
894 p = pathBuffer + strlen(pathBuffer);
895 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
896 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
898 DestroyWindow(hList);
901 HWND g_listBox;
902 HWND g_label;
904 #define ID_TEST_LABEL 1001
905 #define ID_TEST_LISTBOX 1002
907 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCT lpcs)
909 g_label = CreateWindow(
910 "Static",
911 "Contents of static control before DlgDirList.",
912 WS_CHILD | WS_VISIBLE,
913 10, 10, 512, 32,
914 hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
915 if (!g_label) return FALSE;
916 g_listBox = CreateWindow(
917 "ListBox",
918 "DlgDirList test",
919 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
920 10, 60, 256, 256,
921 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
922 if (!g_listBox) return FALSE;
924 return TRUE;
927 static LRESULT CALLBACK listbox_container_window_procA (
928 HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
930 LRESULT result = 0;
932 switch (uiMsg) {
933 case WM_DESTROY:
934 PostQuitMessage(0);
935 break;
936 case WM_CREATE:
937 result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
938 ? 0 : (LRESULT)-1;
939 break;
940 default:
941 result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
942 break;
944 return result;
947 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
949 WNDCLASSA cls;
951 cls.style = 0;
952 cls.cbClsExtra = 0;
953 cls.cbWndExtra = 0;
954 cls.hInstance = hInst;
955 cls.hIcon = NULL;
956 cls.hCursor = LoadCursorA (NULL, IDC_ARROW);
957 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
958 cls.lpszMenuName = NULL;
959 cls.lpfnWndProc = listbox_container_window_procA;
960 cls.lpszClassName = "ListboxContainerClass";
961 if (!RegisterClassA (&cls)) return FALSE;
963 return TRUE;
966 static void test_listbox_dlgdir(void)
968 HINSTANCE hInst;
969 HWND hWnd;
970 int res, itemCount;
971 int itemCount_justFiles;
972 int itemCount_justDrives;
973 int i;
974 char pathBuffer[MAX_PATH];
975 char itemBuffer[MAX_PATH];
976 char tempBuffer[MAX_PATH];
977 char * p;
978 char driveletter;
980 /* NOTE: for this test to succeed, there must be no subdirectories
981 under the current directory. In addition, there must be at least
982 one file that fits the wildcard w*.c . Normally, the test
983 directory itself satisfies both conditions.
986 hInst = GetModuleHandleA(0);
987 if (!RegisterListboxWindowClass(hInst)) assert(0);
988 hWnd = CreateWindow("ListboxContainerClass", "ListboxContainerClass",
989 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
990 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
991 NULL, NULL, hInst, 0);
992 assert(hWnd);
994 /* Test for standard usage */
996 /* The following should be overwritten by the directory path */
997 SendMessage(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
999 /* This should list all the w*.c files in the test directory
1000 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1002 strcpy(pathBuffer, "w*.c");
1003 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1004 ok (res != 0, "DlgDirList(*.c, 0) failed - 0x%08x\n", GetLastError());
1006 /* Path specification gets converted to uppercase */
1007 ok (!strcmp(pathBuffer, "W*.C"),
1008 "expected conversion to uppercase, got %s\n", pathBuffer);
1010 /* Loaded path should have overwritten the label text */
1011 SendMessage(g_label, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)pathBuffer);
1012 trace("Static control after DlgDirList: %s\n", pathBuffer);
1013 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1015 /* There should be some content in the listbox */
1016 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1017 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1018 itemCount_justFiles = itemCount;
1020 /* Every single item in the control should start with a w and end in .c */
1021 for (i = 0; i < itemCount; i++) {
1022 memset(pathBuffer, 0, MAX_PATH);
1023 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1024 p = pathBuffer + strlen(pathBuffer);
1025 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1026 (*(p-1) == 'c' || *(p-1) == 'C') &&
1027 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1030 /* Test DDL_DIRECTORY */
1031 strcpy(pathBuffer, "w*.c");
1032 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1033 DDL_DIRECTORY);
1034 ok (res != 0, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1036 /* There should be some content in the listbox. In particular, there should
1037 * be exactly one more element than before, since the string "[..]" should
1038 * have been added.
1040 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1041 ok (itemCount == itemCount_justFiles + 1,
1042 "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected %d\n",
1043 itemCount, itemCount_justFiles + 1);
1045 /* Every single item in the control should start with a w and end in .c,
1046 * except for the "[..]" string, which should appear exactly as it is.
1048 for (i = 0; i < itemCount; i++) {
1049 memset(pathBuffer, 0, MAX_PATH);
1050 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1051 p = pathBuffer + strlen(pathBuffer);
1052 ok( !strcmp(pathBuffer, "[..]") ||
1053 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1054 (*(p-1) == 'c' || *(p-1) == 'C') &&
1055 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1058 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1059 strcpy(pathBuffer, "w*.c");
1060 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1061 DDL_DRIVES);
1062 ok (res != 0, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1064 /* There should be some content in the listbox. In particular, there should
1065 * be at least one element before, since the string "[-c-]" should
1066 * have been added. Depending on the user setting, more drives might have
1067 * been added.
1069 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1070 ok (itemCount >= 1,
1071 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1072 itemCount, 1);
1073 itemCount_justDrives = itemCount;
1075 /* Every single item in the control should fit the format [-c-] */
1076 for (i = 0; i < itemCount; i++) {
1077 memset(pathBuffer, 0, MAX_PATH);
1078 driveletter = '\0';
1079 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1080 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1081 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1082 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1083 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1084 /* Correct after invalid entry is found */
1085 trace("removing count of invalid entry %s\n", pathBuffer);
1086 itemCount_justDrives--;
1090 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1091 strcpy(pathBuffer, "w*.c");
1092 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1093 DDL_DIRECTORY|DDL_DRIVES);
1094 ok (res != 0, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1096 /* There should be some content in the listbox. In particular, there should
1097 * be exactly the number of plain files, plus the number of mapped drives,
1098 * plus one "[..]"
1100 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1101 ok (itemCount == itemCount_justFiles + itemCount_justDrives + 1,
1102 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1103 itemCount, itemCount_justFiles + itemCount_justDrives + 1);
1105 /* Every single item in the control should start with a w and end in .c,
1106 * except for the "[..]" string, which should appear exactly as it is,
1107 * and the mapped drives in the format "[-X-]".
1109 for (i = 0; i < itemCount; i++) {
1110 memset(pathBuffer, 0, MAX_PATH);
1111 driveletter = '\0';
1112 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1113 p = pathBuffer + strlen(pathBuffer);
1114 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1115 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1116 } else {
1117 ok( !strcmp(pathBuffer, "[..]") ||
1118 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1119 (*(p-1) == 'c' || *(p-1) == 'C') &&
1120 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1124 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1125 strcpy(pathBuffer, "w*.c");
1126 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1127 DDL_DIRECTORY|DDL_EXCLUSIVE);
1128 ok (res != 0, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1130 /* There should be exactly one element: "[..]" */
1131 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1132 ok (itemCount == 1,
1133 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1134 itemCount, 1);
1136 memset(pathBuffer, 0, MAX_PATH);
1137 SendMessage(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1138 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1140 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1141 strcpy(pathBuffer, "w*.c");
1142 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1143 DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1144 ok (res != 0, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1146 /* There should be no plain files on the listbox */
1147 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1148 ok (itemCount == itemCount_justDrives + 1,
1149 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1150 itemCount, itemCount_justDrives + 1);
1152 for (i = 0; i < itemCount; i++) {
1153 memset(pathBuffer, 0, MAX_PATH);
1154 driveletter = '\0';
1155 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1156 p = pathBuffer + strlen(pathBuffer);
1157 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1158 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1159 } else {
1160 ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer);
1164 /* Now test DlgDirSelectEx() in normal operation */
1165 /* Fill with everything - drives, directory and all plain files. */
1166 strcpy(pathBuffer, "*");
1167 res = DlgDirList(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1168 DDL_DIRECTORY|DDL_DRIVES);
1169 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1171 SendMessage(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1172 memset(pathBuffer, 0, MAX_PATH);
1173 SetLastError(0xdeadbeef);
1174 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1175 ok (GetLastError() == 0xdeadbeef,
1176 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1177 GetLastError());
1178 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1179 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1181 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1183 /* Test proper drive/dir/file recognition */
1184 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1185 for (i = 0; i < itemCount; i++) {
1186 memset(itemBuffer, 0, MAX_PATH);
1187 memset(pathBuffer, 0, MAX_PATH);
1188 memset(tempBuffer, 0, MAX_PATH);
1189 driveletter = '\0';
1190 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1191 res = SendMessage(g_listBox, LB_SETCURSEL, i, 0);
1192 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1193 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1194 /* Current item is a drive letter */
1195 SetLastError(0xdeadbeef);
1196 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1197 ok (GetLastError() == 0xdeadbeef,
1198 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1199 i, GetLastError());
1200 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1202 /* For drive letters, DlgDirSelectEx tacks on a colon */
1203 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1204 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1205 } else if (itemBuffer[0] == '[') {
1206 /* Current item is the parent directory */
1207 SetLastError(0xdeadbeef);
1208 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1209 ok (GetLastError() == 0xdeadbeef,
1210 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1211 i, GetLastError());
1212 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1214 /* For directories, DlgDirSelectEx tacks on a backslash */
1215 p = pathBuffer + strlen(pathBuffer);
1216 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1218 tempBuffer[0] = '[';
1219 strncpy(tempBuffer + 1, pathBuffer, strlen(pathBuffer) - 1);
1220 strcat(tempBuffer, "]");
1221 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1222 } else {
1223 /* Current item is a plain file */
1224 SetLastError(0xdeadbeef);
1225 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1226 ok (GetLastError() == 0xdeadbeef,
1227 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1228 i, GetLastError());
1229 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1231 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1232 * for example, "Makefile", which gets reported as "Makefile."
1234 strcpy(tempBuffer, itemBuffer);
1235 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1236 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1240 /* Now test DlgDirSelectEx() in abnormal operation */
1241 /* Fill list with bogus entries, that look somewhat valid */
1242 SendMessage(g_listBox, LB_RESETCONTENT, 0, 0);
1243 SendMessage(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1244 SendMessage(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1245 itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
1246 for (i = 0; i < itemCount; i++) {
1247 memset(itemBuffer, 0, MAX_PATH);
1248 memset(pathBuffer, 0, MAX_PATH);
1249 memset(tempBuffer, 0, MAX_PATH);
1250 driveletter = '\0';
1251 SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1252 res = SendMessage(g_listBox, LB_SETCURSEL, i, 0);
1253 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1254 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1255 /* Current item is a drive letter */
1256 SetLastError(0xdeadbeef);
1257 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1258 ok (GetLastError() == 0xdeadbeef,
1259 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1260 i, GetLastError());
1261 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1263 /* For drive letters, DlgDirSelectEx tacks on a colon */
1264 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1265 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1266 } else if (itemBuffer[0] == '[') {
1267 /* Current item is the parent directory */
1268 SetLastError(0xdeadbeef);
1269 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1270 ok (GetLastError() == 0xdeadbeef,
1271 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1272 i, GetLastError());
1273 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1275 /* For directories, DlgDirSelectEx tacks on a backslash */
1276 p = pathBuffer + strlen(pathBuffer);
1277 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1279 tempBuffer[0] = '[';
1280 strncpy(tempBuffer + 1, pathBuffer, strlen(pathBuffer) - 1);
1281 strcat(tempBuffer, "]");
1282 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1283 } else {
1284 /* Current item is a plain file */
1285 SetLastError(0xdeadbeef);
1286 res = DlgDirSelectEx(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1287 ok (GetLastError() == 0xdeadbeef,
1288 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1289 i, GetLastError());
1290 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1292 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1293 * This affects for example, "Makefile", which gets reported as "Makefile."
1295 strcpy(tempBuffer, itemBuffer);
1296 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1297 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1300 DestroyWindow(hWnd);
1303 START_TEST(listbox)
1305 const struct listbox_test SS =
1306 /* {add_style} */
1307 {{0},
1308 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1309 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1310 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1311 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1312 /* {selected, anchor, caret, selcount}{TODO fields} */
1313 const struct listbox_test SS_NS =
1314 {{LBS_NOSEL},
1315 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1316 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1317 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1318 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1319 const struct listbox_test MS =
1320 {{LBS_MULTIPLESEL},
1321 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1322 { 1, 1, 1, 1}, {0,0,0,0},
1323 { 2, 1, 2, 1}, {0,0,0,0},
1324 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1325 const struct listbox_test MS_NS =
1326 {{LBS_MULTIPLESEL | LBS_NOSEL},
1327 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1328 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1329 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1330 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1331 const struct listbox_test ES =
1332 {{LBS_EXTENDEDSEL},
1333 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1334 { 1, 1, 1, 1}, {0,0,0,0},
1335 { 2, 2, 2, 1}, {0,0,0,0},
1336 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1337 const struct listbox_test ES_NS =
1338 {{LBS_EXTENDEDSEL | LBS_NOSEL},
1339 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1340 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1341 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1342 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1343 const struct listbox_test EMS =
1344 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
1345 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1346 { 1, 1, 1, 1}, {0,0,0,0},
1347 { 2, 2, 2, 1}, {0,0,0,0},
1348 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1349 const struct listbox_test EMS_NS =
1350 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
1351 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1352 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1353 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1354 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1356 trace (" Testing single selection...\n");
1357 check (SS);
1358 trace (" ... with NOSEL\n");
1359 check (SS_NS);
1360 trace (" Testing multiple selection...\n");
1361 check (MS);
1362 trace (" ... with NOSEL\n");
1363 check (MS_NS);
1364 trace (" Testing extended selection...\n");
1365 check (ES);
1366 trace (" ... with NOSEL\n");
1367 check (ES_NS);
1368 trace (" Testing extended and multiple selection...\n");
1369 check (EMS);
1370 trace (" ... with NOSEL\n");
1371 check (EMS_NS);
1373 check_item_height();
1374 test_ownerdraw();
1375 test_selection();
1376 test_listbox_height();
1377 test_itemfrompoint();
1378 test_listbox_item_data();
1379 test_listbox_LB_DIR();
1380 test_listbox_dlgdir();