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 <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 
30 #include "wine/test.h"
31 
32 #ifdef VISIBLE
33 #define WAIT Sleep (1000)
34 #define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW)
35 #else
36 #define WAIT
37 #define REDRAW
38 #endif
39 
40 static const char * const strings[4] = {
41   "First added",
42   "Second added",
43   "Third added",
44   "Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters."
45 };
46 
47 static const char BAD_EXTENSION[] = "*.badtxt";
48 
49 static int strcmp_aw(LPCWSTR strw, const char *stra)
50 {
51     WCHAR buf[1024];
52 
53     if (!stra) return 1;
54     MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, ARRAY_SIZE(buf));
55     return lstrcmpW(strw, buf);
56 }
57 
58 static HWND
59 create_listbox (DWORD add_style, HWND parent)
60 {
61   HWND handle;
62   INT_PTR ctl_id=0;
63   if (parent)
64     ctl_id=1;
65   handle=CreateWindowA("LISTBOX", "TestList",
66                             (LBS_STANDARD & ~LBS_SORT) | add_style,
67                             0, 0, 100, 100,
68                             parent, (HMENU)ctl_id, NULL, 0);
69 
70   assert (handle);
71   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
72   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
73   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
74   SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
75 
76 #ifdef VISIBLE
77   ShowWindow (handle, SW_SHOW);
78 #endif
79   REDRAW;
80 
81   return handle;
82 }
83 
84 struct listbox_prop {
85   DWORD add_style;
86 };
87 
88 struct listbox_stat {
89   int selected, anchor, caret, selcount;
90 };
91 
92 struct listbox_test {
93   struct listbox_stat  init,  init_todo;
94   struct listbox_stat click, click_todo;
95   struct listbox_stat  step,  step_todo;
96   struct listbox_stat   sel,   sel_todo;
97 };
98 
99 static void
100 listbox_query (HWND handle, struct listbox_stat *results)
101 {
102   results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
103   results->anchor   = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
104   results->caret    = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
105   results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
106 }
107 
108 static void
109 buttonpress (HWND handle, WORD x, WORD y)
110 {
111   LPARAM lp=x+(y<<16);
112 
113   WAIT;
114   SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
115   SendMessageA(handle, WM_LBUTTONUP, 0, lp);
116   REDRAW;
117 }
118 
119 static void
120 keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
121 {
122   LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0);
123 
124   WAIT;
125   SendMessageA(handle, WM_KEYDOWN, keycode, lp);
126   SendMessageA(handle, WM_KEYUP  , keycode, lp | 0xc000000);
127   REDRAW;
128 }
129 
130 #define listbox_field_ok(t, s, f, got) \
131   ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
132       ": expected %d, got %d\n", style, t.s.f, got.f)
133 
134 #define listbox_todo_field_ok(t, s, f, got) \
135   todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
136 
137 #define listbox_ok(t, s, got) \
138   listbox_todo_field_ok(t, s, selected, got); \
139   listbox_todo_field_ok(t, s, anchor, got); \
140   listbox_todo_field_ok(t, s, caret, got); \
141   listbox_todo_field_ok(t, s, selcount, got)
142 
143 static void
144 check (DWORD style, const struct listbox_test test)
145 {
146   struct listbox_stat answer;
147   RECT second_item;
148   int i;
149   int res;
150   HWND hLB;
151 
152   hLB = create_listbox (style, 0);
153 
154   listbox_query (hLB, &answer);
155   listbox_ok (test, init, answer);
156 
157   SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
158   buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
159 
160   listbox_query (hLB, &answer);
161   listbox_ok (test, click, answer);
162 
163   keypress (hLB, VK_DOWN, 0x50, TRUE);
164 
165   listbox_query (hLB, &answer);
166   listbox_ok (test, step, answer);
167 
168   DestroyWindow (hLB);
169   hLB = create_listbox(style, 0);
170 
171   SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
172   listbox_query (hLB, &answer);
173   listbox_ok (test, sel, answer);
174 
175   for (i = 0; i < 4 && !(style & LBS_NODATA); i++) {
176 	DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
177 	CHAR *txt;
178 	WCHAR *txtw;
179 	int resA, resW;
180 
181 	txt = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, size+1);
182 	resA=SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
183         ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
184 
185 	txtw = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, 2*size+2);
186 	resW=SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
187 	ok(resA == resW, "Unexpected text length.\n");
188 	WideCharToMultiByte( CP_ACP, 0, txtw, -1, txt, size, NULL, NULL );
189         ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
190 
191 	HeapFree (GetProcessHeap(), 0, txtw);
192 	HeapFree (GetProcessHeap(), 0, txt);
193   }
194 
195   /* Confirm the count of items, and that an invalid delete does not remove anything */
196   res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
197   ok((res==4), "Expected 4 items, got %d\n", res);
198   res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
199   ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
200   res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
201   ok((res==LB_ERR), "Expected LB_ERR items, got %d\n", res);
202   res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
203   ok((res==4), "Expected 4 items, got %d\n", res);
204 
205   WAIT;
206   DestroyWindow (hLB);
207 }
208 
209 static void check_item_height(void)
210 {
211     HWND hLB;
212     HDC hdc;
213     HFONT font;
214     TEXTMETRICA tm;
215     INT itemHeight;
216 
217     hLB = create_listbox (0, 0);
218     ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
219     ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
220     ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
221     ReleaseDC( hLB, hdc);
222 
223     ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
224 
225     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
226     ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
227 
228     DestroyWindow (hLB);
229 
230     hLB = CreateWindowA("LISTBOX", "TestList", LBS_OWNERDRAWVARIABLE,
231                          0, 0, 100, 100, NULL, NULL, NULL, 0);
232     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
233     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
234     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
235     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
236     itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
237     ok(itemHeight == tm.tmHeight, "itemHeight %d\n", itemHeight);
238     DestroyWindow (hLB);
239 }
240 
241 static int got_selchange;
242 
243 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
244 {
245     switch (msg)
246     {
247     case WM_MEASUREITEM:
248     {
249         DWORD style = GetWindowLongA(GetWindow(hwnd, GW_CHILD), GWL_STYLE);
250         MEASUREITEMSTRUCT *mi = (void*)lparam;
251 
252         ok(wparam == mi->CtlID, "got wParam=%08lx, expected %08x\n", wparam, mi->CtlID);
253         ok(mi->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mi->CtlType);
254         ok(mi->CtlID == 1, "mi->CtlID = %u\n", mi->CtlID);
255         ok(mi->itemHeight, "mi->itemHeight = 0\n");
256 
257         if (mi->itemID > 4 || style & LBS_OWNERDRAWFIXED)
258             break;
259 
260         if (style & LBS_HASSTRINGS)
261         {
262             ok(!strcmp_aw((WCHAR*)mi->itemData, strings[mi->itemID]),
263                     "mi->itemData = %s (%d)\n", wine_dbgstr_w((WCHAR*)mi->itemData), mi->itemID);
264         }
265         else
266         {
267             ok((void*)mi->itemData == strings[mi->itemID],
268                     "mi->itemData = %08lx, expected %p\n", mi->itemData, strings[mi->itemID]);
269         }
270         break;
271     }
272     case WM_DRAWITEM:
273     {
274         RECT rc_item, rc_client, rc_clip;
275         DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
276 
277         trace("%p WM_DRAWITEM %08lx %08lx\n", hwnd, wparam, lparam);
278 
279         ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n",
280 			wparam, dis->CtlID);
281         ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
282 
283         GetClientRect(dis->hwndItem, &rc_client);
284         trace("hwndItem %p client rect %s\n", dis->hwndItem, wine_dbgstr_rect(&rc_client));
285         GetClipBox(dis->hDC, &rc_clip);
286         trace("clip rect %s\n", wine_dbgstr_rect(&rc_clip));
287         ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
288            "client rect of the listbox should be equal to the clip box,"
289            "or the clip box should be empty\n");
290 
291         trace("rcItem %s\n", wine_dbgstr_rect(&dis->rcItem));
292         SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
293         trace("item rect %s\n", wine_dbgstr_rect(&rc_item));
294         ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
295 
296         break;
297     }
298 
299     case WM_COMMAND:
300         if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
301         break;
302 
303     default:
304         break;
305     }
306 
307     return DefWindowProcA(hwnd, msg, wparam, lparam);
308 }
309 
310 static HWND create_parent( void )
311 {
312     WNDCLASSA cls;
313     HWND parent;
314     static ATOM class;
315 
316     if (!class)
317     {
318         cls.style = 0;
319         cls.lpfnWndProc = main_window_proc;
320         cls.cbClsExtra = 0;
321         cls.cbWndExtra = 0;
322         cls.hInstance = GetModuleHandleA(NULL);
323         cls.hIcon = 0;
324         cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
325         cls.hbrBackground = GetStockObject(WHITE_BRUSH);
326         cls.lpszMenuName = NULL;
327         cls.lpszClassName = "main_window_class";
328         class = RegisterClassA( &cls );
329     }
330 
331     parent = CreateWindowExA(0, "main_window_class", NULL,
332                             WS_POPUP | WS_VISIBLE,
333                             100, 100, 400, 400,
334                             GetDesktopWindow(), 0,
335                             GetModuleHandleA(NULL), NULL);
336     return parent;
337 }
338 
339 static void test_ownerdraw(void)
340 {
341     static const DWORD styles[] =
342     {
343         0,
344         LBS_NODATA
345     };
346     HWND parent, hLB;
347     INT ret;
348     RECT rc;
349     UINT i;
350 
351     parent = create_parent();
352     assert(parent);
353 
354     for (i = 0; i < ARRAY_SIZE(styles); i++)
355     {
356         hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent);
357         assert(hLB);
358 
359         SetForegroundWindow(hLB);
360         UpdateWindow(hLB);
361 
362         /* make height short enough */
363         SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
364         SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1,
365                      SWP_NOZORDER | SWP_NOMOVE);
366 
367         /* make 0 item invisible */
368         SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
369         ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
370         ok(ret == 1, "wrong top index %d\n", ret);
371 
372         SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
373         trace("item 0 rect %s\n", wine_dbgstr_rect(&rc));
374         ok(!IsRectEmpty(&rc), "empty item rect\n");
375         ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
376 
377         DestroyWindow(hLB);
378 
379         /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
380         hLB = CreateWindowA("listbox", "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i],
381             0, 0, 100, 100, NULL, NULL, NULL, 0);
382         ok(hLB != NULL, "last error 0x%08x\n", GetLastError());
383 
384         ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n");
385 
386         ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
387         ok(ret == 0, "Unexpected return value %d.\n", ret);
388         ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
389         ok(ret == 1, "Unexpected return value %d.\n", ret);
390 
391         ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
392         ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
393 
394         ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
395         ok(ret == 13, "Unexpected item height %d.\n", ret);
396 
397         ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
398         ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
399 
400         ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
401         ok(ret == 42, "Unexpected item height %d.\n", ret);
402 
403         ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
404         ok(ret == 42, "Unexpected item height %d.\n", ret);
405 
406         DestroyWindow (hLB);
407     }
408     DestroyWindow(parent);
409 }
410 
411 #define listbox_test_query(exp, got) \
412   ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
413   ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
414   ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
415   ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
416 
417 static void test_LB_SELITEMRANGE(void)
418 {
419     static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
420     static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
421     static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
422     static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
423     HWND hLB;
424     struct listbox_stat answer;
425     INT ret;
426 
427     trace("testing LB_SELITEMRANGE\n");
428 
429     hLB = create_listbox(LBS_EXTENDEDSEL, 0);
430     assert(hLB);
431 
432     listbox_query(hLB, &answer);
433     listbox_test_query(test_nosel, answer);
434 
435     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
436     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
437     listbox_query(hLB, &answer);
438     listbox_test_query(test_1, answer);
439 
440     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
441     listbox_query(hLB, &answer);
442     listbox_test_query(test_nosel, answer);
443 
444     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
445     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
446     listbox_query(hLB, &answer);
447     listbox_test_query(test_3, answer);
448 
449     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
450     listbox_query(hLB, &answer);
451     listbox_test_query(test_nosel, answer);
452 
453     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
454     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
455     listbox_query(hLB, &answer);
456     listbox_test_query(test_nosel, answer);
457 
458     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
459     listbox_query(hLB, &answer);
460     listbox_test_query(test_nosel, answer);
461 
462     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
463     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
464     listbox_query(hLB, &answer);
465     listbox_test_query(test_1, answer);
466 
467     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
468     listbox_query(hLB, &answer);
469     listbox_test_query(test_nosel, answer);
470 
471     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
472     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
473     listbox_query(hLB, &answer);
474     listbox_test_query(test_nosel, answer);
475 
476     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
477     listbox_query(hLB, &answer);
478     listbox_test_query(test_nosel, answer);
479 
480     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
481     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
482     listbox_query(hLB, &answer);
483     listbox_test_query(test_2, answer);
484 
485     SendMessageA(hLB, LB_SETSEL, FALSE, -1);
486     listbox_query(hLB, &answer);
487     listbox_test_query(test_nosel, answer);
488 
489     ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
490     ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
491     listbox_query(hLB, &answer);
492     listbox_test_query(test_2, answer);
493 
494     DestroyWindow(hLB);
495 }
496 
497 static void test_LB_SETCURSEL(void)
498 {
499     HWND parent, hLB;
500     INT ret;
501 
502     trace("testing LB_SETCURSEL\n");
503 
504     parent = create_parent();
505     assert(parent);
506 
507     hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
508     assert(hLB);
509 
510     SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
511 
512     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
513     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
514 
515     ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
516     ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
517     ret = GetScrollPos(hLB, SB_VERT);
518     ok(ret == 0, "expected vscroll 0, got %d\n", ret);
519 
520     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
521     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
522 
523     ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
524     ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
525     ret = GetScrollPos(hLB, SB_VERT);
526     ok(ret == 1, "expected vscroll 1, got %d\n", ret);
527 
528     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
529     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
530 
531     DestroyWindow(hLB);
532 
533     hLB = create_listbox(0, 0);
534     ok(hLB != NULL, "Failed to create ListBox window.\n");
535 
536     ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
537     ok(ret == 1, "Unexpected return value %d.\n", ret);
538 
539     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
540     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
541 
542     DestroyWindow(hLB);
543 
544     /* LBS_EXTENDEDSEL */
545     hLB = create_listbox(LBS_EXTENDEDSEL, 0);
546     ok(hLB != NULL, "Failed to create ListBox window.\n");
547 
548     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
549     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
550 
551     ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
552     ok(ret == -1, "Unexpected return value %d.\n", ret);
553 
554     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
555     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
556 
557     DestroyWindow(hLB);
558 
559     /* LBS_MULTIPLESEL */
560     hLB = create_listbox(LBS_MULTIPLESEL, 0);
561     ok(hLB != NULL, "Failed to create ListBox window.\n");
562 
563     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
564     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
565 
566     ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
567     ok(ret == -1, "Unexpected return value %d.\n", ret);
568 
569     ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
570     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
571 
572     DestroyWindow(hLB);
573 }
574 
575 static void test_LB_SETSEL(void)
576 {
577     HWND list;
578     int ret;
579 
580     /* LBS_EXTENDEDSEL */
581     list = create_listbox(LBS_EXTENDEDSEL, 0);
582     ok(list != NULL, "Failed to create ListBox window.\n");
583 
584     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
585     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
586 
587     ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
588     ok(ret == 0, "Unexpected return value %d.\n", ret);
589     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
590     ok(ret == 0, "Unexpected anchor index %d.\n", ret);
591 
592     ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
593     ok(ret == 0, "Unexpected return value %d.\n", ret);
594     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
595     ok(ret == 1, "Unexpected anchor index %d.\n", ret);
596 
597     ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
598     ok(ret == 0, "Unexpected return value %d.\n", ret);
599     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
600     ok(ret == 1, "Unexpected anchor index %d.\n", ret);
601 
602     DestroyWindow(list);
603 
604     /* LBS_MULTIPLESEL */
605     list = create_listbox(LBS_MULTIPLESEL, 0);
606     ok(list != NULL, "Failed to create ListBox window.\n");
607 
608     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
609     ok(ret == -1, "Unexpected anchor index %d.\n", ret);
610 
611     ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
612     ok(ret == 0, "Unexpected return value %d.\n", ret);
613     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
614     ok(ret == 0, "Unexpected anchor index %d.\n", ret);
615 
616     ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
617     ok(ret == 0, "Unexpected return value %d.\n", ret);
618     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
619     ok(ret == 1, "Unexpected anchor index %d.\n", ret);
620 
621     ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
622     ok(ret == 0, "Unexpected return value %d.\n", ret);
623     ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
624     ok(ret == 1, "Unexpected anchor index %d.\n", ret);
625 
626     DestroyWindow(list);
627 }
628 
629 static void test_listbox_height(void)
630 {
631     HWND hList;
632     int r, id;
633 
634     hList = CreateWindowA( "ListBox", "list test", 0,
635                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
636     ok( hList != NULL, "failed to create listbox\n");
637 
638     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
639     ok( id == 0, "item id wrong\n");
640 
641     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
642     ok( r == 0, "send message failed\n");
643 
644     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
645     ok( r == 20, "height wrong\n");
646 
647     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
648     ok( r == -1, "send message failed\n");
649 
650     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
651     ok( r == 20, "height wrong\n");
652 
653     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0x100, 0 ));
654     ok( r == -1, "send message failed\n");
655 
656     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
657     ok( r == 20, "height wrong\n");
658 
659     r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
660     ok( r == 0, "send message failed\n");
661 
662     r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
663     ok( r == 0xff, "height wrong\n");
664 
665     DestroyWindow( hList );
666 }
667 
668 static void test_changing_selection_styles(void)
669 {
670     static const DWORD styles[] =
671     {
672         0,
673         LBS_NODATA | LBS_OWNERDRAWFIXED
674     };
675     static const DWORD selstyles[] =
676     {
677         0,
678         LBS_MULTIPLESEL,
679         LBS_EXTENDEDSEL,
680         LBS_MULTIPLESEL | LBS_EXTENDEDSEL
681     };
682     static const LONG selexpect_single[]  = { 0, 0, 1 };
683     static const LONG selexpect_single2[] = { 1, 0, 0 };
684     static const LONG selexpect_multi[]   = { 1, 0, 1 };
685     static const LONG selexpect_multi2[]  = { 1, 1, 0 };
686 
687     HWND parent, listbox;
688     DWORD style;
689     LONG ret;
690     UINT i, j, k;
691 
692     parent = create_parent();
693     ok(parent != NULL, "Failed to create parent window.\n");
694     for (i = 0; i < ARRAY_SIZE(styles); i++)
695     {
696         /* Test if changing selection styles affects selection storage */
697         for (j = 0; j < ARRAY_SIZE(selstyles); j++)
698         {
699             LONG setcursel_expect, selitemrange_expect, getselcount_expect;
700             const LONG *selexpect;
701 
702             listbox = CreateWindowA("listbox", "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE,
703                                     0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
704             ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j);
705 
706             if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
707             {
708                 setcursel_expect = LB_ERR;
709                 selitemrange_expect = LB_OKAY;
710                 getselcount_expect = 2;
711                 selexpect = selexpect_multi;
712             }
713             else
714             {
715                 setcursel_expect = 2;
716                 selitemrange_expect = LB_ERR;
717                 getselcount_expect = LB_ERR;
718                 selexpect = selexpect_single;
719             }
720 
721             for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
722             {
723                 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x");
724                 ok(ret == k, "%u: Unexpected return value %d, expected %d.\n", j, ret, k);
725             }
726             ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
727             ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %d.\n", j, ret);
728 
729             /* Select items with different methods */
730             ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
731             ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
732             ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0));
733             ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
734             ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2));
735             ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
736 
737             /* Verify that the proper items are selected */
738             for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
739             {
740                 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
741                 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
742                     j, ret, selexpect[k]);
743             }
744 
745             /* Now change the selection style */
746             style = GetWindowLongA(listbox, GWL_STYLE);
747             ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j],
748                 "%u: unexpected window styles %#x.\n", j, style);
749             if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
750                 style &= ~selstyles[j];
751             else
752                 style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
753             SetWindowLongA(listbox, GWL_STYLE, style);
754             style = GetWindowLongA(listbox, GWL_STYLE);
755             ok(!(style & selstyles[j]), "%u: unexpected window styles %#x.\n", j, style);
756 
757             /* Verify that the same items are selected */
758             ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
759             ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
760                 j, getselcount_expect, ret);
761 
762             for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
763             {
764                 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
765                 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
766                     j, ret, selexpect[k]);
767             }
768 
769             /* Lastly see if we can still change the selection as before with old style */
770             if (setcursel_expect != LB_ERR) setcursel_expect = 0;
771             ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
772             ok(ret == setcursel_expect, "%u: Unexpected return value %d.\n", j, ret);
773             ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1));
774             ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
775             ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2));
776             ok(ret == selitemrange_expect, "%u: Unexpected return value %d.\n", j, ret);
777 
778             /* And verify the selections */
779             selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2;
780             ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
781             ok(ret == getselcount_expect, "%u: expected %d from LB_GETSELCOUNT, got %d\n",
782                 j, getselcount_expect, ret);
783 
784             for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
785             {
786                 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
787                 ok(ret == selexpect[k], "%u: Unexpected selection state %d, expected %d.\n",
788                     j, ret, selexpect[k]);
789             }
790 
791             DestroyWindow(listbox);
792         }
793     }
794     DestroyWindow(parent);
795 }
796 
797 static void test_itemfrompoint(void)
798 {
799     /* WS_POPUP is required in order to have a more accurate size calculation (
800        without caption). LBS_NOINTEGRALHEIGHT is required in order to test
801        behavior of partially-displayed item.
802      */
803     HWND hList = CreateWindowA( "ListBox", "list test",
804                                WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
805                                1, 1, 600, 100, NULL, NULL, NULL, NULL );
806     ULONG r, id;
807     RECT rc;
808 
809     /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
810     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
811     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
812 
813     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
814     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
815 
816     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
817     ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
818 
819     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
820     ok( id == 0, "item id wrong\n");
821     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
822     ok( id == 1, "item id wrong\n");
823 
824     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
825     ok( r == 0x1, "ret %x\n", r );
826 
827     r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
828     ok( r == 0x10001 || broken(r == 1), /* nt4 */
829         "ret %x\n", r );
830 
831     /* Resize control so that below assertions about sizes are valid */
832     r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
833     ok( r == 1, "ret %x\n", r);
834     r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
835     ok( r != 0, "ret %x\n", r);
836 
837     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
838     ok( id == 2, "item id wrong\n");
839     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
840     ok( id == 3, "item id wrong\n");
841     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
842     ok( id == 4, "item id wrong\n");
843     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
844     ok( id == 5, "item id wrong\n");
845     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
846     ok( id == 6, "item id wrong\n");
847     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
848     ok( id == 7, "item id wrong\n");
849 
850     /* Set the listbox up so that id 1 is at the top, this leaves 5
851        partially visible at the bottom and 6, 7 are invisible */
852 
853     SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
854     r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
855     ok( r == 1, "top %d\n", r);
856 
857     r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
858     ok( r == 1, "ret %x\n", r);
859     r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
860     ok( r == 0, "ret %x\n", r);
861 
862     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
863     ok( r == 1, "ret %x\n", r);
864 
865     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
866     ok( r == 0x10001 || broken(r == 1), /* nt4 */
867         "ret %x\n", r );
868 
869     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
870     ok( r == 0x10001 || broken(r == 1), /* nt4 */
871         "ret %x\n", r );
872 
873     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
874     ok( r == 0x10005 || broken(r == 5), /* nt4 */
875         "item %x\n", r );
876 
877     r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
878     ok( r == 0x10005 || broken(r == 5), /* nt4 */
879         "item %x\n", r );
880 
881     DestroyWindow( hList );
882 }
883 
884 static void test_listbox_item_data(void)
885 {
886     HWND hList;
887     int r, id;
888 
889     hList = CreateWindowA( "ListBox", "list test", 0,
890                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
891     ok( hList != NULL, "failed to create listbox\n");
892 
893     id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
894     ok( id == 0, "item id wrong\n");
895 
896     r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
897     ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
898 
899     r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
900     ok( r == 20, "get item data failed\n");
901 
902     DestroyWindow( hList );
903 }
904 
905 static void test_listbox_LB_DIR(void)
906 {
907     char path[MAX_PATH], curdir[MAX_PATH];
908     HWND hList;
909     int res, itemCount;
910     int itemCount_justFiles;
911     int itemCount_justDrives;
912     int itemCount_allFiles;
913     int itemCount_allDirs;
914     int i;
915     char pathBuffer[MAX_PATH];
916     char * p;
917     char driveletter;
918     const char *wildcard = "*";
919     HANDLE file;
920     BOOL ret;
921 
922     GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
923 
924     GetTempPathA(ARRAY_SIZE(path), path);
925     ret = SetCurrentDirectoryA(path);
926     ok(ret, "Failed to set current directory.\n");
927 
928     ret = CreateDirectoryA("lb_dir_test", NULL);
929     ok(ret, "Failed to create test directory.\n");
930 
931     file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
932     ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
933     CloseHandle( file );
934 
935     /* NOTE: for this test to succeed, there must be no subdirectories
936        under the current directory. In addition, there must be at least
937        one file that fits the wildcard w*.c . Normally, the test
938        directory itself satisfies both conditions.
939      */
940     hList = CreateWindowA( "ListBox", "list test", WS_VISIBLE|WS_POPUP,
941                           1, 1, 600, 100, NULL, NULL, NULL, NULL );
942     assert(hList);
943 
944     /* Test for standard usage */
945 
946     /* This should list all the files in the test directory. */
947     strcpy(pathBuffer, wildcard);
948     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
949     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
950     if (res == -1)  /* "*" wildcard doesn't work on win9x */
951     {
952         wildcard = "*.*";
953         strcpy(pathBuffer, wildcard);
954         res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
955     }
956     ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
957 
958     /* There should be some content in the listbox */
959     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
960     ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
961     itemCount_allFiles = itemCount;
962     ok(res + 1 == itemCount,
963         "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
964         itemCount - 1, res);
965 
966     /* This tests behavior when no files match the wildcard */
967     strcpy(pathBuffer, BAD_EXTENSION);
968     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
969     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
970     ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
971 
972     /* There should be NO content in the listbox */
973     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
974     ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
975 
976 
977     /* This should list all the w*.c files in the test directory
978      * As of this writing, this includes win.c, winstation.c, wsprintf.c
979      */
980     strcpy(pathBuffer, "w*.c");
981     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
982     res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
983     ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
984 
985     /* Path specification does NOT converted to uppercase */
986     ok (!strcmp(pathBuffer, "w*.c"),
987         "expected no change to pathBuffer, got %s\n", pathBuffer);
988 
989     /* There should be some content in the listbox */
990     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
991     ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
992     itemCount_justFiles = itemCount;
993     ok(res + 1 == itemCount,
994         "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
995         itemCount - 1, res);
996 
997     /* Every single item in the control should start with a w and end in .c */
998     for (i = 0; i < itemCount; i++) {
999         memset(pathBuffer, 0, MAX_PATH);
1000         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1001         p = pathBuffer + strlen(pathBuffer);
1002         ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1003             (*(p-1) == 'c' || *(p-1) == 'C') &&
1004             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1005     }
1006 
1007     /* Test DDL_DIRECTORY */
1008     strcpy(pathBuffer, wildcard);
1009     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1010     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1011     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
1012 
1013     /* There should be some content in the listbox.
1014      * All files plus "[..]"
1015      */
1016     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1017     itemCount_allDirs = itemCount - itemCount_allFiles;
1018     ok (itemCount > itemCount_allFiles,
1019         "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
1020         itemCount, itemCount_allFiles);
1021     ok(res + 1 == itemCount,
1022         "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
1023         itemCount - 1, res);
1024 
1025     /* This tests behavior when no files match the wildcard */
1026     strcpy(pathBuffer, BAD_EXTENSION);
1027     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1028     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1029     ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1030 
1031     /* There should be NO content in the listbox */
1032     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1033     ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1034 
1035 
1036     /* Test DDL_DIRECTORY */
1037     strcpy(pathBuffer, "w*.c");
1038     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1039     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1040     ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
1041 
1042     /* There should be some content in the listbox. Since the parent directory does not
1043      * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
1044      */
1045     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1046     ok (itemCount == itemCount_justFiles,
1047         "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
1048         itemCount, itemCount_justFiles);
1049     ok(res + 1 == itemCount,
1050         "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
1051         itemCount - 1, res);
1052 
1053     /* Every single item in the control should start with a w and end in .c. */
1054     for (i = 0; i < itemCount; i++) {
1055         memset(pathBuffer, 0, MAX_PATH);
1056         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1057         p = pathBuffer + strlen(pathBuffer);
1058         ok(
1059             ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1060             (*(p-1) == 'c' || *(p-1) == 'C') &&
1061             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1062     }
1063 
1064 
1065     /* Test DDL_DRIVES|DDL_EXCLUSIVE */
1066     strcpy(pathBuffer, wildcard);
1067     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1068     res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1069     ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *)  failed - 0x%08x\n", GetLastError());
1070 
1071     /* There should be some content in the listbox. In particular, there should
1072      * be at least one element before, since the string "[-c-]" should
1073      * have been added. Depending on the user setting, more drives might have
1074      * been added.
1075      */
1076     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1077     ok (itemCount >= 1,
1078         "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
1079         itemCount, 1);
1080     itemCount_justDrives = itemCount;
1081     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1082 
1083     /* Every single item in the control should fit the format [-c-] */
1084     for (i = 0; i < itemCount; i++) {
1085         memset(pathBuffer, 0, MAX_PATH);
1086         driveletter = '\0';
1087         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1088         ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1089         ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1090         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1091         if (!(driveletter >= 'a' && driveletter <= 'z')) {
1092             /* Correct after invalid entry is found */
1093             trace("removing count of invalid entry %s\n", pathBuffer);
1094             itemCount_justDrives--;
1095         }
1096     }
1097 
1098     /* This tests behavior when no files match the wildcard */
1099     strcpy(pathBuffer, BAD_EXTENSION);
1100     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1101     res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1102     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1103         BAD_EXTENSION, res, itemCount_justDrives -1);
1104 
1105     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1106     ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
1107         itemCount, itemCount_justDrives);
1108 
1109     trace("Files with w*.c: %d Mapped drives: %d Directories: 1\n",
1110         itemCount_justFiles, itemCount_justDrives);
1111 
1112     /* Test DDL_DRIVES. */
1113     strcpy(pathBuffer, wildcard);
1114     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1115     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1116     ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *)  failed - 0x%08x\n", GetLastError());
1117 
1118     /* There should be some content in the listbox. In particular, there should
1119      * be at least one element before, since the string "[-c-]" should
1120      * have been added. Depending on the user setting, more drives might have
1121      * been added.
1122      */
1123     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1124     ok (itemCount == itemCount_justDrives + itemCount_allFiles,
1125         "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
1126         itemCount, itemCount_justDrives + itemCount_allFiles);
1127     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
1128 
1129     /* This tests behavior when no files match the wildcard */
1130     strcpy(pathBuffer, BAD_EXTENSION);
1131     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1132     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1133     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
1134         BAD_EXTENSION, res, itemCount_justDrives -1);
1135 
1136     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1137     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1138 
1139 
1140     /* Test DDL_DRIVES. */
1141     strcpy(pathBuffer, "w*.c");
1142     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1143     res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1144     ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c)  failed - 0x%08x\n", GetLastError());
1145 
1146     /* There should be some content in the listbox. In particular, there should
1147      * be at least one element before, since the string "[-c-]" should
1148      * have been added. Depending on the user setting, more drives might have
1149      * been added.
1150      */
1151     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1152     ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1153         "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1154         itemCount, itemCount_justDrives + itemCount_justFiles);
1155     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1156 
1157     /* Every single item in the control should fit the format [-c-], or w*.c */
1158     for (i = 0; i < itemCount; i++) {
1159         memset(pathBuffer, 0, MAX_PATH);
1160         driveletter = '\0';
1161         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1162         p = pathBuffer + strlen(pathBuffer);
1163         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1164             ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1165             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1166         } else {
1167             ok(
1168                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1169                 (*(p-1) == 'c' || *(p-1) == 'C') &&
1170                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1171         }
1172     }
1173 
1174 
1175     /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1176     strcpy(pathBuffer, wildcard);
1177     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1178     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1179     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1180 
1181     /* There should be some content in the listbox. In particular, there should
1182      * be exactly the number of plain files, plus the number of mapped drives.
1183      */
1184     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1185     ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1186         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1187         itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1188     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1189 
1190     /* Every single item in the control should start with a w and end in .c,
1191      * except for the "[..]" string, which should appear exactly as it is,
1192      * and the mapped drives in the format "[-X-]".
1193      */
1194     for (i = 0; i < itemCount; i++) {
1195         memset(pathBuffer, 0, MAX_PATH);
1196         driveletter = '\0';
1197         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1198         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1199             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1200         }
1201     }
1202 
1203     /* This tests behavior when no files match the wildcard */
1204     strcpy(pathBuffer, BAD_EXTENSION);
1205     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1206     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1207     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1208         BAD_EXTENSION, res, itemCount_justDrives -1);
1209 
1210     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1211     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1212 
1213 
1214 
1215     /* Test DDL_DIRECTORY|DDL_DRIVES. */
1216     strcpy(pathBuffer, "w*.c");
1217     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1218     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1219     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1220 
1221     /* There should be some content in the listbox. In particular, there should
1222      * be exactly the number of plain files, plus the number of mapped drives.
1223      */
1224     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1225     ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1226         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1227         itemCount, itemCount_justFiles + itemCount_justDrives);
1228     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1229 
1230     /* Every single item in the control should start with a w and end in .c,
1231      * except the mapped drives in the format "[-X-]". The "[..]" directory
1232      * should not appear.
1233      */
1234     for (i = 0; i < itemCount; i++) {
1235         memset(pathBuffer, 0, MAX_PATH);
1236         driveletter = '\0';
1237         SendMessageA(hList, 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(
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 
1249     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1250     strcpy(pathBuffer, wildcard);
1251     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1252     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1253     ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
1254 
1255     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1256     ok (itemCount == itemCount_allDirs,
1257         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1258         itemCount, itemCount_allDirs);
1259     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1260 
1261     if (itemCount)
1262     {
1263         memset(pathBuffer, 0, MAX_PATH);
1264         SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1265         ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1266     }
1267 
1268     /* This tests behavior when no files match the wildcard */
1269     strcpy(pathBuffer, BAD_EXTENSION);
1270     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1271     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1272     ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1273         BAD_EXTENSION, res, -1);
1274 
1275     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1276     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1277 
1278 
1279     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1280     strcpy(pathBuffer, "w*.c");
1281     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1282     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1283     ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1284 
1285     /* There should be no elements, since "[..]" does not fit w*.c */
1286     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1287     ok (itemCount == 0,
1288         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1289         itemCount, 0);
1290 
1291     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1292     strcpy(pathBuffer, wildcard);
1293     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1294     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1295     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1296 
1297     /* There should be no plain files on the listbox */
1298     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1299     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1300         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1301         itemCount, itemCount_justDrives + itemCount_allDirs);
1302     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1303 
1304     for (i = 0; i < itemCount; i++) {
1305         memset(pathBuffer, 0, MAX_PATH);
1306         driveletter = '\0';
1307         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1308         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1309             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1310         } else {
1311             ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1312                 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1313         }
1314     }
1315 
1316     /* This tests behavior when no files match the wildcard */
1317     strcpy(pathBuffer, BAD_EXTENSION);
1318     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1319     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1320     ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1321         BAD_EXTENSION, res, itemCount_justDrives -1);
1322 
1323     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1324     ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1325 
1326     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1327     strcpy(pathBuffer, "w*.c");
1328     SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1329     res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1330     ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1331 
1332     /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1333     itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1334     ok (itemCount == itemCount_justDrives,
1335         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1336         itemCount, itemCount_justDrives);
1337     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1338 
1339     for (i = 0; i < itemCount; i++) {
1340         memset(pathBuffer, 0, MAX_PATH);
1341         driveletter = '\0';
1342         SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1343         ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1344         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1345     }
1346     DestroyWindow(hList);
1347 
1348     DeleteFileA( "wtest1.tmp.c" );
1349     RemoveDirectoryA("lb_dir_test");
1350 
1351     SetCurrentDirectoryA(curdir);
1352 }
1353 
1354 static HWND g_listBox;
1355 static HWND g_label;
1356 
1357 #define ID_TEST_LABEL    1001
1358 #define ID_TEST_LISTBOX  1002
1359 
1360 static BOOL on_listbox_container_create (HWND hwnd, LPCREATESTRUCTA lpcs)
1361 {
1362     g_label = CreateWindowA(
1363         "Static",
1364         "Contents of static control before DlgDirList.",
1365         WS_CHILD | WS_VISIBLE,
1366         10, 10, 512, 32,
1367         hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1368     if (!g_label) return FALSE;
1369     g_listBox = CreateWindowA(
1370         "ListBox",
1371         "DlgDirList test",
1372         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL,
1373         10, 60, 256, 256,
1374         hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1375     if (!g_listBox) return FALSE;
1376 
1377     return TRUE;
1378 }
1379 
1380 static LRESULT CALLBACK listbox_container_window_procA (
1381     HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1382 {
1383     LRESULT result = 0;
1384 
1385     switch (uiMsg) {
1386     case WM_DESTROY:
1387         PostQuitMessage(0);
1388         break;
1389     case WM_CREATE:
1390         result = on_listbox_container_create(hwnd, (LPCREATESTRUCTA) lParam)
1391             ? 0 : (LRESULT)-1;
1392         break;
1393     default:
1394         result = DefWindowProcA (hwnd, uiMsg, wParam, lParam);
1395         break;
1396     }
1397     return result;
1398 }
1399 
1400 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1401 {
1402     WNDCLASSA cls;
1403 
1404     cls.style = 0;
1405     cls.cbClsExtra = 0;
1406     cls.cbWndExtra = 0;
1407     cls.hInstance = hInst;
1408     cls.hIcon = NULL;
1409     cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1410     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1411     cls.lpszMenuName = NULL;
1412     cls.lpfnWndProc = listbox_container_window_procA;
1413     cls.lpszClassName = "ListboxContainerClass";
1414     if (!RegisterClassA (&cls)) return FALSE;
1415 
1416     return TRUE;
1417 }
1418 
1419 static void test_listbox_dlgdir(void)
1420 {
1421     HINSTANCE hInst;
1422     HWND hWnd;
1423     int res, itemCount;
1424     int itemCount_allDirs;
1425     int itemCount_justFiles;
1426     int itemCount_justDrives;
1427     int i;
1428     char pathBuffer[MAX_PATH];
1429     char itemBuffer[MAX_PATH];
1430     char tempBuffer[MAX_PATH];
1431     char * p;
1432     char driveletter;
1433     HANDLE file;
1434 
1435     file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1436     ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1437     CloseHandle( file );
1438 
1439     /* NOTE: for this test to succeed, there must be no subdirectories
1440        under the current directory. In addition, there must be at least
1441        one file that fits the wildcard w*.c . Normally, the test
1442        directory itself satisfies both conditions.
1443      */
1444 
1445     hInst = GetModuleHandleA(0);
1446     if (!RegisterListboxWindowClass(hInst)) assert(0);
1447     hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1448                     WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1449             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1450             NULL, NULL, hInst, 0);
1451     assert(hWnd);
1452 
1453     /* Test for standard usage */
1454 
1455     /* The following should be overwritten by the directory path */
1456     SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1457 
1458     /* This should list all the w*.c files in the test directory
1459      * As of this writing, this includes win.c, winstation.c, wsprintf.c
1460      */
1461     strcpy(pathBuffer, "w*.c");
1462     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1463     ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1464 
1465     /* Path specification gets converted to uppercase */
1466     ok (!strcmp(pathBuffer, "W*.C"),
1467         "expected conversion to uppercase, got %s\n", pathBuffer);
1468 
1469     /* Loaded path should have overwritten the label text */
1470     SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1471     trace("Static control after DlgDirList: %s\n", pathBuffer);
1472     ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1473 
1474     /* There should be some content in the listbox */
1475     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1476     ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1477     itemCount_justFiles = itemCount;
1478 
1479     /* Every single item in the control should start with a w and end in .c */
1480     for (i = 0; i < itemCount; i++) {
1481         memset(pathBuffer, 0, MAX_PATH);
1482         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1483         p = pathBuffer + strlen(pathBuffer);
1484         ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1485             (*(p-1) == 'c' || *(p-1) == 'C') &&
1486             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1487     }
1488 
1489     /* Test behavior when no files match the wildcard */
1490     strcpy(pathBuffer, BAD_EXTENSION);
1491     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1492     ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1493 
1494     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1495     ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1496 
1497     /* Test DDL_DIRECTORY */
1498     strcpy(pathBuffer, "w*.c");
1499     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1500         DDL_DIRECTORY);
1501     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1502 
1503     /* There should be some content in the listbox. In particular, there should
1504      * be exactly more elements than before, since the directories should
1505      * have been added.
1506      */
1507     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1508     itemCount_allDirs = itemCount - itemCount_justFiles;
1509     ok (itemCount >= itemCount_justFiles,
1510         "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1511         itemCount, itemCount_justFiles);
1512 
1513     /* Every single item in the control should start with a w and end in .c,
1514      * except for the "[..]" string, which should appear exactly as it is.
1515      */
1516     for (i = 0; i < itemCount; i++) {
1517         memset(pathBuffer, 0, MAX_PATH);
1518         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1519         p = pathBuffer + strlen(pathBuffer);
1520         ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1521             ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1522             (*(p-1) == 'c' || *(p-1) == 'C') &&
1523             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1524     }
1525 
1526     /* Test behavior when no files match the wildcard */
1527     strcpy(pathBuffer, BAD_EXTENSION);
1528     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1529         DDL_DIRECTORY);
1530     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1531 
1532     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1533     ok (itemCount == itemCount_allDirs,
1534         "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1535         itemCount_allDirs, itemCount);
1536     for (i = 0; i < itemCount; i++) {
1537         memset(pathBuffer, 0, MAX_PATH);
1538         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1539         ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1540             "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1541     }
1542 
1543 
1544     /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1545     strcpy(pathBuffer, "w*.c");
1546     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1547         DDL_DRIVES);
1548     ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1549 
1550     /* There should be some content in the listbox. In particular, there should
1551      * be at least one element before, since the string "[-c-]" should
1552      * have been added. Depending on the user setting, more drives might have
1553      * been added.
1554      */
1555     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1556     ok (itemCount >= 1,
1557         "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1558         itemCount, 1);
1559     itemCount_justDrives = itemCount;
1560 
1561     /* Every single item in the control should fit the format [-c-] */
1562     for (i = 0; i < itemCount; i++) {
1563         memset(pathBuffer, 0, MAX_PATH);
1564         driveletter = '\0';
1565         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1566         ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1567         ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1568         ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1569         if (!(driveletter >= 'a' && driveletter <= 'z')) {
1570             /* Correct after invalid entry is found */
1571             trace("removing count of invalid entry %s\n", pathBuffer);
1572             itemCount_justDrives--;
1573         }
1574     }
1575 
1576     /* Test behavior when no files match the wildcard */
1577     strcpy(pathBuffer, BAD_EXTENSION);
1578     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1579         DDL_DRIVES);
1580     ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1581 
1582     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1583     ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1584 
1585 
1586     /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1587     strcpy(pathBuffer, "w*.c");
1588     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1589         DDL_DIRECTORY|DDL_DRIVES);
1590     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1591 
1592     /* There should be some content in the listbox. In particular, there should
1593      * be exactly the number of plain files, plus the number of mapped drives,
1594      * plus one "[..]"
1595      */
1596     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1597     ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1598         "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1599         itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1600 
1601     /* Every single item in the control should start with a w and end in .c,
1602      * except for the "[..]" string, which should appear exactly as it is,
1603      * and the mapped drives in the format "[-X-]".
1604      */
1605     for (i = 0; i < itemCount; i++) {
1606         memset(pathBuffer, 0, MAX_PATH);
1607         driveletter = '\0';
1608         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1609         p = pathBuffer + strlen(pathBuffer);
1610         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1611             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1612         } else {
1613             ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1614                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1615                 (*(p-1) == 'c' || *(p-1) == 'C') &&
1616                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1617         }
1618     }
1619 
1620     /* Test behavior when no files match the wildcard */
1621     strcpy(pathBuffer, BAD_EXTENSION);
1622     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1623         DDL_DIRECTORY|DDL_DRIVES);
1624     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1625 
1626     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1627     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1628         "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1629         itemCount_justDrives + itemCount_allDirs, itemCount);
1630 
1631 
1632 
1633     /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1634     strcpy(pathBuffer, "w*.c");
1635     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1636         DDL_DIRECTORY|DDL_EXCLUSIVE);
1637     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1638 
1639     /* There should be exactly one element: "[..]" */
1640     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1641     ok (itemCount == itemCount_allDirs,
1642         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1643         itemCount, itemCount_allDirs);
1644 
1645     if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3)  /* there's no [..] in drive root */
1646     {
1647         memset(pathBuffer, 0, MAX_PATH);
1648         SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1649         ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1650     }
1651 
1652     /* Test behavior when no files match the wildcard */
1653     strcpy(pathBuffer, BAD_EXTENSION);
1654     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1655         DDL_DIRECTORY|DDL_EXCLUSIVE);
1656     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1657 
1658     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1659     ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1660 
1661 
1662     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1663     strcpy(pathBuffer, "w*.c");
1664     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1665         DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1666     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1667 
1668     /* There should be no plain files on the listbox */
1669     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1670     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1671         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1672         itemCount, itemCount_justDrives + itemCount_allDirs);
1673 
1674     for (i = 0; i < itemCount; i++) {
1675         memset(pathBuffer, 0, MAX_PATH);
1676         driveletter = '\0';
1677         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1678         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
1679             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1680         } else {
1681             ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1682                 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1683         }
1684     }
1685 
1686     /* Test behavior when no files match the wildcard */
1687     strcpy(pathBuffer, BAD_EXTENSION);
1688     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1689         DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1690     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1691 
1692     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1693     ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1694         "DlgDirList() incorrectly filled the listbox!\n");
1695 
1696     /* Now test DlgDirSelectEx() in normal operation */
1697     /* Fill with everything - drives, directory and all plain files. */
1698     strcpy(pathBuffer, "*");
1699     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL,
1700         DDL_DIRECTORY|DDL_DRIVES);
1701     ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1702 
1703     SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1704     memset(pathBuffer, 0, MAX_PATH);
1705     SetLastError(0xdeadbeef);
1706     res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1707     ok (GetLastError() == 0xdeadbeef,
1708         "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1709         GetLastError());
1710     ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1711     /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1712     /*
1713     ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1714     */
1715     /* Test proper drive/dir/file recognition */
1716     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1717     for (i = 0; i < itemCount; i++) {
1718         memset(itemBuffer, 0, MAX_PATH);
1719         memset(pathBuffer, 0, MAX_PATH);
1720         memset(tempBuffer, 0, MAX_PATH);
1721         driveletter = '\0';
1722         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1723         if (!strstr(itemBuffer, ".exe")) continue; // skip downloaded/generated files from other tests
1724         res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1725         ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1726         if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1727             /* Current item is a drive letter */
1728             SetLastError(0xdeadbeef);
1729             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1730             ok (GetLastError() == 0xdeadbeef,
1731                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1732                 i, GetLastError());
1733             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1734 
1735             /* For drive letters, DlgDirSelectEx tacks on a colon */
1736             ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1737                 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1738         } else if (itemBuffer[0] == '[') {
1739             /* Current item is the parent directory */
1740             SetLastError(0xdeadbeef);
1741             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1742             ok (GetLastError() == 0xdeadbeef,
1743                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1744                 i, GetLastError());
1745             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1746 
1747             /* For directories, DlgDirSelectEx tacks on a backslash */
1748             p = pathBuffer + strlen(pathBuffer);
1749             ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1750 
1751             tempBuffer[0] = '[';
1752             lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1753             strcat(tempBuffer, "]");
1754             ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1755         } else {
1756             /* Current item is a plain file */
1757             SetLastError(0xdeadbeef);
1758             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1759             ok (GetLastError() == 0xdeadbeef,
1760                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1761                 i, GetLastError());
1762             ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1763 
1764             /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1765              * for example, "Makefile", which gets reported as "Makefile."
1766              */
1767             strcpy(tempBuffer, itemBuffer);
1768             if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1769             ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1770         }
1771     }
1772 
1773     DeleteFileA( "wtest1.tmp.c" );
1774 
1775     /* Now test DlgDirSelectEx() in abnormal operation */
1776     /* Fill list with bogus entries, that look somewhat valid */
1777     SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1778     SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1779     SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1780     itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1781     for (i = 0; i < itemCount; i++) {
1782         memset(itemBuffer, 0, MAX_PATH);
1783         memset(pathBuffer, 0, MAX_PATH);
1784         memset(tempBuffer, 0, MAX_PATH);
1785         driveletter = '\0';
1786         SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1787         res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1788         ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1789         if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1) {
1790             /* Current item is a drive letter */
1791             SetLastError(0xdeadbeef);
1792             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1793             ok (GetLastError() == 0xdeadbeef,
1794                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1795                 i, GetLastError());
1796             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1797 
1798             /* For drive letters, DlgDirSelectEx tacks on a colon */
1799             ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1800                 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1801         } else if (itemBuffer[0] == '[') {
1802             /* Current item is the parent directory */
1803             SetLastError(0xdeadbeef);
1804             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1805             ok (GetLastError() == 0xdeadbeef,
1806                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1807                 i, GetLastError());
1808             ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1809 
1810             /* For directories, DlgDirSelectEx tacks on a backslash */
1811             p = pathBuffer + strlen(pathBuffer);
1812             ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1813 
1814             tempBuffer[0] = '[';
1815             lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1816             strcat(tempBuffer, "]");
1817             ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1818         } else {
1819             /* Current item is a plain file */
1820             SetLastError(0xdeadbeef);
1821             res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1822             ok (GetLastError() == 0xdeadbeef,
1823                "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1824                 i, GetLastError());
1825             ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1826 
1827             /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1828              * This affects for example, "Makefile", which gets reported as "Makefile."
1829              */
1830             strcpy(tempBuffer, itemBuffer);
1831             if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1832             ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1833         }
1834     }
1835 
1836     /* Test behavior when loading folders from root with and without wildcard */
1837     strcpy(pathBuffer, "C:\\");
1838     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1839     ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\ folders\n");
1840     ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1841        "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1842 
1843     strcpy(pathBuffer, "C:\\*");
1844     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1845     ok(res || broken(!res) /* NT4/W2K */, "DlgDirList failed to list C:\\* folders\n");
1846     ok(!strcmp(pathBuffer, "*") || broken(!res) /* NT4/W2K */,
1847        "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1848 
1849     /* Try loading files from an invalid folder */
1850     SetLastError(0xdeadbeef);
1851     strcpy(pathBuffer, "C:\\INVALID$$DIR");
1852     res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1853     ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1854     ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1855        "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1856 
1857     DestroyWindow(hWnd);
1858 }
1859 
1860 static void test_set_count( void )
1861 {
1862     static const DWORD styles[] =
1863     {
1864         LBS_OWNERDRAWFIXED,
1865         LBS_HASSTRINGS,
1866     };
1867     HWND parent, listbox;
1868     unsigned int i;
1869     LONG ret;
1870     RECT r;
1871 
1872     parent = create_parent();
1873     listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1874 
1875     UpdateWindow( listbox );
1876     GetUpdateRect( listbox, &r, TRUE );
1877     ok( IsRectEmpty( &r ), "got non-empty rect\n");
1878 
1879     ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1880     ok( ret == 0, "got %d\n", ret );
1881     ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1882     ok( ret == 100, "got %d\n", ret );
1883 
1884     GetUpdateRect( listbox, &r, TRUE );
1885     ok( !IsRectEmpty( &r ), "got empty rect\n");
1886 
1887     ValidateRect( listbox, NULL );
1888     GetUpdateRect( listbox, &r, TRUE );
1889     ok( IsRectEmpty( &r ), "got non-empty rect\n");
1890 
1891     ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1892     ok( ret == 0, "got %d\n", ret );
1893 
1894     GetUpdateRect( listbox, &r, TRUE );
1895     ok( !IsRectEmpty( &r ), "got empty rect\n");
1896 
1897     ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 );
1898     ok( ret == 0, "got %d\n", ret );
1899     ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1900     ok( ret == -5, "got %d\n", ret );
1901 
1902     DestroyWindow( listbox );
1903 
1904     for (i = 0; i < ARRAY_SIZE(styles); ++i)
1905     {
1906         listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
1907 
1908         SetLastError( 0xdeadbeef );
1909         ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1910         ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
1911         ok( GetLastError() == ERROR_SETCOUNT_ON_BAD_LB, "Unexpected error %d.\n", GetLastError() );
1912 
1913         DestroyWindow( listbox );
1914     }
1915 
1916     DestroyWindow( parent );
1917 }
1918 
1919 static DWORD (WINAPI *pGetListBoxInfo)(HWND);
1920 static int lb_getlistboxinfo;
1921 
1922 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1923 {
1924     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1925 
1926     if (message == LB_GETLISTBOXINFO)
1927         lb_getlistboxinfo++;
1928 
1929     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1930 }
1931 
1932 static void test_GetListBoxInfo(void)
1933 {
1934     HWND listbox, parent;
1935     WNDPROC oldproc;
1936     DWORD ret;
1937 
1938     pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetListBoxInfo");
1939 
1940     if (!pGetListBoxInfo)
1941     {
1942         win_skip("GetListBoxInfo() not available\n");
1943         return;
1944     }
1945 
1946     parent = create_parent();
1947     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1948 
1949     oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1950     SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1951 
1952     lb_getlistboxinfo = 0;
1953     ret = pGetListBoxInfo(listbox);
1954     ok(ret > 0, "got %d\n", ret);
1955 todo_wine
1956     ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo);
1957 
1958     DestroyWindow(listbox);
1959     DestroyWindow(parent);
1960 }
1961 
1962 static void test_init_storage( void )
1963 {
1964     static const DWORD styles[] =
1965     {
1966         LBS_HASSTRINGS,
1967         LBS_NODATA | LBS_OWNERDRAWFIXED,
1968     };
1969     HWND parent, listbox;
1970     LONG ret, items_size;
1971     int i, j;
1972 
1973     parent = create_parent();
1974     for (i = 0; i < ARRAY_SIZE(styles); i++)
1975     {
1976         listbox = CreateWindowA("listbox", "TestList", styles[i] | WS_CHILD,
1977                                 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
1978 
1979         items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0);
1980         ok(items_size >= 100, "expected at least 100, got %d\n", items_size);
1981 
1982         ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
1983         ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
1984 
1985         /* it doesn't grow since the space was already reserved */
1986         ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0);
1987         ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
1988 
1989         /* it doesn't shrink the reserved space */
1990         ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0);
1991         ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
1992 
1993         /* now populate almost all of it so it's not reserved anymore */
1994         if (styles[i] & LBS_NODATA)
1995         {
1996             ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0);
1997             ok(ret == 0, "unexpected return value %d\n", ret);
1998         }
1999         else
2000         {
2001             for (j = 0; j < items_size - 1; j++)
2002             {
2003                 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2004                 ok(ret == j, "expected %d, got %d\n", j, ret);
2005             }
2006         }
2007 
2008         /* we still have one more reserved slot, so it doesn't grow yet */
2009         ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2010         ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2011 
2012         /* fill the slot and check again, it should grow this time */
2013         ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2014         ok(ret == items_size - 1, "expected %d, got %d\n", items_size - 1, ret);
2015         ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
2016         ok(ret == items_size, "expected %d, got %d\n", items_size, ret);
2017         ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2018         ok(ret > items_size, "expected it to grow past %d, got %d\n", items_size, ret);
2019 
2020         DestroyWindow(listbox);
2021     }
2022     DestroyWindow(parent);
2023 }
2024 
2025 static void test_missing_lbuttonup( void )
2026 {
2027     HWND listbox, parent, capture;
2028 
2029     parent = create_parent();
2030     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2031 
2032     /* Send button down without a corresponding button up */
2033     SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10,10));
2034     capture = GetCapture();
2035     ok(capture == listbox, "got %p expected %p\n", capture, listbox);
2036 
2037     /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
2038     got_selchange = 0;
2039     SetFocus(NULL);
2040     capture = GetCapture();
2041     ok(capture == NULL, "got %p\n", capture);
2042     ok(got_selchange, "got %d\n", got_selchange);
2043 
2044     DestroyWindow(listbox);
2045     DestroyWindow(parent);
2046 }
2047 
2048 static void test_extents(void)
2049 {
2050     HWND listbox, parent;
2051     DWORD res;
2052     SCROLLINFO sinfo;
2053     BOOL br;
2054 
2055     parent = create_parent();
2056 
2057     listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2058 
2059     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2060     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2061 
2062     sinfo.cbSize = sizeof(sinfo);
2063     sinfo.fMask = SIF_RANGE;
2064     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2065     ok(br == TRUE, "GetScrollInfo failed\n");
2066     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2067     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2068     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2069         "List box should not have a horizontal scroll bar\n");
2070 
2071     /* horizontal extent < width */
2072     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2073 
2074     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2075     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2076 
2077     sinfo.cbSize = sizeof(sinfo);
2078     sinfo.fMask = SIF_RANGE;
2079     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2080     ok(br == TRUE, "GetScrollInfo failed\n");
2081     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2082     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2083     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2084         "List box should not have a horizontal scroll bar\n");
2085 
2086     /* horizontal extent > width */
2087     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2088 
2089     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2090     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2091 
2092     sinfo.cbSize = sizeof(sinfo);
2093     sinfo.fMask = SIF_RANGE;
2094     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2095     ok(br == TRUE, "GetScrollInfo failed\n");
2096     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2097     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2098     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2099         "List box should not have a horizontal scroll bar\n");
2100 
2101     DestroyWindow(listbox);
2102 
2103 
2104     listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
2105 
2106     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2107     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2108 
2109     sinfo.cbSize = sizeof(sinfo);
2110     sinfo.fMask = SIF_RANGE;
2111     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2112     ok(br == TRUE, "GetScrollInfo failed\n");
2113     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2114     ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2115     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2116         "List box should not have a horizontal scroll bar\n");
2117 
2118     /* horizontal extent < width */
2119     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2120 
2121     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2122     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2123 
2124     sinfo.cbSize = sizeof(sinfo);
2125     sinfo.fMask = SIF_RANGE;
2126     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2127     ok(br == TRUE, "GetScrollInfo failed\n");
2128     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2129     ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2130     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2131         "List box should not have a horizontal scroll bar\n");
2132 
2133     /* horizontal extent > width */
2134     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2135 
2136     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2137     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2138 
2139     sinfo.cbSize = sizeof(sinfo);
2140     sinfo.fMask = SIF_RANGE;
2141     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2142     ok(br == TRUE, "GetScrollInfo failed\n");
2143     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2144     ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2145     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2146         "List box should have a horizontal scroll bar\n");
2147 
2148     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2149 
2150     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2151     ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2152 
2153     sinfo.cbSize = sizeof(sinfo);
2154     sinfo.fMask = SIF_RANGE;
2155     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2156     ok(br == TRUE, "GetScrollInfo failed\n");
2157     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2158     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2159     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2160         "List box should not have a horizontal scroll bar\n");
2161 
2162     DestroyWindow(listbox);
2163 
2164 
2165     listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
2166 
2167     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2168     ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2169 
2170     sinfo.cbSize = sizeof(sinfo);
2171     sinfo.fMask = SIF_RANGE;
2172     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2173     ok(br == TRUE, "GetScrollInfo failed\n");
2174     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2175     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2176     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2177         "List box should have a horizontal scroll bar\n");
2178 
2179     /* horizontal extent < width */
2180     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2181 
2182     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2183     ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2184 
2185     sinfo.cbSize = sizeof(sinfo);
2186     sinfo.fMask = SIF_RANGE;
2187     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2188     ok(br == TRUE, "GetScrollInfo failed\n");
2189     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2190     ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2191     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2192         "List box should have a horizontal scroll bar\n");
2193 
2194     /* horizontal extent > width */
2195     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2196 
2197     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2198     ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2199 
2200     sinfo.cbSize = sizeof(sinfo);
2201     sinfo.fMask = SIF_RANGE;
2202     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2203     ok(br == TRUE, "GetScrollInfo failed\n");
2204     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2205     ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2206     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2207         "List box should have a horizontal scroll bar\n");
2208 
2209     SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2210 
2211     res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2212     ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2213 
2214     sinfo.cbSize = sizeof(sinfo);
2215     sinfo.fMask = SIF_RANGE;
2216     br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2217     ok(br == TRUE, "GetScrollInfo failed\n");
2218     ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2219     ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2220     ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2221         "List box should have a horizontal scroll bar\n");
2222 
2223     DestroyWindow(listbox);
2224 
2225     DestroyWindow(parent);
2226 }
2227 
2228 static void test_WM_MEASUREITEM(void)
2229 {
2230     HWND parent, listbox;
2231     LRESULT data;
2232 
2233     parent = create_parent();
2234     listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2235 
2236     data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2237     ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
2238     DestroyWindow(parent);
2239 
2240     parent = create_parent();
2241     listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2242 
2243     data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2244     ok(!data, "data = %08lx\n", data);
2245     DestroyWindow(parent);
2246 }
2247 
2248 static void test_LBS_NODATA(void)
2249 {
2250     static const DWORD invalid_styles[] =
2251     {
2252         0,
2253         LBS_OWNERDRAWVARIABLE,
2254         LBS_SORT,
2255         LBS_HASSTRINGS,
2256         LBS_OWNERDRAWFIXED | LBS_SORT,
2257         LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
2258     };
2259     static const UINT invalid_idx[] = { -2, 2 };
2260     static const UINT valid_idx[] = { 0, 1 };
2261     static const ULONG_PTR zero_data;
2262     HWND listbox, parent;
2263     unsigned int i;
2264     ULONG_PTR data;
2265     INT ret;
2266 
2267     listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
2268         0, 0, 100, 100, NULL, NULL, NULL, 0);
2269     ok(listbox != NULL, "Failed to create ListBox window.\n");
2270 
2271     ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2272     ok(ret == 0, "Unexpected return value %d.\n", ret);
2273     ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2274     ok(ret == 1, "Unexpected return value %d.\n", ret);
2275     ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
2276     ok(ret == 2, "Unexpected return value %d.\n", ret);
2277 
2278     /* Invalid indices. */
2279     for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
2280     {
2281         ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
2282         ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2283         ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
2284         ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2285         if (ret == LB_ERR)
2286         {
2287             ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
2288             ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2289         }
2290         ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
2291         ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2292     }
2293 
2294     /* Valid indices. */
2295     for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
2296     {
2297         ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
2298         ok(ret == TRUE, "Unexpected return value %d.\n", ret);
2299         ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
2300         ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2301 
2302         memset(&data, 0xee, sizeof(data));
2303         ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
2304         ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2305         ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
2306 
2307         ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
2308         ok(ret == 0, "Unexpected return value %d.\n", ret);
2309     }
2310 
2311     /* More messages that don't work with LBS_NODATA. */
2312     SetLastError(0xdeadbeef);
2313     ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0);
2314     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2315     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2316     SetLastError(0xdeadbeef);
2317     ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
2318     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2319     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2320     SetLastError(0xdeadbeef);
2321     ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0);
2322     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2323     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2324     SetLastError(0xdeadbeef);
2325     ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
2326     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2327     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2328     SetLastError(0xdeadbeef);
2329     ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0);
2330     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2331     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2332     SetLastError(0xdeadbeef);
2333     ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
2334     ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2335     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError should return 0x57, got 0x%X\n", GetLastError());
2336 
2337     DestroyWindow(listbox);
2338 
2339     /* Invalid window style combinations. */
2340     parent = create_parent();
2341     ok(parent != NULL, "Failed to create parent window.\n");
2342 
2343     for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
2344     {
2345         DWORD style;
2346 
2347         listbox = CreateWindowA("listbox", "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
2348                 0, 0, 100, 100, parent, (HMENU)1, NULL, 0);
2349         ok(listbox != NULL, "Failed to create a listbox.\n");
2350 
2351         style = GetWindowLongA(listbox, GWL_STYLE);
2352         ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style);
2353         ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
2354         ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
2355         DestroyWindow(listbox);
2356     }
2357 
2358     DestroyWindow(parent);
2359 }
2360 
2361 START_TEST(listbox)
2362 {
2363   const struct listbox_test SS =
2364 /*   {add_style} */
2365     {{LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
2366      {     1,      1,      1, LB_ERR}, {0,0,0,0},
2367      {     2,      2,      2, LB_ERR}, {0,0,0,0},
2368      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
2369 /* {selected, anchor,  caret, selcount}{TODO fields} */
2370   const struct listbox_test SS_NS =
2371     {{LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
2372      {     1,      1,      1, LB_ERR}, {0,0,0,0},
2373      {     2,      2,      2, LB_ERR}, {0,0,0,0},
2374      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
2375   const struct listbox_test MS =
2376     {{     0, LB_ERR,      0,      0}, {0,0,0,0},
2377      {     1,      1,      1,      1}, {0,0,0,0},
2378      {     2,      1,      2,      1}, {0,0,0,0},
2379      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
2380   const struct listbox_test MS_NS =
2381     {{LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
2382      {     1,      1,      1, LB_ERR}, {0,0,0,0},
2383      {     2,      2,      2, LB_ERR}, {0,0,0,0},
2384      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
2385   const struct listbox_test ES =
2386     {{     0, LB_ERR,      0,      0}, {0,0,0,0},
2387      {     1,      1,      1,      1}, {0,0,0,0},
2388      {     2,      2,      2,      1}, {0,0,0,0},
2389      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
2390   const struct listbox_test ES_NS =
2391     {{LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
2392      {     1,      1,      1, LB_ERR}, {0,0,0,0},
2393      {     2,      2,      2, LB_ERR}, {0,0,0,0},
2394      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
2395   const struct listbox_test EMS =
2396     {{     0, LB_ERR,      0,      0}, {0,0,0,0},
2397      {     1,      1,      1,      1}, {0,0,0,0},
2398      {     2,      2,      2,      1}, {0,0,0,0},
2399      {     0, LB_ERR,      0,      2}, {0,0,0,0}};
2400   const struct listbox_test EMS_NS =
2401     {{LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0},
2402      {     1,      1,      1, LB_ERR}, {0,0,0,0},
2403      {     2,      2,      2, LB_ERR}, {0,0,0,0},
2404      {LB_ERR, LB_ERR,      0, LB_ERR}, {0,0,0,0}};
2405 
2406   trace (" Testing single selection...\n");
2407   check (0, SS);
2408   trace (" ... with NOSEL\n");
2409   check (LBS_NOSEL, SS_NS);
2410   trace (" ... LBS_NODATA variant ...\n");
2411   check (LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
2412   trace (" ... with NOSEL\n");
2413   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
2414 
2415   trace (" Testing multiple selection...\n");
2416   check (LBS_MULTIPLESEL, MS);
2417   trace (" ... with NOSEL\n");
2418   check (LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2419   trace (" ... LBS_NODATA variant ...\n");
2420   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
2421   trace (" ... with NOSEL\n");
2422   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2423 
2424   trace (" Testing extended selection...\n");
2425   check (LBS_EXTENDEDSEL, ES);
2426   trace (" ... with NOSEL\n");
2427   check (LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2428   trace (" ... LBS_NODATA variant ...\n");
2429   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
2430   trace (" ... with NOSEL\n");
2431   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2432 
2433   trace (" Testing extended and multiple selection...\n");
2434   check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2435   trace (" ... with NOSEL\n");
2436   check (LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2437   trace (" ... LBS_NODATA variant ...\n");
2438   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2439   trace (" ... with NOSEL\n");
2440   check (LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2441 
2442   check_item_height();
2443   test_ownerdraw();
2444   test_LB_SELITEMRANGE();
2445   test_LB_SETCURSEL();
2446   test_listbox_height();
2447   test_changing_selection_styles();
2448   test_itemfrompoint();
2449   test_listbox_item_data();
2450   test_listbox_LB_DIR();
2451   test_listbox_dlgdir();
2452   test_set_count();
2453   test_init_storage();
2454   test_GetListBoxInfo();
2455   test_missing_lbuttonup();
2456   test_extents();
2457   test_WM_MEASUREITEM();
2458   test_LB_SETSEL();
2459   test_LBS_NODATA();
2460 }
2461