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