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