e7894839838a54f5fce468074d6ad1ab1eda58fa
[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_itemfrompoint(void)
788 {
789 /* WS_POPUP is required in order to have a more accurate size calculation (
790 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
791 behavior of partially-displayed item.
792 */
793 HWND hList = CreateWindowA( WC_LISTBOXA, "list test",
794 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
795 1, 1, 600, 100, NULL, NULL, NULL, NULL );
796 ULONG r, id;
797 RECT rc;
798
799 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
800 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
801
802 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
803 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
804
805 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
806 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
807
808 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
809 ok( id == 0, "item id wrong\n");
810 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
811 ok( id == 1, "item id wrong\n");
812
813 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
814 ok( r == 0x1, "ret %x\n", r );
815
816 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
817 ok( r == MAKELPARAM(1, 1), "Unexpected ret value %#x.\n", r );
818
819 /* Resize control so that below assertions about sizes are valid */
820 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
821 ok( r == 1, "ret %x\n", r);
822 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
823 ok( r != 0, "ret %x\n", r);
824
825 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
826 ok( id == 2, "item id wrong\n");
827 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
828 ok( id == 3, "item id wrong\n");
829 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
830 ok( id == 4, "item id wrong\n");
831 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
832 ok( id == 5, "item id wrong\n");
833 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
834 ok( id == 6, "item id wrong\n");
835 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
836 ok( id == 7, "item id wrong\n");
837
838 /* Set the listbox up so that id 1 is at the top, this leaves 5
839 partially visible at the bottom and 6, 7 are invisible */
840
841 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
842 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
843 ok( r == 1, "top %d\n", r);
844
845 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
846 ok( r == 1, "ret %x\n", r);
847 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
848 ok( r == 0, "ret %x\n", r);
849
850 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
851 ok( r == 1, "ret %x\n", r);
852
853 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
854 ok( r == 0x10001, "ret %x\n", r );
855
856 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
857 ok( r == 0x10001, "ret %x\n", r );
858
859 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
860 ok( r == 0x10005, "item %x\n", r );
861
862 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
863 ok( r == 0x10005, "item %x\n", r );
864
865 DestroyWindow( hList );
866 }
867
868 static void test_listbox_item_data(void)
869 {
870 HWND hList;
871 int r, id;
872
873 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
874 1, 1, 600, 100, NULL, NULL, NULL, NULL );
875 ok( hList != NULL, "failed to create listbox\n");
876
877 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
878 ok( id == 0, "item id wrong\n");
879
880 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
881 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
882
883 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
884 ok( r == 20, "get item data failed\n");
885
886 DestroyWindow( hList );
887 }
888
889 static void test_listbox_LB_DIR(void)
890 {
891 char path[MAX_PATH], curdir[MAX_PATH];
892 HWND hList;
893 int res, itemCount;
894 int itemCount_justFiles;
895 int itemCount_justDrives;
896 int itemCount_allFiles;
897 int itemCount_allDirs;
898 int i;
899 char pathBuffer[MAX_PATH];
900 char * p;
901 char driveletter;
902 const char *wildcard = "*";
903 HANDLE file;
904 BOOL ret;
905
906 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
907
908 GetTempPathA(ARRAY_SIZE(path), path);
909 ret = SetCurrentDirectoryA(path);
910 ok(ret, "Failed to set current directory.\n");
911
912 ret = CreateDirectoryA("lb_dir_test", NULL);
913 ok(ret, "Failed to create test directory.\n");
914
915 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
916 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
917 CloseHandle( file );
918
919 /* NOTE: for this test to succeed, there must be no subdirectories
920 under the current directory. In addition, there must be at least
921 one file that fits the wildcard w*.c . Normally, the test
922 directory itself satisfies both conditions.
923 */
924 hList = CreateWindowA( WC_LISTBOXA, "list test", WS_VISIBLE|WS_POPUP,
925 1, 1, 600, 100, NULL, NULL, NULL, NULL );
926 ok(hList != NULL, "Failed to create listbox window.\n");
927
928 /* Test for standard usage */
929
930 /* This should list all the files in the test directory. */
931 strcpy(pathBuffer, wildcard);
932 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
933 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
934 if (res == -1) /* "*" wildcard doesn't work on win9x */
935 {
936 wildcard = "*.*";
937 strcpy(pathBuffer, wildcard);
938 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
939 }
940 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
941
942 /* There should be some content in the listbox */
943 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
944 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
945 itemCount_allFiles = itemCount;
946 ok(res + 1 == itemCount,
947 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
948 itemCount - 1, res);
949
950 /* This tests behavior when no files match the wildcard */
951 strcpy(pathBuffer, BAD_EXTENSION);
952 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
953 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
954 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
955
956 /* There should be NO content in the listbox */
957 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
958 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
959
960
961 /* This should list all the w*.c files in the test directory
962 * As of this writing, this includes win.c, winstation.c, wsprintf.c
963 */
964 strcpy(pathBuffer, "w*.c");
965 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
966 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
967 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
968
969 /* Path specification does NOT converted to uppercase */
970 ok (!strcmp(pathBuffer, "w*.c"),
971 "expected no change to pathBuffer, got %s\n", pathBuffer);
972
973 /* There should be some content in the listbox */
974 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
975 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
976 itemCount_justFiles = itemCount;
977 ok(res + 1 == itemCount,
978 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
979 itemCount - 1, res);
980
981 /* Every single item in the control should start with a w and end in .c */
982 for (i = 0; i < itemCount; i++)
983 {
984 memset(pathBuffer, 0, MAX_PATH);
985 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
986 p = pathBuffer + strlen(pathBuffer);
987 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
988 (*(p-1) == 'c' || *(p-1) == 'C') &&
989 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
990 }
991
992 /* Test DDL_DIRECTORY */
993 strcpy(pathBuffer, wildcard);
994 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
995 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
996 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
997
998 /* There should be some content in the listbox.
999 * All files plus "[..]"
1000 */
1001 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1002 itemCount_allDirs = itemCount - itemCount_allFiles;
1003 ok (itemCount >= itemCount_allFiles,
1004 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
1005 itemCount, itemCount_allFiles);
1006 ok(res + 1 == itemCount,
1007 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
1008 itemCount - 1, res);
1009
1010 /* This tests behavior when no files match the wildcard */
1011 strcpy(pathBuffer, BAD_EXTENSION);
1012 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1013 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1014 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1015
1016 /* There should be NO content in the listbox */
1017 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1018 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1019
1020 /* Test DDL_DIRECTORY */
1021 strcpy(pathBuffer, "w*.c");
1022 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1023 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1024 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
1025
1026 /* There should be some content in the listbox. Since the parent directory does not
1027 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
1028 */
1029 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1030 ok (itemCount == itemCount_justFiles,
1031 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
1032 itemCount, itemCount_justFiles);
1033 ok(res + 1 == itemCount,
1034 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
1035 itemCount - 1, res);
1036
1037 /* Every single item in the control should start with a w and end in .c. */
1038 for (i = 0; i < itemCount; i++)
1039 {
1040 memset(pathBuffer, 0, MAX_PATH);
1041 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1042 p = pathBuffer + strlen(pathBuffer);
1043 ok(
1044 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1045 (*(p-1) == 'c' || *(p-1) == 'C') &&
1046 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1047 }
1048
1049 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
1050 strcpy(pathBuffer, wildcard);
1051 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1052 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1053 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
1054
1055 /* There should be some content in the listbox. In particular, there should
1056 * be at least one element before, since the string "[-c-]" should
1057 * have been added. Depending on the user setting, more drives might have
1058 * been added.
1059 */
1060 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1061 ok (itemCount >= 1,
1062 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
1063 itemCount, 1);
1064 itemCount_justDrives = itemCount;
1065 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1066
1067 /* Every single item in the control should fit the format [-c-] */
1068 for (i = 0; i < itemCount; i++)
1069 {
1070 memset(pathBuffer, 0, MAX_PATH);
1071 driveletter = '\0';
1072 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1073 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1074 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1075 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1076 if (!(driveletter >= 'a' && driveletter <= 'z'))
1077 {
1078 /* Correct after invalid entry is found */
1079 itemCount_justDrives--;
1080 }
1081 }
1082
1083 /* This tests behavior when no files match the wildcard */
1084 strcpy(pathBuffer, BAD_EXTENSION);
1085 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1086 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1087 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1088 BAD_EXTENSION, res, itemCount_justDrives -1);
1089
1090 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1091 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
1092 itemCount, itemCount_justDrives);
1093
1094 /* Test DDL_DRIVES. */
1095 strcpy(pathBuffer, wildcard);
1096 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1097 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1098 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1099
1100 /* There should be some content in the listbox. In particular, there should
1101 * be at least one element before, since the string "[-c-]" should
1102 * have been added. Depending on the user setting, more drives might have
1103 * been added.
1104 */
1105 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1106 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
1107 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
1108 itemCount, itemCount_justDrives + itemCount_allFiles);
1109 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
1110
1111 /* This tests behavior when no files match the wildcard */
1112 strcpy(pathBuffer, BAD_EXTENSION);
1113 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1114 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1115 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
1116 BAD_EXTENSION, res, itemCount_justDrives -1);
1117
1118 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1119 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1120
1121 /* Test DDL_DRIVES. */
1122 strcpy(pathBuffer, "w*.c");
1123 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1124 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1125 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1126
1127 /* There should be some content in the listbox. In particular, there should
1128 * be at least one element before, since the string "[-c-]" should
1129 * have been added. Depending on the user setting, more drives might have
1130 * been added.
1131 */
1132 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1133 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1134 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1135 itemCount, itemCount_justDrives + itemCount_justFiles);
1136 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1137
1138 /* Every single item in the control should fit the format [-c-], or w*.c */
1139 for (i = 0; i < itemCount; i++)
1140 {
1141 memset(pathBuffer, 0, MAX_PATH);
1142 driveletter = '\0';
1143 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1144 p = pathBuffer + strlen(pathBuffer);
1145 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1146 {
1147 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1148 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1149 }
1150 else
1151 {
1152 ok(
1153 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1154 (*(p-1) == 'c' || *(p-1) == 'C') &&
1155 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1156 }
1157 }
1158
1159 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1160 strcpy(pathBuffer, wildcard);
1161 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1162 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1163 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1164
1165 /* There should be some content in the listbox. In particular, there should
1166 * be exactly the number of plain files, plus the number of mapped drives.
1167 */
1168 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1169 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1170 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1171 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1172 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1173
1174 /* Every single item in the control should start with a w and end in .c,
1175 * except for the "[..]" string, which should appear exactly as it is,
1176 * and the mapped drives in the format "[-X-]".
1177 */
1178 for (i = 0; i < itemCount; i++)
1179 {
1180 memset(pathBuffer, 0, MAX_PATH);
1181 driveletter = '\0';
1182 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1183 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1184 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1185 }
1186
1187 /* This tests behavior when no files match the wildcard */
1188 strcpy(pathBuffer, BAD_EXTENSION);
1189 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1190 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1191 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1192 BAD_EXTENSION, res, itemCount_justDrives -1);
1193
1194 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1195 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1196
1197 /* Test DDL_DIRECTORY|DDL_DRIVES. */
1198 strcpy(pathBuffer, "w*.c");
1199 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1200 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1201 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1202
1203 /* There should be some content in the listbox. In particular, there should
1204 * be exactly the number of plain files, plus the number of mapped drives.
1205 */
1206 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1207 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1208 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1209 itemCount, itemCount_justFiles + itemCount_justDrives);
1210 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1211
1212 /* Every single item in the control should start with a w and end in .c,
1213 * except the mapped drives in the format "[-X-]". The "[..]" directory
1214 * should not appear.
1215 */
1216 for (i = 0; i < itemCount; i++)
1217 {
1218 memset(pathBuffer, 0, MAX_PATH);
1219 driveletter = '\0';
1220 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1221 p = pathBuffer + strlen(pathBuffer);
1222 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1223 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1224 else
1225 ok(
1226 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1227 (*(p-1) == 'c' || *(p-1) == 'C') &&
1228 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1229 }
1230
1231 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1232 strcpy(pathBuffer, wildcard);
1233 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1234 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1235 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n",
1236 GetLastError());
1237
1238 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1239 ok (itemCount == itemCount_allDirs,
1240 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1241 itemCount, itemCount_allDirs);
1242 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1243
1244 if (itemCount)
1245 {
1246 memset(pathBuffer, 0, MAX_PATH);
1247 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1248 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1249 }
1250
1251 /* This tests behavior when no files match the wildcard */
1252 strcpy(pathBuffer, BAD_EXTENSION);
1253 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1254 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1255 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1256 BAD_EXTENSION, res, -1);
1257
1258 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1259 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1260
1261
1262 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1263 strcpy(pathBuffer, "w*.c");
1264 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1265 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1266 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1267
1268 /* There should be no elements, since "[..]" does not fit w*.c */
1269 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1270 ok (itemCount == 0,
1271 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1272 itemCount, 0);
1273
1274 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1275 strcpy(pathBuffer, wildcard);
1276 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1277 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1278 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1279
1280 /* There should be no plain files on the listbox */
1281 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1282 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1283 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1284 itemCount, itemCount_justDrives + itemCount_allDirs);
1285 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1286
1287 for (i = 0; i < itemCount; i++)
1288 {
1289 memset(pathBuffer, 0, MAX_PATH);
1290 driveletter = '\0';
1291 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1292 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1293 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1294 else
1295 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1296 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1297 }
1298
1299 /* This tests behavior when no files match the wildcard */
1300 strcpy(pathBuffer, BAD_EXTENSION);
1301 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1302 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1303 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1304 BAD_EXTENSION, res, itemCount_justDrives -1);
1305
1306 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1307 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1308
1309 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1310 strcpy(pathBuffer, "w*.c");
1311 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1312 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1313 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1314
1315 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1316 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1317 ok (itemCount == itemCount_justDrives,
1318 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1319 itemCount, itemCount_justDrives);
1320 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1321
1322 for (i = 0; i < itemCount; i++)
1323 {
1324 memset(pathBuffer, 0, MAX_PATH);
1325 driveletter = '\0';
1326 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1327 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1328 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1329 }
1330 DestroyWindow(hList);
1331
1332 DeleteFileA( "wtest1.tmp.c" );
1333 RemoveDirectoryA("lb_dir_test");
1334
1335 SetCurrentDirectoryA(curdir);
1336 }
1337
1338 static HWND g_listBox;
1339 static HWND g_label;
1340
1341 #define ID_TEST_LABEL 1001
1342 #define ID_TEST_LISTBOX 1002
1343
1344 static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs)
1345 {
1346 g_label = CreateWindowA(WC_STATICA, "Contents of static control before DlgDirList.",
1347 WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1348 if (!g_label) return FALSE;
1349
1350 g_listBox = CreateWindowA(WC_LISTBOXA, "DlgDirList test",
1351 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256,
1352 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1353 if (!g_listBox) return FALSE;
1354
1355 return TRUE;
1356 }
1357
1358 static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1359 {
1360 LRESULT result = 0;
1361
1362 switch (uiMsg)
1363 {
1364 case WM_DESTROY:
1365 PostQuitMessage(0);
1366 break;
1367 case WM_CREATE:
1368 result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1;
1369 break;
1370 default:
1371 result = DefWindowProcA(hwnd, uiMsg, wParam, lParam);
1372 break;
1373 }
1374 return result;
1375 }
1376
1377 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1378 {
1379 WNDCLASSA cls;
1380
1381 cls.style = 0;
1382 cls.cbClsExtra = 0;
1383 cls.cbWndExtra = 0;
1384 cls.hInstance = hInst;
1385 cls.hIcon = NULL;
1386 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1387 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1388 cls.lpszMenuName = NULL;
1389 cls.lpfnWndProc = listbox_container_window_procA;
1390 cls.lpszClassName = "ListboxContainerClass";
1391 if (!RegisterClassA (&cls)) return FALSE;
1392
1393 return TRUE;
1394 }
1395
1396 static void test_listbox_dlgdir(void)
1397 {
1398 HINSTANCE hInst;
1399 HWND hWnd;
1400 int res, itemCount;
1401 int itemCount_allDirs;
1402 int itemCount_justFiles;
1403 int itemCount_justDrives;
1404 int i;
1405 char pathBuffer[MAX_PATH];
1406 char itemBuffer[MAX_PATH];
1407 char tempBuffer[MAX_PATH];
1408 char * p;
1409 char driveletter;
1410 HANDLE file;
1411 BOOL ret;
1412
1413 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1414 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1415 CloseHandle( file );
1416
1417 /* NOTE: for this test to succeed, there must be no subdirectories
1418 under the current directory. In addition, there must be at least
1419 one file that fits the wildcard w*.c . Normally, the test
1420 directory itself satisfies both conditions.
1421 */
1422
1423 hInst = GetModuleHandleA(0);
1424 ret = RegisterListboxWindowClass(hInst);
1425 ok(ret, "Failed to register test class.\n");
1426
1427 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1428 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1429 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1430 NULL, NULL, hInst, 0);
1431 ok(hWnd != NULL, "Failed to create container window.\n");
1432
1433 /* Test for standard usage */
1434
1435 /* The following should be overwritten by the directory path */
1436 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1437
1438 /* This should list all the w*.c files in the test directory
1439 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1440 */
1441 strcpy(pathBuffer, "w*.c");
1442 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1443 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1444
1445 /* Path specification gets converted to uppercase */
1446 ok (!strcmp(pathBuffer, "W*.C"),
1447 "expected conversion to uppercase, got %s\n", pathBuffer);
1448
1449 /* Loaded path should have overwritten the label text */
1450 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1451 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1452
1453 /* There should be some content in the listbox */
1454 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1455 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1456 itemCount_justFiles = itemCount;
1457
1458 /* Every single item in the control should start with a w and end in .c */
1459 for (i = 0; i < itemCount; i++)
1460 {
1461 memset(pathBuffer, 0, MAX_PATH);
1462 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1463 p = pathBuffer + strlen(pathBuffer);
1464 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1465 (*(p-1) == 'c' || *(p-1) == 'C') &&
1466 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1467 }
1468
1469 /* Test behavior when no files match the wildcard */
1470 strcpy(pathBuffer, BAD_EXTENSION);
1471 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1472 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1473
1474 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1475 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1476
1477 /* Test DDL_DIRECTORY */
1478 strcpy(pathBuffer, "w*.c");
1479 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1480 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1481
1482 /* There should be some content in the listbox. In particular, there should
1483 * be exactly more elements than before, since the directories should
1484 * have been added.
1485 */
1486 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1487 itemCount_allDirs = itemCount - itemCount_justFiles;
1488 ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1489 itemCount, itemCount_justFiles);
1490
1491 /* Every single item in the control should start with a w and end in .c,
1492 * except for the "[..]" string, which should appear exactly as it is.
1493 */
1494 for (i = 0; i < itemCount; i++)
1495 {
1496 memset(pathBuffer, 0, MAX_PATH);
1497 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1498 p = pathBuffer + strlen(pathBuffer);
1499 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1500 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1501 (*(p-1) == 'c' || *(p-1) == 'C') &&
1502 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1503 }
1504
1505 /* Test behavior when no files match the wildcard */
1506 strcpy(pathBuffer, BAD_EXTENSION);
1507 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1508 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1509
1510 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1511 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1512 itemCount_allDirs, itemCount);
1513 for (i = 0; i < itemCount; i++)
1514 {
1515 memset(pathBuffer, 0, MAX_PATH);
1516 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1517 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1518 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1519 }
1520
1521 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1522 strcpy(pathBuffer, "w*.c");
1523 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1524 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1525
1526 /* There should be some content in the listbox. In particular, there should
1527 * be at least one element before, since the string "[-c-]" should
1528 * have been added. Depending on the user setting, more drives might have
1529 * been added.
1530 */
1531 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1532 ok (itemCount >= 1,
1533 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1534 itemCount, 1);
1535 itemCount_justDrives = itemCount;
1536
1537 /* Every single item in the control should fit the format [-c-] */
1538 for (i = 0; i < itemCount; i++)
1539 {
1540 memset(pathBuffer, 0, MAX_PATH);
1541 driveletter = '\0';
1542 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1543 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1544 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1545 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1546 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1547 /* Correct after invalid entry is found */
1548 trace("removing count of invalid entry %s\n", pathBuffer);
1549 itemCount_justDrives--;
1550 }
1551 }
1552
1553 /* Test behavior when no files match the wildcard */
1554 strcpy(pathBuffer, BAD_EXTENSION);
1555 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1556 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1557
1558 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1559 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1560
1561 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1562 strcpy(pathBuffer, "w*.c");
1563 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1564 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1565
1566 /* There should be some content in the listbox. In particular, there should
1567 * be exactly the number of plain files, plus the number of mapped drives,
1568 * plus one "[..]"
1569 */
1570 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1571 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1572 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1573 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1574
1575 /* Every single item in the control should start with a w and end in .c,
1576 * except for the "[..]" string, which should appear exactly as it is,
1577 * and the mapped drives in the format "[-X-]".
1578 */
1579 for (i = 0; i < itemCount; i++)
1580 {
1581 memset(pathBuffer, 0, MAX_PATH);
1582 driveletter = '\0';
1583 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1584 p = pathBuffer + strlen(pathBuffer);
1585 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1586 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1587 else
1588 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1589 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1590 (*(p-1) == 'c' || *(p-1) == 'C') &&
1591 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1592 }
1593
1594 /* Test behavior when no files match the wildcard */
1595 strcpy(pathBuffer, BAD_EXTENSION);
1596 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1597 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1598
1599 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1600 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1601 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1602 itemCount_justDrives + itemCount_allDirs, itemCount);
1603
1604 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1605 strcpy(pathBuffer, "w*.c");
1606 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1607 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1608
1609 /* There should be exactly one element: "[..]" */
1610 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1611 ok (itemCount == itemCount_allDirs,
1612 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1613 itemCount, itemCount_allDirs);
1614
1615 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1616 {
1617 memset(pathBuffer, 0, MAX_PATH);
1618 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1619 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1620 }
1621
1622 /* Test behavior when no files match the wildcard */
1623 strcpy(pathBuffer, BAD_EXTENSION);
1624 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1625 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1626
1627 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1628 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1629
1630 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1631 strcpy(pathBuffer, "w*.c");
1632 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1633 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1634
1635 /* There should be no plain files on the listbox */
1636 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1637 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1638 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1639 itemCount, itemCount_justDrives + itemCount_allDirs);
1640
1641 for (i = 0; i < itemCount; i++)
1642 {
1643 memset(pathBuffer, 0, MAX_PATH);
1644 driveletter = '\0';
1645 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1646 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1647 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1648 else
1649 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1650 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1651 }
1652
1653 /* Test behavior when no files match the wildcard */
1654 strcpy(pathBuffer, BAD_EXTENSION);
1655 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1656 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1657
1658 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1659 ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1660
1661 /* Now test DlgDirSelectEx() in normal operation */
1662 /* Fill with everything - drives, directory and all plain files. */
1663 strcpy(pathBuffer, "*");
1664 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1665 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1666
1667 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1668 memset(pathBuffer, 0, MAX_PATH);
1669 SetLastError(0xdeadbeef);
1670 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1671 ok (GetLastError() == 0xdeadbeef,
1672 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1673 GetLastError());
1674 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1675 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1676 /*
1677 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1678 */
1679 /* Test proper drive/dir/file recognition */
1680 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1681 for (i = 0; i < itemCount; i++)
1682 {
1683 memset(itemBuffer, 0, MAX_PATH);
1684 memset(pathBuffer, 0, MAX_PATH);
1685 memset(tempBuffer, 0, MAX_PATH);
1686 driveletter = '\0';
1687 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1688 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1689 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1690 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1691 {
1692 /* Current item is a drive letter */
1693 SetLastError(0xdeadbeef);
1694 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1695 ok (GetLastError() == 0xdeadbeef,
1696 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1697 i, GetLastError());
1698 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1699
1700 /* For drive letters, DlgDirSelectEx tacks on a colon */
1701 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1702 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1703 }
1704 else if (itemBuffer[0] == '[')
1705 {
1706 /* Current item is the parent directory */
1707 SetLastError(0xdeadbeef);
1708 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1709 ok (GetLastError() == 0xdeadbeef,
1710 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1711 i, GetLastError());
1712 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1713
1714 /* For directories, DlgDirSelectEx tacks on a backslash */
1715 p = pathBuffer + strlen(pathBuffer);
1716 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1717
1718 tempBuffer[0] = '[';
1719 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1720 strcat(tempBuffer, "]");
1721 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1722 }
1723 else
1724 {
1725 /* Current item is a plain file */
1726 SetLastError(0xdeadbeef);
1727 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1728 ok (GetLastError() == 0xdeadbeef,
1729 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1730 i, GetLastError());
1731 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1732
1733 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1734 * for example, "Makefile", which gets reported as "Makefile."
1735 */
1736 strcpy(tempBuffer, itemBuffer);
1737 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1738 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1739 }
1740 }
1741
1742 DeleteFileA( "wtest1.tmp.c" );
1743
1744 /* Now test DlgDirSelectEx() in abnormal operation */
1745 /* Fill list with bogus entries, that look somewhat valid */
1746 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1747 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1748 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1749 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1750 for (i = 0; i < itemCount; i++)
1751 {
1752 memset(itemBuffer, 0, MAX_PATH);
1753 memset(pathBuffer, 0, MAX_PATH);
1754 memset(tempBuffer, 0, MAX_PATH);
1755 driveletter = '\0';
1756 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1757 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1758 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1759 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1760 {
1761 /* Current item is a drive letter */
1762 SetLastError(0xdeadbeef);
1763 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1764 ok (GetLastError() == 0xdeadbeef,
1765 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1766 i, GetLastError());
1767 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1768
1769 /* For drive letters, DlgDirSelectEx tacks on a colon */
1770 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1771 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1772 }
1773 else if (itemBuffer[0] == '[')
1774 {
1775 /* Current item is the parent directory */
1776 SetLastError(0xdeadbeef);
1777 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1778 ok (GetLastError() == 0xdeadbeef,
1779 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1780 i, GetLastError());
1781 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1782
1783 /* For directories, DlgDirSelectEx tacks on a backslash */
1784 p = pathBuffer + strlen(pathBuffer);
1785 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1786
1787 tempBuffer[0] = '[';
1788 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1789 strcat(tempBuffer, "]");
1790 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1791 }
1792 else
1793 {
1794 /* Current item is a plain file */
1795 SetLastError(0xdeadbeef);
1796 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1797 ok (GetLastError() == 0xdeadbeef,
1798 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1799 i, GetLastError());
1800 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1801
1802 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1803 * This affects for example, "Makefile", which gets reported as "Makefile."
1804 */
1805 strcpy(tempBuffer, itemBuffer);
1806 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1807 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1808 }
1809 }
1810
1811 /* Test behavior when loading folders from root with and without wildcard */
1812 strcpy(pathBuffer, "C:\\");
1813 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1814 ok(res, "DlgDirList failed to list C:\\ folders\n");
1815 todo_wine ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1816
1817 strcpy(pathBuffer, "C:\\*");
1818 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1819 ok(res, "DlgDirList failed to list C:\\* folders\n");
1820 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1821
1822 /* Try loading files from an invalid folder */
1823 SetLastError(0xdeadbeef);
1824 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1825 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1826 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1827 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1828 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1829
1830 DestroyWindow(hWnd);
1831 }
1832
1833 static void test_set_count( void )
1834 {
1835 static const DWORD styles[] =
1836 {
1837 LBS_OWNERDRAWFIXED,
1838 LBS_HASSTRINGS,
1839 };
1840 HWND parent, listbox;
1841 unsigned int i;
1842 LONG ret;
1843 RECT r;
1844
1845 parent = create_parent();
1846 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1847
1848 UpdateWindow( listbox );
1849 GetUpdateRect( listbox, &r, TRUE );
1850 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1851
1852 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1853 ok( ret == 0, "got %d\n", ret );
1854 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1855 ok( ret == 100, "got %d\n", ret );
1856
1857 GetUpdateRect( listbox, &r, TRUE );
1858 ok( !IsRectEmpty( &r ), "got empty rect\n");
1859
1860 ValidateRect( listbox, NULL );
1861 GetUpdateRect( listbox, &r, TRUE );
1862 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1863
1864 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1865 ok( ret == 0, "got %d\n", ret );
1866
1867 GetUpdateRect( listbox, &r, TRUE );
1868 ok( !IsRectEmpty( &r ), "got empty rect\n");
1869
1870 DestroyWindow( listbox );
1871
1872 for (i = 0; i < ARRAY_SIZE(styles); ++i)
1873 {
1874 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
1875
1876 SetLastError( 0xdeadbeef );
1877 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1878 ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
1879 ok( GetLastError() == 0xdeadbeef, "Unexpected error %d.\n", GetLastError() );
1880
1881 DestroyWindow( listbox );
1882 }
1883
1884 DestroyWindow( parent );
1885 }
1886
1887 static void test_GetListBoxInfo(void)
1888 {
1889 static const struct message getlistboxinfo_seq[] =
1890 {
1891 { LB_GETLISTBOXINFO, sent },
1892 { 0 }
1893 };
1894 HWND listbox, parent;
1895 DWORD ret;
1896
1897 parent = create_parent();
1898 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1899
1900 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1901 ret = GetListBoxInfo(listbox);
1902 ok(ret > 0, "got %d\n", ret);
1903 ok_sequence(sequences, LB_SEQ_INDEX, getlistboxinfo_seq, "GetListBoxInfo()", FALSE);
1904
1905 DestroyWindow(listbox);
1906 DestroyWindow(parent);
1907 }
1908
1909 static void test_missing_lbuttonup(void)
1910 {
1911 HWND listbox, parent, capture;
1912
1913 parent = create_parent();
1914 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1915
1916 /* Send button down without a corresponding button up */
1917 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10));
1918 capture = GetCapture();
1919 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1920
1921 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1922 got_selchange = 0;
1923 SetFocus(NULL);
1924 capture = GetCapture();
1925 ok(capture == NULL, "got %p\n", capture);
1926 ok(got_selchange, "got %d\n", got_selchange);
1927
1928 DestroyWindow(listbox);
1929 DestroyWindow(parent);
1930 }
1931
1932 static void test_extents(void)
1933 {
1934 HWND listbox, parent;
1935 SCROLLINFO sinfo;
1936 DWORD res;
1937 BOOL br;
1938
1939 parent = create_parent();
1940
1941 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1942
1943 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1944 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1945
1946 sinfo.cbSize = sizeof(sinfo);
1947 sinfo.fMask = SIF_RANGE;
1948 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1949 ok(br == TRUE, "GetScrollInfo failed\n");
1950 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1951 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1952 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1953 "List box should not have a horizontal scroll bar\n");
1954
1955 /* horizontal extent < width */
1956 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1957
1958 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1959 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1960
1961 sinfo.cbSize = sizeof(sinfo);
1962 sinfo.fMask = SIF_RANGE;
1963 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1964 ok(br == TRUE, "GetScrollInfo failed\n");
1965 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1966 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1967 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1968 "List box should not have a horizontal scroll bar\n");
1969
1970 /* horizontal extent > width */
1971 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1972
1973 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1974 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1975
1976 sinfo.cbSize = sizeof(sinfo);
1977 sinfo.fMask = SIF_RANGE;
1978 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1979 ok(br == TRUE, "GetScrollInfo failed\n");
1980 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1981 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1982 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1983 "List box should not have a horizontal scroll bar\n");
1984
1985 DestroyWindow(listbox);
1986
1987 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1988
1989 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1990 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1991
1992 sinfo.cbSize = sizeof(sinfo);
1993 sinfo.fMask = SIF_RANGE;
1994 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1995 ok(br == TRUE, "GetScrollInfo failed\n");
1996 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1997 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1998 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1999 "List box should not have a horizontal scroll bar\n");
2000
2001 /* horizontal extent < width */
2002 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2003
2004 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2005 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2006
2007 sinfo.cbSize = sizeof(sinfo);
2008 sinfo.fMask = SIF_RANGE;
2009 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2010 ok(br == TRUE, "GetScrollInfo failed\n");
2011 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2012 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2013 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2014 "List box should not have a horizontal scroll bar\n");
2015
2016 /* horizontal extent > width */
2017 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2018
2019 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2020 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2021
2022 sinfo.cbSize = sizeof(sinfo);
2023 sinfo.fMask = SIF_RANGE;
2024 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2025 ok(br == TRUE, "GetScrollInfo failed\n");
2026 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2027 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2028 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2029 "List box should have a horizontal scroll bar\n");
2030
2031 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2032
2033 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2034 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2035
2036 sinfo.cbSize = sizeof(sinfo);
2037 sinfo.fMask = SIF_RANGE;
2038 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2039 ok(br == TRUE, "GetScrollInfo failed\n");
2040 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2041 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2042 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2043 "List box should not have a horizontal scroll bar\n");
2044
2045 DestroyWindow(listbox);
2046
2047
2048 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
2049
2050 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2051 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2052
2053 sinfo.cbSize = sizeof(sinfo);
2054 sinfo.fMask = SIF_RANGE;
2055 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2056 ok(br == TRUE, "GetScrollInfo failed\n");
2057 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2058 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2059 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2060 "List box should have a horizontal scroll bar\n");
2061
2062 /* horizontal extent < width */
2063 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2064
2065 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2066 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2067
2068 sinfo.cbSize = sizeof(sinfo);
2069 sinfo.fMask = SIF_RANGE;
2070 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2071 ok(br == TRUE, "GetScrollInfo failed\n");
2072 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2073 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2074 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2075 "List box should have a horizontal scroll bar\n");
2076
2077 /* horizontal extent > width */
2078 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2079
2080 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2081 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2082
2083 sinfo.cbSize = sizeof(sinfo);
2084 sinfo.fMask = SIF_RANGE;
2085 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2086 ok(br == TRUE, "GetScrollInfo failed\n");
2087 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2088 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2089 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2090 "List box should have a horizontal scroll bar\n");
2091
2092 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2093
2094 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2095 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2096
2097 sinfo.cbSize = sizeof(sinfo);
2098 sinfo.fMask = SIF_RANGE;
2099 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2100 ok(br == TRUE, "GetScrollInfo failed\n");
2101 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2102 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2103 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2104 "List box should have a horizontal scroll bar\n");
2105
2106 DestroyWindow(listbox);
2107
2108 DestroyWindow(parent);
2109 }
2110
2111 static void test_listbox(void)
2112 {
2113 static const struct listbox_test SS =
2114 /* {add_style} */
2115 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2116 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2117 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2118 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2119
2120 /* {selected, anchor, caret, selcount}{TODO fields} */
2121 static const struct listbox_test SS_NS =
2122 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2123 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2124 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2125 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2126
2127 static const struct listbox_test MS =
2128 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2129 { 1, 1, 1, 1}, {0,0,0,0},
2130 { 2, 1, 2, 1}, {0,0,0,0},
2131 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2132
2133 static const struct listbox_test MS_NS =
2134 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2135 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2136 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2137 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2138
2139 static const struct listbox_test ES =
2140 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2141 { 1, 1, 1, 1}, {0,0,0,0},
2142 { 2, 2, 2, 1}, {0,0,0,0},
2143 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2144
2145 static const struct listbox_test ES_NS =
2146 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2147 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2148 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2149 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2150
2151 static const struct listbox_test EMS =
2152 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2153 { 1, 1, 1, 1}, {0,0,0,0},
2154 { 2, 2, 2, 1}, {0,0,0,0},
2155 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2156
2157 static const struct listbox_test EMS_NS =
2158 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2159 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2160 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2161 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2162
2163 run_test(0, SS);
2164 run_test(LBS_NOSEL, SS_NS);
2165 run_test(LBS_MULTIPLESEL, MS);
2166 run_test(LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2167 run_test(LBS_EXTENDEDSEL, ES);
2168 run_test(LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2169 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2170 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2171
2172 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
2173 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
2174 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
2175 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2176 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
2177 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2178 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2179 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2180 }
2181
2182 static const struct message lb_addstring_ownerdraw_parent_seq[] =
2183 {
2184 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2185 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2186 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2187 { 0 }
2188 };
2189
2190 static const struct message lb_addstring_sort_parent_seq[] =
2191 {
2192 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2193 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
2194 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2195 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
2196 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
2197 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2198 { 0 }
2199 };
2200
2201 static const struct message empty_seq[] =
2202 {
2203 { 0 }
2204 };
2205
2206 static void test_WM_MEASUREITEM(void)
2207 {
2208 HWND parent, listbox;
2209 LRESULT data, ret;
2210
2211 parent = create_parent();
2212 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2213
2214 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2215 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
2216 DestroyWindow(parent);
2217
2218 parent = create_parent();
2219 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2220
2221 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2222 ok(!data, "data = %08lx\n", data);
2223
2224 /* LBS_HASSTRINGS */
2225 parent = create_parent();
2226 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2227 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
2228 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2229
2230 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2231
2232 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2233 ok(ret == 0, "expected 0, got %ld\n", ret);
2234 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2235 ok(ret == 1, "expected 1, got %ld\n", ret);
2236 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2237 ok(ret == 2, "expected 2, got %ld\n", ret);
2238
2239 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
2240 "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
2241 DestroyWindow(listbox);
2242
2243 /* LBS_SORT, no LBS_HASSTRINGS */
2244 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2245 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
2246 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2247
2248 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2249
2250 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2251 ok(ret == 0, "expected 0, got %ld\n", ret);
2252 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2253 ok(ret == 1, "expected 1, got %ld\n", ret);
2254 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2255 ok(ret == 2, "expected 2, got %ld\n", ret);
2256
2257 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", FALSE);
2258 DestroyWindow(listbox);
2259
2260 /* LBS_HASSTRINGS */
2261 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2262 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
2263 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2264
2265 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2266
2267 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2268 ok(ret == 0, "expected 0, got %ld\n", ret);
2269 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2270 ok(ret == 1, "expected 1, got %ld\n", ret);
2271 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2272 ok(ret == 2, "expected 2, got %ld\n", ret);
2273
2274 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
2275 DestroyWindow(listbox);
2276
2277 /* LBS_HASSTRINGS, LBS_SORT */
2278 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2279 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
2280 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2281
2282 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2283
2284 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2285 ok(ret == 0, "expected 0, got %ld\n", ret);
2286 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2287 ok(ret == 0, "expected 0, got %ld\n", ret);
2288 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2289 ok(ret == 1, "expected 1, got %ld\n", ret);
2290
2291 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
2292 DestroyWindow(listbox);
2293
2294 DestroyWindow(parent);
2295 }
2296
2297 static void test_LBS_NODATA(void)
2298 {
2299 static const DWORD invalid_styles[] =
2300 {
2301 0,
2302 LBS_OWNERDRAWVARIABLE,
2303 LBS_SORT,
2304 LBS_HASSTRINGS,
2305 LBS_OWNERDRAWFIXED | LBS_SORT,
2306 LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
2307 };
2308 static const UINT invalid_idx[] = { -2, 2 };
2309 static const UINT valid_idx[] = { 0, 1 };
2310 static const ULONG_PTR zero_data;
2311 HWND listbox, parent;
2312 INT ret, text_len;
2313 unsigned int i;
2314 ULONG_PTR data;
2315 BOOL is_wow64;
2316
2317 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
2318 0, 0, 100, 100, NULL, NULL, NULL, 0);
2319 ok(listbox != NULL, "Failed to create ListBox window.\n");
2320
2321 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2322 ok(ret == 0, "Unexpected return value %d.\n", ret);
2323 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2324 ok(ret == 1, "Unexpected return value %d.\n", ret);
2325 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
2326 ok(ret == 2, "Unexpected return value %d.\n", ret);
2327
2328 /* Invalid indices. */
2329 for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
2330 {
2331 ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
2332 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2333 ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
2334 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2335 if (ret == LB_ERR)
2336 {
2337 ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
2338 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2339 }
2340 ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
2341 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2342 }
2343
2344 IsWow64Process(GetCurrentProcess(), &is_wow64);
2345 #ifdef _WIN64
2346 text_len = 8;
2347 #else
2348 text_len = is_wow64 ? 8 : 4;
2349 #endif
2350
2351 /* Valid indices. */
2352 for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
2353 {
2354 ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
2355 ok(ret == TRUE, "Unexpected return value %d.\n", ret);
2356 ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
2357 todo_wine_if(is_wow64)
2358 ok(ret == text_len, "Unexpected return value %d.\n", ret);
2359
2360 memset(&data, 0xee, sizeof(data));
2361 ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
2362 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2363 ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
2364
2365 ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
2366 ok(ret == 0, "Unexpected return value %d.\n", ret);
2367 }
2368
2369 /* More messages that don't work with LBS_NODATA. */
2370 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0);
2371 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2372 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
2373 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2374 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0);
2375 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2376 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
2377 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2378 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0);
2379 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2380 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
2381 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2382
2383 DestroyWindow(listbox);
2384
2385 /* Invalid window style combinations. */
2386 parent = create_parent();
2387 ok(parent != NULL, "Failed to create parent window.\n");
2388
2389 for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
2390 {
2391 DWORD style;
2392
2393 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
2394 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
2395 ok(listbox != NULL, "Failed to create a listbox.\n");
2396
2397 style = GetWindowLongA(listbox, GWL_STYLE);
2398 ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style);
2399 ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
2400 ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
2401 DestroyWindow(listbox);
2402 }
2403
2404 DestroyWindow(parent);
2405 }
2406
2407 START_TEST(listbox)
2408 {
2409 ULONG_PTR ctx_cookie;
2410 HANDLE hCtx;
2411
2412 if (!load_v6_module(&ctx_cookie, &hCtx))
2413 return;
2414
2415 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2416
2417 test_listbox();
2418 test_item_height();
2419 test_ownerdraw();
2420 test_LB_SELITEMRANGE();
2421 test_LB_SETCURSEL();
2422 test_listbox_height();
2423 test_itemfrompoint();
2424 test_listbox_item_data();
2425 test_listbox_LB_DIR();
2426 test_listbox_dlgdir();
2427 test_set_count();
2428 test_GetListBoxInfo();
2429 test_missing_lbuttonup();
2430 test_extents();
2431 test_WM_MEASUREITEM();
2432 test_LB_SETSEL();
2433 test_LBS_NODATA();
2434
2435 unload_v6_module(ctx_cookie, hCtx);
2436 }