1 /* Unit test suite for list boxes.
2  *
3  * Copyright 2003 Ferenc Wagner
4  *
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.
9  *
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.
14  *
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
18  */
19 
20 #include "precomp.h"
21 
22 #ifdef VISIBLE
23 #define WAIT Sleep (1000)
24 #define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW)
25 #else
26 #define WAIT
27 #define REDRAW
28 #endif
29 
30 static const char * const strings[4] = {
31   "First added",
32   "Second added",
33   "Third added",
34   "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."
35 };
36 
37 static const char BAD_EXTENSION[] = "*.badtxt";
38 
39 static HWND
40 create_listbox (DWORD add_style, HWND parent)
41 {
42   HWND handle;
43   INT_PTR ctl_id=0;
44   if (parent)
45     ctl_id=1;
46   handle=CreateWindowA("LISTBOX", "TestList",
47                             (LBS_STANDARD & ~LBS_SORT) | add_style,
48                             0, 0, 100, 100,
49                             parent, (HMENU)ctl_id, NULL, 0);
50 
51   assert (handle);
52   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
53   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
54   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
55   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
56 
57 #ifdef VISIBLE
58   ShowWindow (handle, SW_SHOW);
59 #endif
60   REDRAW;
61 
62   return handle;
63 }
64 
65 struct listbox_prop {
66   DWORD add_style;
67 };
68 
69 struct listbox_stat {
70   int selected, anchor, caret, selcount;
71 };
72 
73 struct listbox_test {
74   struct listbox_prop prop;
75   struct listbox_stat  init,  init_todo;
76   struct listbox_stat click, click_todo;
77   struct listbox_stat  step,  step_todo;
78   struct listbox_stat   sel,   sel_todo;
79 };
80 
81 static void
82 listbox_query (HWND handle, struct listbox_stat *results)
83 {
84   results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
85   results->anchor   = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
86   results->caret    = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
87   results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
88 }
89 
90 static void
91 buttonpress (HWND handle, WORD x, WORD y)
92 {
93   LPARAM lp=x+(y<<16);
94 
95   WAIT;
96   SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
97   SendMessageA(handle, WM_LBUTTONUP, 0, lp);
98   REDRAW;
99 }
100 
101 static void
102 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
103 {
104   LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
105 
106   WAIT;
107   SendMessageA(handle, WM_KEYDOWN, keycode, lp);
108   SendMessageA(handle, WM_KEYUP  , keycode, lp | 0xc000000);
109   REDRAW;
110 }
111 
112 #define listbox_field_ok(t, s, f, got) \
113   ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
114       ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
115       t.s.f, got.f)
116 
117 #define listbox_todo_field_ok(t, s, f, got) \
118   todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
119 
120 #define listbox_ok(t, s, got) \
121   listbox_todo_field_ok(t, s, selected, got); \
122   listbox_todo_field_ok(t, s, anchor, got); \
123   listbox_todo_field_ok(t, s, caret, got); \
124   listbox_todo_field_ok(t, s, selcount, got)
125 
126 static void
127 check (const struct listbox_test test)
128 {
129   struct listbox_stat answer;
130   HWND hLB=create_listbox (test.prop.add_style, 0);
131   RECT second_item;
132   int i;
133   int res;
134 
135   listbox_query (hLB, &answer);
136   listbox_ok (test, init, answer);
137 
138   SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
139   buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
140 
141   listbox_query (hLB, &answer);
142   listbox_ok (test, click, answer);
143 
144   keypress (hLB, VK_DOWN, 0x50, TRUE);
145 
146   listbox_query (hLB, &answer);
147   listbox_ok (test, step, answer);
148 
149   DestroyWindow (hLB);
150   hLB=create_listbox (test.prop.add_style, 0);
151 
152   SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
153   listbox_query (hLB, &answer);
154   listbox_ok (test, sel, answer);
155 
156   for (i=0;i<4;i++) {
157 	DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
158 	CHAR *txt;
159 	WCHAR *txtw;
160 	int resA, resW;
161 
162 	txt = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, size+1);
163 	resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
164         ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
165 
166 	txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2);
167 	resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
168 	if (resA != resW) {
169             trace("SendMessageW(LB_GETTEXT) not supported on this platform (resA=%d resW=%d), skipping...\n",
170                 resA, resW);
171 	} else {
172 	    WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
173             ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
174 	}
175 
176 	HeapFree (GetProcessHeap(), 0, txtw);
177 	HeapFree (GetProcessHeap(), 0, txt);
178   }
179 
180   /* Confirm the count of items, and that an invalid delete does not remove anything */
181   res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
182   ok((res==4), "Expected 4 items, got %d\n", res);
183   res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
184   ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
185   res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
186   ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
187   res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
188   ok((res==4), "Expected 4 items, got %d\n", res);
189 
190   WAIT;
191   DestroyWindow (hLB);
192 }
193 
194 static void check_item_height(void)
195 {
196     HWND hLB;
197     HDC hdc;
198     HFONT font;
199     TEXTMETRICA tm;
200     INT itemHeight;
201 
202     hLB = create_listbox (0, 0);
203     ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
204     ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
205     ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
206     ReleaseDC( hLB, hdc);
207 
208     ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
209 
210     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
211     ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
212 
213     DestroyWindow (hLB);
214 
215     hLB = CreateWindowA("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE,
216                          0, 0, 100, 100, NULL, NULL, NULL, 0);
217     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
218     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
219     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
220     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
221     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
222     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
223     DestroyWindow (hLB);
224 }
225 
226 static int got_selchange;
227 
228 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
229 {
230     switch (msg)
231     {
232     case WM_DRAWITEM:
233     {
234         RECT rc_item, rc_client, rc_clip;
235         DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
236 
237         trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam);
238 
239         ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n",
240 			wparam, dis->CtlID);
241         ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
242 
243         GetClientRect(dis->hwndItem, &rc_client);
244         trace("hwndItem %p client rect %s\n", dis->hwndItem, wine_dbgstr_rect(&rc_client));
245         GetClipBox(dis->hDC, &rc_clip);
246         trace("clip rect %s\n", wine_dbgstr_rect(&rc_clip));
247         ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
248            "client rect of the listbox should be equal to the clip box,"
249            "or the clip box should be empty\n");
250 
251         trace("rcItem %s\n", wine_dbgstr_rect(&dis->rcItem));
252         SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
253         trace("item rect %s\n", wine_dbgstr_rect(&rc_item));
254         ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
255 
256         break;
257     }
258 
259     case WM_COMMAND:
260         if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
261         break;
262 
263     default:
264         break;
265     }
266 
267     return DefWindowProcA(hwnd, msg, wparam, lparam);
268 }
269 
270 static HWND create_parent( void )
271 {
272     WNDCLASSA cls;
273     HWND parent;
274     static ATOM class;
275 
276     if (!class)
277     {
278         cls.style = 0;
279         cls.lpfnWndProc = main_window_proc;
280         cls.cbClsExtra = 0;
281         cls.cbWndExtra = 0;
282         cls.hInstance = GetModuleHandleA(NULL);
283         cls.hIcon = 0;
284         cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
285         cls.hbrBackground = GetStockObject(WHITE_BRUSH);
286         cls.lpszMenuName = NULL;
287         cls.lpszClassName = "main_window_class";
288         class = RegisterClassA( &cls );
289     }
290 
291     parent = CreateWindowExA(0, "main_window_class", NULL,
292                             WS_POPUP | WS_VISIBLE,
293                             100, 100, 400, 400,
294                             GetDesktopWindow(), 0,
295                             GetModuleHandleA(NULL), NULL);
296     return parent;
297 }
298 
299 static void test_ownerdraw(void)
300 {
301     HWND parent, hLB;
302     INT ret;
303     RECT rc;
304 
305     parent = create_parent();
306     assert(parent);
307 
308     hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
309     assert(hLB);
310 
311     SetForegroundWindow(hLB);
312     UpdateWindow(hLB);
313 
314     /* make height short enough */
315     SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
316     SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
317                  SWP_NOZORDER | SWP_NOMOVE);
318 
319     /* make 0 item invisible */
320     SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
321     ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
322     ok(ret == 1, "wrong top index %d\n", ret);
323 
324     SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
325     trace("item 0 rect %s\n", wine_dbgstr_rect(&rc));
326     ok(!IsRectEmpty(&rc), "empty item rect\n");
327     ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
328 
329     DestroyWindow(hLB);
330     DestroyWindow(parent);
331 }
332 
333 #define listbox_test_query(exp, got) \
334   ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
335   ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
336   ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
337   ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
338 
339 static void test_LB_SELITEMRANGE(void)
340 {
341     static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
342     static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
343     static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
344     static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
345     HWND hLB;
346     struct listbox_stat answer;
347     INT ret;
348 
349     trace("testing LB_SELITEMRANGE\n");
350 
351     hLB = create_listbox(LBS_EXTENDEDSEL, 0);
352     assert(hLB);
353 
354     listbox_query(hLB, &answer);
355     listbox_test_query(test_nosel, answer);
356 
357     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
358     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
359     listbox_query(hLB, &answer);
360     listbox_test_query(test_1, answer);
361 
362     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
363     listbox_query(hLB, &answer);
364     listbox_test_query(test_nosel, answer);
365 
366     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
367     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
368     listbox_query(hLB, &answer);
369     listbox_test_query(test_3, answer);
370 
371     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
372     listbox_query(hLB, &answer);
373     listbox_test_query(test_nosel, answer);
374 
375     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
376     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
377     listbox_query(hLB, &answer);
378     listbox_test_query(test_nosel, answer);
379 
380     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
381     listbox_query(hLB, &answer);
382     listbox_test_query(test_nosel, answer);
383 
384     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
385     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
386     listbox_query(hLB, &answer);
387     listbox_test_query(test_1, answer);
388 
389     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
390     listbox_query(hLB, &answer);
391     listbox_test_query(test_nosel, answer);
392 
393     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
394     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
395     listbox_query(hLB, &answer);
396     listbox_test_query(test_nosel, answer);
397 
398     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
399     listbox_query(hLB, &answer);
400     listbox_test_query(test_nosel, answer);
401 
402     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
403     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
404     listbox_query(hLB, &answer);
405     listbox_test_query(test_2, answer);
406 
407     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
408     listbox_query(hLB, &answer);
409     listbox_test_query(test_nosel, answer);
410 
411     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
412     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
413     listbox_query(hLB, &answer);
414     listbox_test_query(test_2, answer);
415 
416     DestroyWindow(hLB);
417 }
418 
419 static void test_LB_SETCURSEL(void)
420 {
421     HWND parent, hLB;
422     INT ret;
423 
424     trace("testing LB_SETCURSEL\n");
425 
426     parent = create_parent();
427     assert(parent);
428 
429     hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
430     assert(hLB);
431 
432     SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
433 
434     ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
435     ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
436     ret = GetScrollPos(hLB, SB_VERT);
437     ok(ret == 0, "expected vscroll 0, got %d\n", ret);
438 
439     ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
440     ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
441     ret = GetScrollPos(hLB, SB_VERT);
442     ok(ret == 1, "expected vscroll 1, got %d\n", ret);
443 
444     DestroyWindow(hLB);
445 }
446 
447 static void test_listbox_height(void)
448 {
449     HWND hList;
450     int r, id;
451 
452     hList = CreateWindowA( "ListBox", "list test", 0,
453                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
454     ok( hList != NULL, "failed to create listbox\n");
455 
456     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
457     ok( id == 0, "item id wrong\n");
458 
459     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
460     ok( r == 0, "send message failed\n");
461 
462     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
463     ok( r == 20, "height wrong\n");
464 
465     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
466     ok( r == -1, "send message failed\n");
467 
468     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
469     ok( r == 20, "height wrong\n");
470 
471     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
472     ok( r == -1, "send message failed\n");
473 
474     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
475     ok( r == 20, "height wrong\n");
476 
477     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
478     ok( r == 0, "send message failed\n");
479 
480     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
481     ok( r == 0xff, "height wrong\n");
482 
483     DestroyWindow( hList );
484 }
485 
486 static void test_itemfrompoint(void)
487 {
488     /* WS_POPUP is required in order to have a more accurate size calculation (
489        without caption). LBS_NOINTEGRALHEIGHT is required in order to test
490        behavior of partially-displayed item.
491      */
492     HWND hList = CreateWindowA( "ListBox", "list test",
493                                WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
494                                1, 1, 600, 100, NULL, NULL, NULL, NULL );
495     ULONG r, id;
496     RECT rc;
497 
498     /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
499     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
500     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
501 
502     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
503     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
504 
505     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
506     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
507 
508     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
509     ok( id == 0, "item id wrong\n");
510     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
511     ok( id == 1, "item id wrong\n");
512 
513     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
514     ok( r == 0x1, "ret %x\n", r );
515 
516     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
517     ok( r == 0x10001 || broken(r == 1), /* nt4 */
518         "ret %x\n", r );
519 
520     /* Resize control so that below assertions about sizes are valid */
521     r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
522     ok( r == 1, "ret %x\n", r);
523     r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
524     ok( r != 0, "ret %x\n", r);
525 
526     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
527     ok( id == 2, "item id wrong\n");
528     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
529     ok( id == 3, "item id wrong\n");
530     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
531     ok( id == 4, "item id wrong\n");
532     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
533     ok( id == 5, "item id wrong\n");
534     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
535     ok( id == 6, "item id wrong\n");
536     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
537     ok( id == 7, "item id wrong\n");
538 
539     /* Set the listbox up so that id 1 is at the top, this leaves 5
540        partially visible at the bottom and 6, 7 are invisible */
541 
542     SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
543     r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
544     ok( r == 1, "top %d\n", r);
545 
546     r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
547     ok( r == 1, "ret %x\n", r);
548     r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
549     ok( r == 0, "ret %x\n", r);
550 
551     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
552     ok( r == 1, "ret %x\n", r);
553 
554     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
555     ok( r == 0x10001 || broken(r == 1), /* nt4 */
556         "ret %x\n", r );
557 
558     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
559     ok( r == 0x10001 || broken(r == 1), /* nt4 */
560         "ret %x\n", r );
561 
562     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
563     ok( r == 0x10005 || broken(r == 5), /* nt4 */
564         "item %x\n", r );
565 
566     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
567     ok( r == 0x10005 || broken(r == 5), /* nt4 */
568         "item %x\n", r );
569 
570     DestroyWindow( hList );
571 }
572 
573 static void test_listbox_item_data(void)
574 {
575     HWND hList;
576     int r, id;
577 
578     hList = CreateWindowA( "ListBox", "list test", 0,
579                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
580     ok( hList != NULL, "failed to create listbox\n");
581 
582     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
583     ok( id == 0, "item id wrong\n");
584 
585     r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
586     ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
587 
588     r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
589     ok( r == 20, "get item data failed\n");
590 
591     DestroyWindow( hList );
592 }
593 
594 static void test_listbox_LB_DIR(void)
595 {
596     HWND hList;
597     int res, itemCount;
598     int itemCount_justFiles;
599     int itemCount_justDrives;
600     int itemCount_allFiles;
601     int itemCount_allDirs;
602     int i;
603     char pathBuffer[MAX_PATH];
604     char * p;
605     char driveletter;
606     const char *wildcard = "*";
607     HANDLE file;
608 
609     file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
610     ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
611     CloseHandle( file );
612 
613     /* NOTE: for this test to succeed, there must be no subdirectories
614        under the current directory. In addition, there must be at least
615        one file that fits the wildcard w*.c . Normally, the test
616        directory itself satisfies both conditions.
617      */
618     hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
619                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
620     assert(hList);
621 
622     /* Test for standard usage */
623 
624     /* This should list all the files in the test directory. */
625     strcpy(pathBuffer, wildcard);
626     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
627     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
628     if (res == -1)  /* "*" wildcard doesn't work on win9x */
629     {
630         wildcard = "*.*";
631         strcpy(pathBuffer, wildcard);
632         res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
633     }
634     ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
635 
636     /* There should be some content in the listbox */
637     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
638     ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
639     itemCount_allFiles = itemCount;
640     ok(res + 1 == itemCount,
641         "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
642         itemCount - 1, res);
643 
644     /* This tests behavior when no files match the wildcard */
645     strcpy(pathBuffer, BAD_EXTENSION);
646     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
647     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
648     ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
649 
650     /* There should be NO content in the listbox */
651     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
652     ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
653 
654 
655     /* This should list all the w*.c files in the test directory
656      * As of this writing, this includes win.c, winstation.c, wsprintf.c
657      */
658     strcpy(pathBuffer, "w*.c");
659     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
660     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
661     ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
662 
663     /* Path specification does NOT converted to uppercase */
664     ok (!strcmp(pathBuffer, "w*.c"),
665         "expected no change to pathBuffer, got %s\n", pathBuffer);
666 
667     /* There should be some content in the listbox */
668     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
669     ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
670     itemCount_justFiles = itemCount;
671     ok(res + 1 == itemCount,
672         "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
673         itemCount - 1, res);
674 
675     /* Every single item in the control should start with a w and end in .c */
676     for (i = 0; i < itemCount; i++) {
677         memset(pathBuffer, 0, MAX_PATH);
678         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
679         p = pathBuffer + strlen(pathBuffer);
680         ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
681             (*(p-1) == 'c' || *(p-1) == 'C') &&
682             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
683     }
684 
685     /* Test DDL_DIRECTORY */
686     strcpy(pathBuffer, wildcard);
687     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
688     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
689     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
690 
691     /* There should be some content in the listbox.
692      * All files plus "[..]"
693      */
694     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
695     itemCount_allDirs = itemCount - itemCount_allFiles;
696     ok (itemCount > itemCount_allFiles,
697         "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
698         itemCount, itemCount_allFiles);
699     ok(res + 1 == itemCount,
700         "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
701         itemCount - 1, res);
702 
703     /* This tests behavior when no files match the wildcard */
704     strcpy(pathBuffer, BAD_EXTENSION);
705     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
706     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
707     ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
708 
709     /* There should be NO content in the listbox */
710     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
711     ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
712 
713 
714     /* Test DDL_DIRECTORY */
715     strcpy(pathBuffer, "w*.c");
716     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
717     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
718     ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
719 
720     /* There should be some content in the listbox. Since the parent directory does not
721      * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
722      */
723     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
724     ok (itemCount == itemCount_justFiles,
725         "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
726         itemCount, itemCount_justFiles);
727     ok(res + 1 == itemCount,
728         "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
729         itemCount - 1, res);
730 
731     /* Every single item in the control should start with a w and end in .c. */
732     for (i = 0; i < itemCount; i++) {
733         memset(pathBuffer, 0, MAX_PATH);
734         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
735         p = pathBuffer + strlen(pathBuffer);
736         ok(
737             ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
738             (*(p-1) == 'c' || *(p-1) == 'C') &&
739             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
740     }
741 
742 
743     /* Test DDL_DRIVES|DDL_EXCLUSIVE */
744     strcpy(pathBuffer, wildcard);
745     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
746     res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
747     ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *)  failed - 0x%08x\n", GetLastError());
748 
749     /* There should be some content in the listbox. In particular, there should
750      * be at least one element before, since the string "[-c-]" should
751      * have been added. Depending on the user setting, more drives might have
752      * been added.
753      */
754     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
755     ok (itemCount >= 1,
756         "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
757         itemCount, 1);
758     itemCount_justDrives = itemCount;
759     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
760 
761     /* Every single item in the control should fit the format [-c-] */
762     for (i = 0; i < itemCount; i++) {
763         memset(pathBuffer, 0, MAX_PATH);
764         driveletter = '\0';
765         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
766         ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
767         ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
768         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
769         if (!(driveletter >= 'a' && driveletter <= 'z')) {
770             /* Correct after invalid entry is found */
771             trace("removing count of invalid entry %s\n", pathBuffer);
772             itemCount_justDrives--;
773         }
774     }
775 
776     /* This tests behavior when no files match the wildcard */
777     strcpy(pathBuffer, BAD_EXTENSION);
778     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
779     res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
780     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
781         BAD_EXTENSION, res, itemCount_justDrives -1);
782 
783     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
784     ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
785         itemCount, itemCount_justDrives);
786 
787     trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
788         itemCount_justFiles, itemCount_justDrives);
789 
790     /* Test DDL_DRIVES. */
791     strcpy(pathBuffer, wildcard);
792     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
793     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
794     ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *)  failed - 0x%08x\n", GetLastError());
795 
796     /* There should be some content in the listbox. In particular, there should
797      * be at least one element before, since the string "[-c-]" should
798      * have been added. Depending on the user setting, more drives might have
799      * been added.
800      */
801     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
802     ok (itemCount == itemCount_justDrives + itemCount_allFiles,
803         "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
804         itemCount, itemCount_justDrives + itemCount_allFiles);
805     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
806 
807     /* This tests behavior when no files match the wildcard */
808     strcpy(pathBuffer, BAD_EXTENSION);
809     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
810     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
811     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
812         BAD_EXTENSION, res, itemCount_justDrives -1);
813 
814     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
815     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
816 
817 
818     /* Test DDL_DRIVES. */
819     strcpy(pathBuffer, "w*.c");
820     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
821     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
822     ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c)  failed - 0x%08x\n", GetLastError());
823 
824     /* There should be some content in the listbox. In particular, there should
825      * be at least one element before, since the string "[-c-]" should
826      * have been added. Depending on the user setting, more drives might have
827      * been added.
828      */
829     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
830     ok (itemCount == itemCount_justDrives + itemCount_justFiles,
831         "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
832         itemCount, itemCount_justDrives + itemCount_justFiles);
833     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
834 
835     /* Every single item in the control should fit the format [-c-], or w*.c */
836     for (i = 0; i < itemCount; i++) {
837         memset(pathBuffer, 0, MAX_PATH);
838         driveletter = '\0';
839         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
840         p = pathBuffer + strlen(pathBuffer);
841         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
842             ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
843             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
844         } else {
845             ok(
846                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
847                 (*(p-1) == 'c' || *(p-1) == 'C') &&
848                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
849         }
850     }
851 
852 
853     /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
854     strcpy(pathBuffer, wildcard);
855     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
856     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
857     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
858 
859     /* There should be some content in the listbox. In particular, there should
860      * be exactly the number of plain files, plus the number of mapped drives.
861      */
862     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
863     ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
864         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
865         itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
866     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
867 
868     /* Every single item in the control should start with a w and end in .c,
869      * except for the "[..]" string, which should appear exactly as it is,
870      * and the mapped drives in the format "[-X-]".
871      */
872     for (i = 0; i < itemCount; i++) {
873         memset(pathBuffer, 0, MAX_PATH);
874         driveletter = '\0';
875         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
876         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
877             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
878         }
879     }
880 
881     /* This tests behavior when no files match the wildcard */
882     strcpy(pathBuffer, BAD_EXTENSION);
883     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
884     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
885     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
886         BAD_EXTENSION, res, itemCount_justDrives -1);
887 
888     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
889     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
890 
891 
892 
893     /* Test DDL_DIRECTORY|DDL_DRIVES. */
894     strcpy(pathBuffer, "w*.c");
895     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
896     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
897     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
898 
899     /* There should be some content in the listbox. In particular, there should
900      * be exactly the number of plain files, plus the number of mapped drives.
901      */
902     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
903     ok (itemCount == itemCount_justFiles + itemCount_justDrives,
904         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
905         itemCount, itemCount_justFiles + itemCount_justDrives);
906     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
907 
908     /* Every single item in the control should start with a w and end in .c,
909      * except the mapped drives in the format "[-X-]". The "[..]" directory
910      * should not appear.
911      */
912     for (i = 0; i < itemCount; i++) {
913         memset(pathBuffer, 0, MAX_PATH);
914         driveletter = '\0';
915         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
916         p = pathBuffer + strlen(pathBuffer);
917         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
918             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
919         } else {
920             ok(
921                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
922                 (*(p-1) == 'c' || *(p-1) == 'C') &&
923                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
924         }
925     }
926 
927     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
928     strcpy(pathBuffer, wildcard);
929     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
930     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
931     ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
932 
933     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
934     ok (itemCount == itemCount_allDirs,
935         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
936         itemCount, itemCount_allDirs);
937     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
938 
939     if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3)  /* there's no [..] in drive root */
940     {
941         memset(pathBuffer, 0, MAX_PATH);
942         SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
943         ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
944     }
945 
946     /* This tests behavior when no files match the wildcard */
947     strcpy(pathBuffer, BAD_EXTENSION);
948     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
949     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
950     ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
951         BAD_EXTENSION, res, -1);
952 
953     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
954     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
955 
956 
957     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
958     strcpy(pathBuffer, "w*.c");
959     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
960     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
961     ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
962 
963     /* There should be no elements, since "[..]" does not fit w*.c */
964     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
965     ok (itemCount == 0,
966         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
967         itemCount, 0);
968 
969     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
970     strcpy(pathBuffer, wildcard);
971     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
972     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
973     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
974 
975     /* There should be no plain files on the listbox */
976     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
977     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
978         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
979         itemCount, itemCount_justDrives + itemCount_allDirs);
980     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
981 
982     for (i = 0; i < itemCount; i++) {
983         memset(pathBuffer, 0, MAX_PATH);
984         driveletter = '\0';
985         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
986         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
987             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
988         } else {
989             ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
990                 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
991         }
992     }
993 
994     /* This tests behavior when no files match the wildcard */
995     strcpy(pathBuffer, BAD_EXTENSION);
996     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
997     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
998     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
999         BAD_EXTENSION, res, itemCount_justDrives -1);
1000 
1001     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1002     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1003 
1004     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1005     strcpy(pathBuffer, "w*.c");
1006     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1007     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1008     ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1009 
1010     /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1011     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1012     ok (itemCount == itemCount_justDrives,
1013         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1014         itemCount, itemCount_justDrives);
1015     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1016 
1017     for (i = 0; i < itemCount; i++) {
1018         memset(pathBuffer, 0, MAX_PATH);
1019         driveletter = '\0';
1020         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1021         ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1022         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1023     }
1024     DestroyWindow(hList);
1025 
1026     DeleteFileA( "wtest1.tmp.c" );
1027 }
1028 
1029 static HWND g_listBox;
1030 static HWND g_label;
1031 
1032 #define ID_TEST_LABEL    1001
1033 #define ID_TEST_LISTBOX  1002
1034 
1035 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCTA lpcs)
1036 {
1037     g_label = CreateWindowA(
1038         "Static",
1039         "Contents of static control before DlgDirList.",
1040         WS_CHILD | WS_VISIBLE,
1041         10, 10, 512, 32,
1042         hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1043     if (!g_label) return FALSE;
1044     g_listBox = CreateWindowA(
1045         "ListBox",
1046         "DlgDirList test",
1047         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1048         10, 60, 256, 256,
1049         hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1050     if (!g_listBox) return FALSE;
1051 
1052     return TRUE;
1053 }
1054 
1055 static LRESULT CALLBACK listbox_container_window_procA (
1056     HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1057 {
1058     LRESULT result = 0;
1059 
1060     switch (uiMsg) {
1061     case WM_DESTROY:
1062         PostQuitMessage(0);
1063         break;
1064     case WM_CREATE:
1065         result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1066             ? 0 : (LRESULT)-1;
1067         break;
1068     default:
1069         result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1070         break;
1071     }
1072     return result;
1073 }
1074 
1075 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1076 {
1077     WNDCLASSA cls;
1078 
1079     cls.style = 0;
1080     cls.cbClsExtra = 0;
1081     cls.cbWndExtra = 0;
1082     cls.hInstance = hInst;
1083     cls.hIcon = NULL;
1084     cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1085     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1086     cls.lpszMenuName = NULL;
1087     cls.lpfnWndProc = listbox_container_window_procA;
1088     cls.lpszClassName = "ListboxContainerClass";
1089     if (!RegisterClassA (&cls)) return FALSE;
1090 
1091     return TRUE;
1092 }
1093 
1094 static void test_listbox_dlgdir(void)
1095 {
1096     HINSTANCE hInst;
1097     HWND hWnd;
1098     int res, itemCount;
1099     int itemCount_allDirs;
1100     int itemCount_justFiles;
1101     int itemCount_justDrives;
1102     int i;
1103     char pathBuffer[MAX_PATH];
1104     char itemBuffer[MAX_PATH];
1105     char tempBuffer[MAX_PATH];
1106     char * p;
1107     char driveletter;
1108     HANDLE file;
1109 
1110     file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1111     ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1112     CloseHandle( file );
1113 
1114     /* NOTE: for this test to succeed, there must be no subdirectories
1115        under the current directory. In addition, there must be at least
1116        one file that fits the wildcard w*.c . Normally, the test
1117        directory itself satisfies both conditions.
1118      */
1119 
1120     hInst = GetModuleHandleA(0);
1121     if (!RegisterListboxWindowClass(hInst)) assert(0);
1122     hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1123                     WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1124             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1125             NULL, NULL, hInst, 0);
1126     assert(hWnd);
1127 
1128     /* Test for standard usage */
1129 
1130     /* The following should be overwritten by the directory path */
1131     SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1132 
1133     /* This should list all the w*.c files in the test directory
1134      * As of this writing, this includes win.c, winstation.c, wsprintf.c
1135      */
1136     strcpy(pathBuffer, "w*.c");
1137     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1138     ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1139 
1140     /* Path specification gets converted to uppercase */
1141     ok (!strcmp(pathBuffer, "W*.C"),
1142         "expected conversion to uppercase, got %s\n", pathBuffer);
1143 
1144     /* Loaded path should have overwritten the label text */
1145     SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1146     trace("Static control after DlgDirList: %s\n", pathBuffer);
1147     ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1148 
1149     /* There should be some content in the listbox */
1150     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1151     ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1152     itemCount_justFiles = itemCount;
1153 
1154     /* Every single item in the control should start with a w and end in .c */
1155     for (i = 0; i < itemCount; i++) {
1156         memset(pathBuffer, 0, MAX_PATH);
1157         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1158         p = pathBuffer + strlen(pathBuffer);
1159         ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1160             (*(p-1) == 'c' || *(p-1) == 'C') &&
1161             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1162     }
1163 
1164     /* Test behavior when no files match the wildcard */
1165     strcpy(pathBuffer, BAD_EXTENSION);
1166     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1167     ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1168 
1169     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1170     ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1171 
1172     /* Test DDL_DIRECTORY */
1173     strcpy(pathBuffer, "w*.c");
1174     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1175         DDL_DIRECTORY);
1176     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1177 
1178     /* There should be some content in the listbox. In particular, there should
1179      * be exactly more elements than before, since the directories should
1180      * have been added.
1181      */
1182     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1183     itemCount_allDirs = itemCount - itemCount_justFiles;
1184     ok (itemCount >= itemCount_justFiles,
1185         "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1186         itemCount, itemCount_justFiles);
1187 
1188     /* Every single item in the control should start with a w and end in .c,
1189      * except for the "[..]" string, which should appear exactly as it is.
1190      */
1191     for (i = 0; i < itemCount; i++) {
1192         memset(pathBuffer, 0, MAX_PATH);
1193         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1194         p = pathBuffer + strlen(pathBuffer);
1195         ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1196             ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1197             (*(p-1) == 'c' || *(p-1) == 'C') &&
1198             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1199     }
1200 
1201     /* Test behavior when no files match the wildcard */
1202     strcpy(pathBuffer, BAD_EXTENSION);
1203     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1204         DDL_DIRECTORY);
1205     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1206 
1207     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1208     ok (itemCount == itemCount_allDirs,
1209         "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1210         itemCount_allDirs, itemCount);
1211     for (i = 0; i < itemCount; i++) {
1212         memset(pathBuffer, 0, MAX_PATH);
1213         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1214         ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1215             "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1216     }
1217 
1218 
1219     /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1220     strcpy(pathBuffer, "w*.c");
1221     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1222         DDL_DRIVES);
1223     ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1224 
1225     /* There should be some content in the listbox. In particular, there should
1226      * be at least one element before, since the string "[-c-]" should
1227      * have been added. Depending on the user setting, more drives might have
1228      * been added.
1229      */
1230     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1231     ok (itemCount >= 1,
1232         "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1233         itemCount, 1);
1234     itemCount_justDrives = itemCount;
1235 
1236     /* Every single item in the control should fit the format [-c-] */
1237     for (i = 0; i < itemCount; i++) {
1238         memset(pathBuffer, 0, MAX_PATH);
1239         driveletter = '\0';
1240         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1241         ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1242         ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1243         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1244         if (!(driveletter >= 'a' && driveletter <= 'z')) {
1245             /* Correct after invalid entry is found */
1246             trace("removing count of invalid entry %s\n", pathBuffer);
1247             itemCount_justDrives--;
1248         }
1249     }
1250 
1251     /* Test behavior when no files match the wildcard */
1252     strcpy(pathBuffer, BAD_EXTENSION);
1253     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1254         DDL_DRIVES);
1255     ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1256 
1257     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1258     ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1259 
1260 
1261     /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1262     strcpy(pathBuffer, "w*.c");
1263     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1264         DDL_DIRECTORY|DDL_DRIVES);
1265     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1266 
1267     /* There should be some content in the listbox. In particular, there should
1268      * be exactly the number of plain files, plus the number of mapped drives,
1269      * plus one "[..]"
1270      */
1271     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1272     ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1273         "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1274         itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1275 
1276     /* Every single item in the control should start with a w and end in .c,
1277      * except for the "[..]" string, which should appear exactly as it is,
1278      * and the mapped drives in the format "[-X-]".
1279      */
1280     for (i = 0; i < itemCount; i++) {
1281         memset(pathBuffer, 0, MAX_PATH);
1282         driveletter = '\0';
1283         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1284         p = pathBuffer + strlen(pathBuffer);
1285         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1286             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1287         } else {
1288             ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1289                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1290                 (*(p-1) == 'c' || *(p-1) == 'C') &&
1291                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1292         }
1293     }
1294 
1295     /* Test behavior when no files match the wildcard */
1296     strcpy(pathBuffer, BAD_EXTENSION);
1297     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1298         DDL_DIRECTORY|DDL_DRIVES);
1299     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1300 
1301     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1302     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1303         "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1304         itemCount_justDrives + itemCount_allDirs, itemCount);
1305 
1306 
1307 
1308     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1309     strcpy(pathBuffer, "w*.c");
1310     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1311         DDL_DIRECTORY|DDL_EXCLUSIVE);
1312     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1313 
1314     /* There should be exactly one element: "[..]" */
1315     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1316     ok (itemCount == itemCount_allDirs,
1317         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1318         itemCount, itemCount_allDirs);
1319 
1320     if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3)  /* there's no [..] in drive root */
1321     {
1322         memset(pathBuffer, 0, MAX_PATH);
1323         SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1324         ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1325     }
1326 
1327     /* Test behavior when no files match the wildcard */
1328     strcpy(pathBuffer, BAD_EXTENSION);
1329     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1330         DDL_DIRECTORY|DDL_EXCLUSIVE);
1331     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1332 
1333     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1334     ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1335 
1336 
1337     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1338     strcpy(pathBuffer, "w*.c");
1339     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1340         DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1341     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1342 
1343     /* There should be no plain files on the listbox */
1344     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1345     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1346         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1347         itemCount, itemCount_justDrives + itemCount_allDirs);
1348 
1349     for (i = 0; i < itemCount; i++) {
1350         memset(pathBuffer, 0, MAX_PATH);
1351         driveletter = '\0';
1352         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1353         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1354             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1355         } else {
1356             ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1357                 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1358         }
1359     }
1360 
1361     /* Test behavior when no files match the wildcard */
1362     strcpy(pathBuffer, BAD_EXTENSION);
1363     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1364         DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1365     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1366 
1367     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1368     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1369         "DlgDirList() incorrectly filled the listbox!\n");
1370 
1371     /* Now test DlgDirSelectEx() in normal operation */
1372     /* Fill with everything - drives, directory and all plain files. */
1373     strcpy(pathBuffer, "*");
1374     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1375         DDL_DIRECTORY|DDL_DRIVES);
1376     ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1377 
1378     SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1379     memset(pathBuffer, 0, MAX_PATH);
1380     SetLastError(0xdeadbeef);
1381     res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1382     ok (GetLastError() == 0xdeadbeef,
1383         "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1384         GetLastError());
1385     ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1386     /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1387     /*
1388     ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1389     */
1390     /* Test proper drive/dir/file recognition */
1391     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1392     for (i = 0; i < itemCount; i++) {
1393         memset(itemBuffer, 0, MAX_PATH);
1394         memset(pathBuffer, 0, MAX_PATH);
1395         memset(tempBuffer, 0, MAX_PATH);
1396         driveletter = '\0';
1397         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1398         res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1399         ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1400         if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1401             /* Current item is a drive letter */
1402             SetLastError(0xdeadbeef);
1403             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1404             ok (GetLastError() == 0xdeadbeef,
1405                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1406                 i, GetLastError());
1407             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1408 
1409             /* For drive letters, DlgDirSelectEx tacks on a colon */
1410             ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1411                 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1412         } else if (itemBuffer[0] == '[') {
1413             /* Current item is the parent directory */
1414             SetLastError(0xdeadbeef);
1415             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1416             ok (GetLastError() == 0xdeadbeef,
1417                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1418                 i, GetLastError());
1419             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1420 
1421             /* For directories, DlgDirSelectEx tacks on a backslash */
1422             p = pathBuffer + strlen(pathBuffer);
1423             ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1424 
1425             tempBuffer[0] = '[';
1426             lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1427             strcat(tempBuffer, "]");
1428             ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1429         } else {
1430             /* Current item is a plain file */
1431             SetLastError(0xdeadbeef);
1432             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1433             ok (GetLastError() == 0xdeadbeef,
1434                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1435                 i, GetLastError());
1436             ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1437 
1438             /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1439              * for example, "Makefile", which gets reported as "Makefile."
1440              */
1441             strcpy(tempBuffer, itemBuffer);
1442             if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1443             ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1444         }
1445     }
1446 
1447     DeleteFileA( "wtest1.tmp.c" );
1448 
1449     /* Now test DlgDirSelectEx() in abnormal operation */
1450     /* Fill list with bogus entries, that look somewhat valid */
1451     SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1452     SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1453     SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1454     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1455     for (i = 0; i < itemCount; i++) {
1456         memset(itemBuffer, 0, MAX_PATH);
1457         memset(pathBuffer, 0, MAX_PATH);
1458         memset(tempBuffer, 0, MAX_PATH);
1459         driveletter = '\0';
1460         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1461         res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1462         ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1463         if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1464             /* Current item is a drive letter */
1465             SetLastError(0xdeadbeef);
1466             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1467             ok (GetLastError() == 0xdeadbeef,
1468                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1469                 i, GetLastError());
1470             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1471 
1472             /* For drive letters, DlgDirSelectEx tacks on a colon */
1473             ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1474                 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1475         } else if (itemBuffer[0] == '[') {
1476             /* Current item is the parent directory */
1477             SetLastError(0xdeadbeef);
1478             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1479             ok (GetLastError() == 0xdeadbeef,
1480                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1481                 i, GetLastError());
1482             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1483 
1484             /* For directories, DlgDirSelectEx tacks on a backslash */
1485             p = pathBuffer + strlen(pathBuffer);
1486             ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1487 
1488             tempBuffer[0] = '[';
1489             lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1490             strcat(tempBuffer, "]");
1491             ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1492         } else {
1493             /* Current item is a plain file */
1494             SetLastError(0xdeadbeef);
1495             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1496             ok (GetLastError() == 0xdeadbeef,
1497                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1498                 i, GetLastError());
1499             ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1500 
1501             /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1502              * This affects for example, "Makefile", which gets reported as "Makefile."
1503              */
1504             strcpy(tempBuffer, itemBuffer);
1505             if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1506             ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1507         }
1508     }
1509 
1510     /* Test behavior when loading folders from root with and without wildcard */
1511     strcpy(pathBuffer, "C:\\");
1512     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1513     ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1514     todo_wine ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1515        "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1516 
1517     strcpy(pathBuffer, "C:\\*");
1518     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1519     ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\* folders\n");
1520     ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1521        "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1522 
1523     /* Try loading files from an invalid folder */
1524     SetLastError(0xdeadbeef);
1525     strcpy(pathBuffer, "C:\\INVALID$$DIR");
1526     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1527     todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1528     todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1529        "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1530 
1531     DestroyWindow(hWnd);
1532 }
1533 
1534 static void test_set_count( void )
1535 {
1536     HWND parent, listbox;
1537     LONG ret;
1538     RECT r;
1539 
1540     parent = create_parent();
1541     listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1542 
1543     UpdateWindow( listbox );
1544     GetUpdateRect( listbox, &r, TRUE );
1545     ok( IsRectEmpty( &r ), "got non-empty rect\n");
1546 
1547     ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1548     ok( ret == 0, "got %d\n", ret );
1549     ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1550     ok( ret == 100, "got %d\n", ret );
1551 
1552     GetUpdateRect( listbox, &r, TRUE );
1553     ok( !IsRectEmpty( &r ), "got empty rect\n");
1554 
1555     ValidateRect( listbox, NULL );
1556     GetUpdateRect( listbox, &r, TRUE );
1557     ok( IsRectEmpty( &r ), "got non-empty rect\n");
1558 
1559     ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1560     ok( ret == 0, "got %d\n", ret );
1561 
1562     GetUpdateRect( listbox, &r, TRUE );
1563     ok( !IsRectEmpty( &r ), "got empty rect\n");
1564 
1565     DestroyWindow( listbox );
1566     DestroyWindow( parent );
1567 }
1568 
1569 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1570 static int lb_getlistboxinfo;
1571 
1572 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1573 {
1574     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1575 
1576     if (message == LB_GETLISTBOXINFO)
1577         lb_getlistboxinfo++;
1578 
1579     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1580 }
1581 
1582 static void test_GetListBoxInfo(void)
1583 {
1584     HWND listbox, parent;
1585     WNDPROC oldproc;
1586     DWORD ret;
1587 
1588     pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetListBoxInfo");
1589 
1590     if (!pGetListBoxInfo)
1591     {
1592         win_skip("GetListBoxInfo() not available\n");
1593         return;
1594     }
1595 
1596     parent = create_parent();
1597     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1598 
1599     oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1600     SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1601 
1602     lb_getlistboxinfo = 0;
1603     ret = pGetListBoxInfo(listbox);
1604     ok(ret > 0, "got %d\n", ret);
1605 todo_wine
1606     ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
1607 
1608     DestroyWindow(listbox);
1609     DestroyWindow(parent);
1610 }
1611 
1612 static void test_missing_lbuttonup( void )
1613 {
1614     HWND listbox, parent, capture;
1615 
1616     parent = create_parent();
1617     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1618 
1619     /* Send button down without a corresponding button up */
1620     SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10,10));
1621     capture = GetCapture();
1622     ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1623 
1624     /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1625     got_selchange = 0;
1626     SetFocus(NULL);
1627     capture = GetCapture();
1628     ok(capture == NULL, "got %p\n", capture);
1629     ok(got_selchange, "got %d\n", got_selchange);
1630 
1631     DestroyWindow(listbox);
1632     DestroyWindow(parent);
1633 }
1634 
1635 static void test_extents(void)
1636 {
1637     HWND listbox, parent;
1638     DWORD res;
1639     SCROLLINFO sinfo;
1640     BOOL br;
1641 
1642     parent = create_parent();
1643 
1644     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1645 
1646     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1647     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1648 
1649     sinfo.cbSize = sizeof(sinfo);
1650     sinfo.fMask = SIF_RANGE;
1651     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1652     ok(br == TRUE, "GetScrollInfo failed\n");
1653     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1654     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1655     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1656         "List box should not have a horizontal scroll bar\n");
1657 
1658     /* horizontal extent < width */
1659     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1660 
1661     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1662     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1663 
1664     sinfo.cbSize = sizeof(sinfo);
1665     sinfo.fMask = SIF_RANGE;
1666     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1667     ok(br == TRUE, "GetScrollInfo failed\n");
1668     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1669     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1670     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1671         "List box should not have a horizontal scroll bar\n");
1672 
1673     /* horizontal extent > width */
1674     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1675 
1676     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1677     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1678 
1679     sinfo.cbSize = sizeof(sinfo);
1680     sinfo.fMask = SIF_RANGE;
1681     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1682     ok(br == TRUE, "GetScrollInfo failed\n");
1683     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1684     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1685     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1686         "List box should not have a horizontal scroll bar\n");
1687 
1688     DestroyWindow(listbox);
1689 
1690 
1691     listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1692 
1693     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1694     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1695 
1696     sinfo.cbSize = sizeof(sinfo);
1697     sinfo.fMask = SIF_RANGE;
1698     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1699     ok(br == TRUE, "GetScrollInfo failed\n");
1700     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1701     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1702     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1703         "List box should not have a horizontal scroll bar\n");
1704 
1705     /* horizontal extent < width */
1706     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1707 
1708     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1709     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1710 
1711     sinfo.cbSize = sizeof(sinfo);
1712     sinfo.fMask = SIF_RANGE;
1713     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1714     ok(br == TRUE, "GetScrollInfo failed\n");
1715     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1716     ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1717     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1718         "List box should not have a horizontal scroll bar\n");
1719 
1720     /* horizontal extent > width */
1721     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1722 
1723     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1724     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1725 
1726     sinfo.cbSize = sizeof(sinfo);
1727     sinfo.fMask = SIF_RANGE;
1728     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1729     ok(br == TRUE, "GetScrollInfo failed\n");
1730     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1731     ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1732     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1733         "List box should have a horizontal scroll bar\n");
1734 
1735     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1736 
1737     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1738     ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1739 
1740     sinfo.cbSize = sizeof(sinfo);
1741     sinfo.fMask = SIF_RANGE;
1742     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1743     ok(br == TRUE, "GetScrollInfo failed\n");
1744     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1745     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1746     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1747         "List box should not have a horizontal scroll bar\n");
1748 
1749     DestroyWindow(listbox);
1750 
1751 
1752     listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
1753 
1754     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1755     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1756 
1757     sinfo.cbSize = sizeof(sinfo);
1758     sinfo.fMask = SIF_RANGE;
1759     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1760     ok(br == TRUE, "GetScrollInfo failed\n");
1761     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1762     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1763     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1764         "List box should have a horizontal scroll bar\n");
1765 
1766     /* horizontal extent < width */
1767     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1768 
1769     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1770     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1771 
1772     sinfo.cbSize = sizeof(sinfo);
1773     sinfo.fMask = SIF_RANGE;
1774     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1775     ok(br == TRUE, "GetScrollInfo failed\n");
1776     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1777     ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1778     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1779         "List box should have a horizontal scroll bar\n");
1780 
1781     /* horizontal extent > width */
1782     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1783 
1784     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1785     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1786 
1787     sinfo.cbSize = sizeof(sinfo);
1788     sinfo.fMask = SIF_RANGE;
1789     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1790     ok(br == TRUE, "GetScrollInfo failed\n");
1791     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1792     ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1793     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1794         "List box should have a horizontal scroll bar\n");
1795 
1796     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1797 
1798     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1799     ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1800 
1801     sinfo.cbSize = sizeof(sinfo);
1802     sinfo.fMask = SIF_RANGE;
1803     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1804     ok(br == TRUE, "GetScrollInfo failed\n");
1805     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1806     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1807     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1808         "List box should have a horizontal scroll bar\n");
1809 
1810     DestroyWindow(listbox);
1811 
1812     DestroyWindow(parent);
1813 }
1814 
1815 START_TEST(listbox)
1816 {
1817   const struct listbox_test SS =
1818 /*   {add_style} */
1819     {{0},
1820      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
1821      {     1,      1,      1, LB_ERR}, {0,0,0,0},
1822      {     2,      2,      2, LB_ERR}, {0,0,0,0},
1823      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
1824 /* {selected, anchor,  caret, selcount}{TODO fields} */
1825   const struct listbox_test SS_NS =
1826     {{LBS_NOSEL},
1827      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
1828      {     1,      1,      1, LB_ERR}, {0,0,0,0},
1829      {     2,      2,      2, LB_ERR}, {0,0,0,0},
1830      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
1831   const struct listbox_test MS =
1832     {{LBS_MULTIPLESEL},
1833      {     0, LB_ERR,      0,      0}, {0,0,0,0},
1834      {     1,      1,      1,      1}, {0,0,0,0},
1835      {     2,      1,      2,      1}, {0,0,0,0},
1836      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
1837   const struct listbox_test MS_NS =
1838     {{LBS_MULTIPLESEL | LBS_NOSEL},
1839      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
1840      {     1,      1,      1, LB_ERR}, {0,0,0,0},
1841      {     2,      2,      2, LB_ERR}, {0,0,0,0},
1842      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
1843   const struct listbox_test ES =
1844     {{LBS_EXTENDEDSEL},
1845      {     0, LB_ERR,      0,      0}, {0,0,0,0},
1846      {     1,      1,      1,      1}, {0,0,0,0},
1847      {     2,      2,      2,      1}, {0,0,0,0},
1848      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
1849   const struct listbox_test ES_NS =
1850     {{LBS_EXTENDEDSEL | LBS_NOSEL},
1851      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
1852      {     1,      1,      1, LB_ERR}, {0,0,0,0},
1853      {     2,      2,      2, LB_ERR}, {0,0,0,0},
1854      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
1855   const struct listbox_test EMS =
1856     {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
1857      {     0, LB_ERR,      0,      0}, {0,0,0,0},
1858      {     1,      1,      1,      1}, {0,0,0,0},
1859      {     2,      2,      2,      1}, {0,0,0,0},
1860      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
1861   const struct listbox_test EMS_NS =
1862     {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
1863      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
1864      {     1,      1,      1, LB_ERR}, {0,0,0,0},
1865      {     2,      2,      2, LB_ERR}, {0,0,0,0},
1866      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
1867 
1868   trace (" Testing single selection...\n");
1869   check (SS);
1870   trace (" ... with NOSEL\n");
1871   check (SS_NS);
1872   trace (" Testing multiple selection...\n");
1873   check (MS);
1874   trace (" ... with NOSEL\n");
1875   check (MS_NS);
1876   trace (" Testing extended selection...\n");
1877   check (ES);
1878   trace (" ... with NOSEL\n");
1879   check (ES_NS);
1880   trace (" Testing extended and multiple selection...\n");
1881   check (EMS);
1882   trace (" ... with NOSEL\n");
1883   check (EMS_NS);
1884 
1885   check_item_height();
1886   test_ownerdraw();
1887   test_LB_SELITEMRANGE();
1888   test_LB_SETCURSEL();
1889   test_listbox_height();
1890   test_itemfrompoint();
1891   test_listbox_item_data();
1892   test_listbox_LB_DIR();
1893   test_listbox_dlgdir();
1894   test_set_count();
1895   test_GetListBoxInfo();
1896   test_missing_lbuttonup();
1897   test_extents();
1898 }
1899