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