comctl32/tests: Use CRT allocation functions.
[wine.git] / dlls / comctl32 / tests / listbox.c
blob16c546852a157ee9edb0c6c890513a8e8dd47e35
1 /* Unit test suite for list boxes.
3 * Copyright 2003 Ferenc Wagner
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.
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.
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
20 #include <stdarg.h>
21 #include <stdio.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "commctrl.h"
30 #include "wine/test.h"
31 #include "v6util.h"
32 #include "msg.h"
34 enum seq_index
36 LB_SEQ_INDEX,
37 PARENT_SEQ_INDEX,
38 NUM_MSG_SEQUENCES
41 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
43 /* encoded MEASUREITEMSTRUCT into a WPARAM */
44 typedef struct
46 union
48 struct
50 UINT CtlType : 4;
51 UINT CtlID : 4;
52 UINT itemID : 4;
53 UINT wParam : 20;
54 } item;
55 WPARAM wp;
56 } u;
57 } MEASURE_ITEM_STRUCT;
59 static unsigned hash_Ly_W(const WCHAR *str)
61 unsigned hash = 0;
63 for (; *str; str++)
64 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
66 return hash;
69 static unsigned hash_Ly(const char *str)
71 unsigned hash = 0;
73 for (; *str; str++)
74 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
76 return hash;
79 static const char * const strings[4] = {
80 "First added",
81 "Second added",
82 "Third added",
83 "Fourth added which is very long because at some time we only had a 256 byte character buffer and "
84 "that was overflowing in one of those applications that had a common dialog file open box and tried "
85 "to add a 300 characters long custom filter string which of course the code did not like and crashed. "
86 "Just make sure this string is longer than 256 characters."
89 static const char BAD_EXTENSION[] = "*.badtxt";
91 #define ID_LISTBOX 1
93 static LRESULT WINAPI listbox_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
95 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
96 static LONG defwndproc_counter = 0;
97 struct message msg = { 0 };
98 LRESULT ret;
100 switch (message)
102 case WM_SIZE:
103 case WM_GETTEXT:
104 case WM_PAINT:
105 case WM_ERASEBKGND:
106 case WM_WINDOWPOSCHANGING:
107 case WM_WINDOWPOSCHANGED:
108 case WM_NCCALCSIZE:
109 case WM_NCPAINT:
110 case WM_NCHITTEST:
111 case WM_DEVICECHANGE:
112 break;
114 default:
115 msg.message = message;
116 msg.flags = sent|wparam|lparam;
117 if (defwndproc_counter) msg.flags |= defwinproc;
118 msg.wParam = wParam;
119 msg.lParam = lParam;
120 add_message(sequences, LB_SEQ_INDEX, &msg);
123 defwndproc_counter++;
124 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
125 defwndproc_counter--;
127 return ret;
130 static HWND create_listbox(DWORD add_style, HWND parent)
132 INT_PTR ctl_id = 0;
133 WNDPROC oldproc;
134 HWND handle;
136 if (parent)
137 ctl_id = ID_LISTBOX;
139 handle = CreateWindowA(WC_LISTBOXA, "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100,
140 parent, (HMENU)ctl_id, NULL, 0);
141 ok(handle != NULL, "Failed to create listbox window.\n");
143 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
144 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
145 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
146 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
148 oldproc = (WNDPROC)SetWindowLongPtrA(handle, GWLP_WNDPROC, (LONG_PTR)listbox_wnd_proc);
149 SetWindowLongPtrA(handle, GWLP_USERDATA, (LONG_PTR)oldproc);
151 return handle;
154 struct listbox_prop
156 DWORD add_style;
159 struct listbox_stat
161 int selected, anchor, caret, selcount;
164 struct listbox_test
166 struct listbox_stat init, init_todo;
167 struct listbox_stat click, click_todo;
168 struct listbox_stat step, step_todo;
169 struct listbox_stat sel, sel_todo;
172 static void listbox_query(HWND handle, struct listbox_stat *results)
174 results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
175 results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
176 results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
177 results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
180 static void buttonpress(HWND handle, WORD x, WORD y)
182 LPARAM lp = x + (y << 16);
184 SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
185 SendMessageA(handle, WM_LBUTTONUP, 0, lp);
188 static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
190 LPARAM lp = 1 + (scancode << 16) + (extended ? KEYEVENTF_EXTENDEDKEY : 0);
192 SendMessageA(handle, WM_KEYDOWN, keycode, lp);
193 SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000);
196 #define listbox_field_ok(t, s, f, got) \
197 ok (t.s.f==got.f, "style %#lx, step " #s ", field " #f \
198 ": expected %d, got %d\n", style, t.s.f, got.f)
200 #define listbox_todo_field_ok(t, s, f, got) \
201 todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
203 #define listbox_ok(t, s, got) \
204 listbox_todo_field_ok(t, s, selected, got); \
205 listbox_todo_field_ok(t, s, anchor, got); \
206 listbox_todo_field_ok(t, s, caret, got); \
207 listbox_todo_field_ok(t, s, selcount, got)
209 static void run_test(DWORD style, const struct listbox_test test)
211 static const struct message delete_seq[] =
213 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
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_RESETCONTENT, sent|wparam|lparam|defwinproc, 0, 0 },
218 { 0 }
220 struct listbox_stat answer;
221 int i, res, count;
222 RECT second_item;
223 HWND hLB;
225 hLB = create_listbox (style, 0);
227 listbox_query (hLB, &answer);
228 listbox_ok (test, init, answer);
230 SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
231 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
233 listbox_query(hLB, &answer);
234 listbox_ok(test, click, answer);
236 keypress(hLB, VK_DOWN, 0x50, TRUE);
238 listbox_query(hLB, &answer);
239 listbox_ok(test, step, answer);
241 DestroyWindow(hLB);
243 hLB = create_listbox(style, 0);
245 SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
246 listbox_query(hLB, &answer);
247 listbox_ok(test, sel, answer);
249 for (i = 0; i < 4 && !(style & LBS_NODATA); i++)
251 DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
252 int resA, resW;
253 WCHAR *txtw;
254 CHAR *txt;
256 txt = calloc(1, size + 1);
257 resA = SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
258 ok(!strcmp(txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
260 txtw = calloc(size + 1, sizeof(*txtw));
261 resW = SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
262 ok(resA == resW, "Unexpected text length.\n");
263 WideCharToMultiByte(CP_ACP, 0, txtw, -1, txt, size, NULL, NULL);
264 ok(!strcmp (txt, strings[i]), "Unexpected string for item %d, %s vs %s.\n", i, txt, strings[i]);
266 free(txtw);
267 free(txt);
270 /* Confirm the count of items, and that an invalid delete does not remove anything */
271 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
272 ok(res == 4, "Expected 4 items, got %d\n", res);
273 res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
274 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
275 res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
276 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
277 count = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
278 ok(count == 4, "Unexpected item count %d.\n", count);
280 /* Emptying listbox sends a LB_RESETCONTENT to itself. */
281 flush_sequence(sequences, LB_SEQ_INDEX);
282 for (i = count; i--;)
284 res = SendMessageA(hLB, LB_DELETESTRING, 0, 0);
285 ok(res == i, "Unexpected return value %d.\n", res);
287 ok_sequence(sequences, LB_SEQ_INDEX, delete_seq, "Emptying listbox", FALSE);
289 DestroyWindow(hLB);
292 static void test_item_height(void)
294 INT itemHeight;
295 TEXTMETRICA tm;
296 HFONT font;
297 HWND hLB;
298 HDC hdc;
300 hLB = create_listbox (0, 0);
301 ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
302 ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
303 ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
304 ReleaseDC( hLB, hdc);
306 ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
308 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
309 ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %ld\n", itemHeight, tm.tmHeight);
311 DestroyWindow (hLB);
313 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100, NULL, NULL, NULL, 0);
315 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
316 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %ld.\n",
317 itemHeight, tm.tmHeight);
318 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
319 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %ld.\n",
320 itemHeight, tm.tmHeight);
321 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
322 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %ld.\n",
323 itemHeight, tm.tmHeight);
325 DestroyWindow (hLB);
328 static unsigned int got_selchange, got_drawitem;
330 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
332 static LONG defwndproc_counter = 0;
333 struct message m = { 0 };
334 LRESULT ret;
336 m.message = msg;
337 m.flags = sent|wparam|lparam;
338 if (defwndproc_counter) m.flags |= defwinproc;
339 m.wParam = wParam;
340 m.lParam = lParam;
342 switch (msg)
344 case WM_MEASUREITEM:
346 MEASUREITEMSTRUCT *mis = (void *)lParam;
347 BOOL is_unicode_data = FALSE;
348 MEASURE_ITEM_STRUCT mi;
350 if (mis->CtlType == ODT_LISTBOX)
352 HWND ctrl = GetDlgItem(hwnd, mis->CtlID);
353 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
356 mi.u.wp = 0;
357 mi.u.item.CtlType = mis->CtlType;
358 mi.u.item.CtlID = mis->CtlID;
359 mi.u.item.itemID = mis->itemID;
360 mi.u.item.wParam = wParam;
362 m.wParam = mi.u.wp;
363 if (is_unicode_data)
364 m.lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
365 else
366 m.lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
367 add_message(sequences, PARENT_SEQ_INDEX, &m);
369 ok(wParam == mis->CtlID, "got wParam=%08Ix, expected %08x\n", wParam, mis->CtlID);
370 ok(mis->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mis->CtlType);
371 ok(mis->CtlID == 1, "mi->CtlID = %u\n", mis->CtlID);
372 ok(mis->itemHeight, "mi->itemHeight = 0\n");
374 break;
376 case WM_COMPAREITEM:
378 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lParam;
379 HWND ctrl = GetDlgItem(hwnd, cis->CtlID);
380 BOOL is_unicode_data = TRUE;
382 ok(wParam == cis->CtlID, "expected %#x, got %#Ix\n", cis->CtlID, wParam);
383 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
384 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
385 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
387 if (cis->CtlType == ODT_LISTBOX)
388 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
390 if (is_unicode_data)
392 m.wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
393 m.lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
395 else
397 m.wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
398 m.lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
400 add_message(sequences, PARENT_SEQ_INDEX, &m);
401 break;
403 case WM_DRAWITEM:
405 RECT rc_item, rc_client, rc_clip;
406 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
408 ok(wParam == dis->CtlID, "got wParam=%08Ix instead of %08x\n", wParam, dis->CtlID);
409 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
411 GetClientRect(dis->hwndItem, &rc_client);
412 GetClipBox(dis->hDC, &rc_clip);
413 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
414 "client rect of the listbox should be equal to the clip box,"
415 "or the clip box should be empty\n");
417 SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
418 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
420 got_drawitem++;
421 break;
424 case WM_COMMAND:
425 if (HIWORD( wParam ) == LBN_SELCHANGE) got_selchange++;
426 break;
428 default:
429 break;
432 defwndproc_counter++;
433 ret = DefWindowProcA(hwnd, msg, wParam, lParam);
434 defwndproc_counter--;
436 return msg == WM_COMPAREITEM ? -1 : ret;
439 static HWND create_parent( void )
441 static ATOM class;
442 WNDCLASSA cls;
444 if (!class)
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 );
459 return CreateWindowExA(0, "main_window_class", NULL, WS_POPUP | WS_VISIBLE, 100, 100, 400, 400, GetDesktopWindow(),
460 0, GetModuleHandleA(NULL), NULL);
463 static void test_ownerdraw(void)
465 static const DWORD styles[] =
468 LBS_NODATA
470 static const struct {
471 UINT message;
472 WPARAM wparam;
473 LPARAM lparam;
474 UINT drawitem;
475 } testcase[] = {
476 { WM_NULL, 0, 0, 0 },
477 { WM_PAINT, 0, 0, 0 },
478 { LB_GETCOUNT, 0, 0, 0 },
479 { LB_SETCOUNT, ARRAY_SIZE(strings), 0, ARRAY_SIZE(strings) },
480 { LB_ADDSTRING, 0, (LPARAM)"foo", ARRAY_SIZE(strings)+1 },
481 { LB_DELETESTRING, 0, 0, ARRAY_SIZE(strings)-1 },
483 HWND parent, hLB;
484 INT ret;
485 RECT rc;
486 UINT i;
488 parent = create_parent();
489 ok(parent != NULL, "Failed to create parent window.\n");
491 for (i = 0; i < ARRAY_SIZE(styles); i++)
493 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent);
494 ok(hLB != NULL, "Failed to create listbox window.\n");
496 SetForegroundWindow(hLB);
497 UpdateWindow(hLB);
499 /* make height short enough */
500 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
501 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, SWP_NOZORDER | SWP_NOMOVE);
503 /* make 0 item invisible */
504 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
505 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
506 ok(ret == 1, "wrong top index %d\n", ret);
508 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
509 ok(!IsRectEmpty(&rc), "empty item rect\n");
510 ok(rc.top < 0, "rc.top is not negative (%ld)\n", rc.top);
512 DestroyWindow(hLB);
514 /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
515 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i],
516 0, 0, 100, 100, NULL, NULL, NULL, 0);
517 ok(hLB != NULL, "last error 0x%08lx\n", GetLastError());
519 ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n");
521 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
522 ok(ret == 0, "Unexpected return value %d.\n", ret);
523 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
524 ok(ret == 1, "Unexpected return value %d.\n", ret);
526 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
527 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
529 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
530 ok(ret == 13, "Unexpected item height %d.\n", ret);
532 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
533 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
535 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
536 ok(ret == 42, "Unexpected item height %d.\n", ret);
538 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
539 ok(ret == 42, "Unexpected item height %d.\n", ret);
541 DestroyWindow (hLB);
544 /* test pending redraw state */
545 for (i = 0; i < ARRAY_SIZE(testcase); i++)
547 winetest_push_context("%d", i);
548 hLB = create_listbox(LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent);
549 assert(hLB);
551 ret = SendMessageA(hLB, WM_SETREDRAW, FALSE, 0);
552 ok(!ret, "got %d\n", ret);
553 ret = SendMessageA(hLB, testcase[i].message, testcase[i].wparam, testcase[i].lparam);
554 if (testcase[i].message >= LB_ADDSTRING && testcase[i].message < LB_MSGMAX &&
555 testcase[i].message != LB_SETCOUNT)
556 ok(ret > 0, "expected > 0, got %d\n", ret);
557 else
558 ok(!ret, "expected 0, got %d\n", ret);
560 got_drawitem = 0;
561 ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW);
562 ok(ret, "RedrawWindow failed\n");
563 ok(!got_drawitem, "got %u\n", got_drawitem);
565 ret = SendMessageA(hLB, WM_SETREDRAW, TRUE, 0);
566 ok(!ret, "got %d\n", ret);
568 got_drawitem = 0;
569 ret = RedrawWindow(hLB, NULL, 0, RDW_UPDATENOW);
570 ok(ret, "RedrawWindow failed\n");
571 ok(got_drawitem == testcase[i].drawitem, "expected %u, got %u\n", testcase[i].drawitem, got_drawitem);
573 DestroyWindow(hLB);
574 winetest_pop_context();
577 DestroyWindow(parent);
580 #define listbox_test_query(exp, got) \
581 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
582 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
583 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
584 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
586 static void test_LB_SELITEMRANGE(void)
588 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
589 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
590 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
591 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
592 struct listbox_stat answer;
593 HWND hLB;
594 INT ret;
596 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
597 ok(hLB != NULL, "Failed to create listbox window.\n");
599 listbox_query(hLB, &answer);
600 listbox_test_query(test_nosel, answer);
602 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
603 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
604 listbox_query(hLB, &answer);
605 listbox_test_query(test_1, answer);
607 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
608 listbox_query(hLB, &answer);
609 listbox_test_query(test_nosel, answer);
611 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
612 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
613 listbox_query(hLB, &answer);
614 listbox_test_query(test_3, answer);
616 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
617 listbox_query(hLB, &answer);
618 listbox_test_query(test_nosel, answer);
620 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
621 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
622 listbox_query(hLB, &answer);
623 listbox_test_query(test_nosel, answer);
625 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
626 listbox_query(hLB, &answer);
627 listbox_test_query(test_nosel, answer);
629 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
630 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
631 listbox_query(hLB, &answer);
632 listbox_test_query(test_1, answer);
634 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
635 listbox_query(hLB, &answer);
636 listbox_test_query(test_nosel, answer);
638 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
639 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
640 listbox_query(hLB, &answer);
641 listbox_test_query(test_nosel, answer);
643 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
644 listbox_query(hLB, &answer);
645 listbox_test_query(test_nosel, answer);
647 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
648 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
649 listbox_query(hLB, &answer);
650 listbox_test_query(test_2, answer);
652 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
653 listbox_query(hLB, &answer);
654 listbox_test_query(test_nosel, answer);
656 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
657 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
658 listbox_query(hLB, &answer);
659 listbox_test_query(test_2, answer);
661 DestroyWindow(hLB);
664 static void test_LB_SETCURSEL(void)
666 HWND parent, hLB;
667 INT ret;
669 parent = create_parent();
670 ok(parent != NULL, "Failed to create parent window.\n");
672 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
673 ok(hLB != NULL, "Failed to create listbox.\n");
675 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
677 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
678 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
680 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
681 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
682 ret = GetScrollPos(hLB, SB_VERT);
683 ok(ret == 0, "expected vscroll 0, got %d\n", ret);
685 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
686 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
688 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
689 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
690 ret = GetScrollPos(hLB, SB_VERT);
691 ok(ret == 1, "expected vscroll 1, got %d\n", ret);
693 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
694 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
696 DestroyWindow(hLB);
698 hLB = create_listbox(0, 0);
699 ok(hLB != NULL, "Failed to create ListBox window.\n");
701 ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
702 ok(ret == 1, "Unexpected return value %d.\n", ret);
704 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
705 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
707 DestroyWindow(hLB);
709 /* LBS_EXTENDEDSEL */
710 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
711 ok(hLB != NULL, "Failed to create listbox.\n");
713 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
714 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
716 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
717 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
719 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
720 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
722 DestroyWindow(hLB);
724 /* LBS_MULTIPLESEL */
725 hLB = create_listbox(LBS_MULTIPLESEL, 0);
726 ok(hLB != NULL, "Failed to create listbox.\n");
728 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
729 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
731 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
732 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
734 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
735 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
737 DestroyWindow(hLB);
740 static void test_LB_SETSEL(void)
742 HWND list;
743 int ret;
745 /* LBS_EXTENDEDSEL */
746 list = create_listbox(LBS_EXTENDEDSEL, 0);
747 ok(list != NULL, "Failed to create ListBox window.\n");
749 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
750 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
752 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
753 ok(ret == 0, "Unexpected return value %d.\n", ret);
754 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
755 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
756 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
757 ok(ret == 0, "Unexpected caret index %d.\n", ret);
759 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
760 ok(ret == 0, "Unexpected return value %d.\n", ret);
761 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
762 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
763 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
764 ok(ret == 1, "Unexpected caret index %d.\n", ret);
766 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
767 ok(ret == 0, "Unexpected return value %d.\n", ret);
768 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
769 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
770 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
771 ok(ret == 1, "Unexpected caret index %d.\n", ret);
773 DestroyWindow(list);
775 /* LBS_MULTIPLESEL */
776 list = create_listbox(LBS_MULTIPLESEL, 0);
777 ok(list != NULL, "Failed to create ListBox window.\n");
779 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
780 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
782 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
783 ok(ret == 0, "Unexpected return value %d.\n", ret);
784 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
785 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
786 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
787 ok(ret == 0, "Unexpected caret index %d.\n", ret);
789 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
790 ok(ret == 0, "Unexpected return value %d.\n", ret);
791 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
792 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
793 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
794 ok(ret == 1, "Unexpected caret index %d.\n", ret);
796 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
797 ok(ret == 0, "Unexpected return value %d.\n", ret);
798 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
799 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
800 ret = SendMessageA(list, LB_GETCARETINDEX, 0, 0);
801 ok(ret == 1, "Unexpected caret index %d.\n", ret);
803 DestroyWindow(list);
806 static void test_listbox_height(void)
808 HWND hList;
809 int r, id;
811 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
812 1, 1, 600, 100, NULL, NULL, NULL, NULL );
813 ok( hList != NULL, "failed to create listbox\n");
815 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
816 ok( id == 0, "item id wrong\n");
818 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
819 ok( r == 0, "send message failed\n");
821 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
822 ok( r == 20, "height wrong\n");
824 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
825 ok( r == -1, "send message failed\n");
827 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
828 ok( r == 20, "height wrong\n");
830 /* Before Windows 10 1709 (or 1703?) the item height was limited to 255.
831 * Since then, with comctl32 V6 the limit is 65535.
833 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 256, 0 ));
834 ok(r == 0 || broken(r == -1), "Failed to set item height, %d.\n", r);
835 if (r == -1)
837 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
838 ok( r == 20, "Unexpected item height %d.\n", r);
840 else
842 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
843 ok( r == 256, "Unexpected item height %d.\n", r);
845 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 65535, 0 ));
846 ok(r == 0, "Failed to set item height, %d.\n", r);
848 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
849 ok( r == 65535, "Unexpected item height %d.\n", r);
852 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
853 ok( r == 0, "send message failed\n");
855 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
856 ok( r == 0xff, "height wrong\n");
858 DestroyWindow( hList );
861 static void test_changing_selection_styles(void)
863 static const DWORD styles[] =
866 LBS_NODATA | LBS_OWNERDRAWFIXED
868 static const DWORD selstyles[] =
871 LBS_MULTIPLESEL,
872 LBS_EXTENDEDSEL,
873 LBS_MULTIPLESEL | LBS_EXTENDEDSEL
875 static const LONG selexpect_single[] = { 0, 0, 1 };
876 static const LONG selexpect_single2[] = { 1, 0, 0 };
877 static const LONG selexpect_multi[] = { 1, 0, 1 };
878 static const LONG selexpect_multi2[] = { 1, 1, 0 };
880 HWND parent, listbox;
881 DWORD style;
882 LONG ret;
883 UINT i, j, k;
885 parent = create_parent();
886 ok(parent != NULL, "Failed to create parent window.\n");
887 for (i = 0; i < ARRAY_SIZE(styles); i++)
889 /* Test if changing selection styles affects selection storage */
890 for (j = 0; j < ARRAY_SIZE(selstyles); j++)
892 LONG setcursel_expect, selitemrange_expect, getselcount_expect;
893 const LONG *selexpect;
895 listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | selstyles[j] | WS_CHILD | WS_VISIBLE,
896 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
897 ok(listbox != NULL, "%u: Failed to create ListBox window.\n", j);
899 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
901 setcursel_expect = LB_ERR;
902 selitemrange_expect = LB_OKAY;
903 getselcount_expect = 2;
904 selexpect = selexpect_multi;
906 else
908 setcursel_expect = 2;
909 selitemrange_expect = LB_ERR;
910 getselcount_expect = LB_ERR;
911 selexpect = selexpect_single;
914 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
916 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"x");
917 ok(ret == k, "%u: Unexpected return value %ld, expected %d.\n", j, ret, k);
919 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
920 ok(ret == ARRAY_SIZE(selexpect_multi), "%u: Unexpected count %ld.\n", j, ret);
922 /* Select items with different methods */
923 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
924 ok(ret == setcursel_expect, "%u: Unexpected return value %ld.\n", j, ret);
925 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 0));
926 ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret);
927 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 2));
928 ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret);
930 /* Verify that the proper items are selected */
931 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
933 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
934 ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n",
935 j, ret, selexpect[k]);
938 /* Now change the selection style */
939 style = GetWindowLongA(listbox, GWL_STYLE);
940 ok((style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == selstyles[j],
941 "%u: unexpected window styles %#lx.\n", j, style);
942 if (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
943 style &= ~selstyles[j];
944 else
945 style |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
946 SetWindowLongA(listbox, GWL_STYLE, style);
947 style = GetWindowLongA(listbox, GWL_STYLE);
948 ok(!(style & selstyles[j]), "%u: unexpected window styles %#lx.\n", j, style);
950 /* Verify that the same items are selected */
951 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
952 ok(ret == getselcount_expect, "%u: expected %ld from LB_GETSELCOUNT, got %ld\n",
953 j, getselcount_expect, ret);
955 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
957 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
958 ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n",
959 j, ret, selexpect[k]);
962 /* Lastly see if we can still change the selection as before with old style */
963 if (setcursel_expect != LB_ERR) setcursel_expect = 0;
964 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
965 ok(ret == setcursel_expect, "%u: Unexpected return value %ld.\n", j, ret);
966 ret = SendMessageA(listbox, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 1));
967 ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret);
968 ret = SendMessageA(listbox, LB_SELITEMRANGE, FALSE, MAKELPARAM(2, 2));
969 ok(ret == selitemrange_expect, "%u: Unexpected return value %ld.\n", j, ret);
971 /* And verify the selections */
972 selexpect = (selstyles[j] & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ? selexpect_multi2 : selexpect_single2;
973 ret = SendMessageA(listbox, LB_GETSELCOUNT, 0, 0);
974 ok(ret == getselcount_expect, "%u: expected %ld from LB_GETSELCOUNT, got %ld\n",
975 j, getselcount_expect, ret);
977 for (k = 0; k < ARRAY_SIZE(selexpect_multi); k++)
979 ret = SendMessageA(listbox, LB_GETSEL, k, 0);
980 ok(ret == selexpect[k], "%u: Unexpected selection state %ld, expected %ld.\n",
981 j, ret, selexpect[k]);
984 DestroyWindow(listbox);
987 DestroyWindow(parent);
990 static void test_itemfrompoint(void)
992 /* WS_POPUP is required in order to have a more accurate size calculation (
993 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
994 behavior of partially-displayed item.
996 HWND hList = CreateWindowA( WC_LISTBOXA, "list test",
997 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
998 1, 1, 600, 100, NULL, NULL, NULL, NULL );
999 ULONG r, id;
1000 RECT rc;
1002 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
1003 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#lx.\n", r );
1005 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
1006 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#lx.\n", r );
1008 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
1009 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#lx.\n", r );
1011 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
1012 ok( id == 0, "item id wrong\n");
1013 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
1014 ok( id == 1, "item id wrong\n");
1016 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
1017 ok( r == 0x1, "ret %lx\n", r );
1019 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
1020 ok( r == MAKELPARAM(1, 1), "Unexpected ret value %#lx.\n", r );
1022 /* Resize control so that below assertions about sizes are valid */
1023 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
1024 ok( r == 1, "ret %lx\n", r);
1025 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
1026 ok( r != 0, "ret %lx\n", r);
1028 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
1029 ok( id == 2, "item id wrong\n");
1030 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
1031 ok( id == 3, "item id wrong\n");
1032 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
1033 ok( id == 4, "item id wrong\n");
1034 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
1035 ok( id == 5, "item id wrong\n");
1036 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
1037 ok( id == 6, "item id wrong\n");
1038 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
1039 ok( id == 7, "item id wrong\n");
1041 /* Set the listbox up so that id 1 is at the top, this leaves 5
1042 partially visible at the bottom and 6, 7 are invisible */
1044 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
1045 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
1046 ok( r == 1, "top %ld\n", r);
1048 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
1049 ok( r == 1, "ret %lx\n", r);
1050 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
1051 ok( r == 0, "ret %lx\n", r);
1053 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
1054 ok( r == 1, "ret %lx\n", r);
1056 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
1057 ok( r == 0x10001, "ret %lx\n", r );
1059 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
1060 ok( r == 0x10001, "ret %lx\n", r );
1062 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
1063 ok( r == 0x10005, "item %lx\n", r );
1065 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
1066 ok( r == 0x10005, "item %lx\n", r );
1068 DestroyWindow( hList );
1071 static void test_listbox_item_data(void)
1073 HWND hList;
1074 int r, id;
1076 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
1077 1, 1, 600, 100, NULL, NULL, NULL, NULL );
1078 ok( hList != NULL, "failed to create listbox\n");
1080 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
1081 ok( id == 0, "item id wrong\n");
1083 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
1084 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
1086 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
1087 ok( r == 20, "get item data failed\n");
1089 DestroyWindow( hList );
1092 static void test_listbox_LB_DIR(void)
1094 char path[MAX_PATH], curdir[MAX_PATH];
1095 HWND hList;
1096 int res, itemCount;
1097 int itemCount_justFiles;
1098 int itemCount_justDrives;
1099 int itemCount_allFiles;
1100 int itemCount_allDirs;
1101 int i;
1102 char pathBuffer[MAX_PATH];
1103 char * p;
1104 char driveletter;
1105 const char *wildcard = "*";
1106 HANDLE file;
1107 BOOL ret;
1109 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
1111 GetTempPathA(ARRAY_SIZE(path), path);
1112 ret = SetCurrentDirectoryA(path);
1113 ok(ret, "Failed to set current directory.\n");
1115 ret = CreateDirectoryA("lb_dir_test", NULL);
1116 ok(ret, "Failed to create test directory.\n");
1118 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1119 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %ld\n", GetLastError());
1120 CloseHandle( file );
1122 /* NOTE: for this test to succeed, there must be no subdirectories
1123 under the current directory. In addition, there must be at least
1124 one file that fits the wildcard w*.c . Normally, the test
1125 directory itself satisfies both conditions.
1127 hList = CreateWindowA( WC_LISTBOXA, "list test", WS_VISIBLE|WS_POPUP,
1128 1, 1, 600, 100, NULL, NULL, NULL, NULL );
1129 ok(hList != NULL, "Failed to create listbox window.\n");
1131 /* Test for standard usage */
1133 /* This should list all the files in the test directory. */
1134 strcpy(pathBuffer, wildcard);
1135 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1136 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1137 if (res == -1) /* "*" wildcard doesn't work on win9x */
1139 wildcard = "*.*";
1140 strcpy(pathBuffer, wildcard);
1141 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1143 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08lx\n", GetLastError());
1145 /* There should be some content in the listbox */
1146 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1147 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
1148 itemCount_allFiles = itemCount;
1149 ok(res + 1 == itemCount,
1150 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
1151 itemCount - 1, res);
1153 /* This tests behavior when no files match the wildcard */
1154 strcpy(pathBuffer, BAD_EXTENSION);
1155 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1156 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1157 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1159 /* There should be NO content in the listbox */
1160 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1161 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1164 /* This should list all the w*.c files in the test directory
1165 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1167 strcpy(pathBuffer, "w*.c");
1168 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1169 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
1170 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08lx\n", GetLastError());
1172 /* Path specification does NOT converted to uppercase */
1173 ok (!strcmp(pathBuffer, "w*.c"),
1174 "expected no change to pathBuffer, got %s\n", pathBuffer);
1176 /* There should be some content in the listbox */
1177 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1178 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
1179 itemCount_justFiles = itemCount;
1180 ok(res + 1 == itemCount,
1181 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
1182 itemCount - 1, res);
1184 /* Every single item in the control should start with a w and end in .c */
1185 for (i = 0; i < itemCount; i++)
1187 memset(pathBuffer, 0, MAX_PATH);
1188 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1189 p = pathBuffer + strlen(pathBuffer);
1190 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1191 (*(p-1) == 'c' || *(p-1) == 'C') &&
1192 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1195 /* Test DDL_DIRECTORY */
1196 strcpy(pathBuffer, wildcard);
1197 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1198 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1199 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08lx\n", GetLastError());
1201 /* There should be some content in the listbox.
1202 * All files plus "[..]"
1204 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1205 itemCount_allDirs = itemCount - itemCount_allFiles;
1206 ok (itemCount >= itemCount_allFiles,
1207 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
1208 itemCount, itemCount_allFiles);
1209 ok(res + 1 == itemCount,
1210 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
1211 itemCount - 1, res);
1213 /* This tests behavior when no files match the wildcard */
1214 strcpy(pathBuffer, BAD_EXTENSION);
1215 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1216 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1217 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
1219 /* There should be NO content in the listbox */
1220 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1221 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
1223 /* Test DDL_DIRECTORY */
1224 strcpy(pathBuffer, "w*.c");
1225 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1226 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
1227 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08lx\n", GetLastError());
1229 /* There should be some content in the listbox. Since the parent directory does not
1230 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
1232 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1233 ok (itemCount == itemCount_justFiles,
1234 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
1235 itemCount, itemCount_justFiles);
1236 ok(res + 1 == itemCount,
1237 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
1238 itemCount - 1, res);
1240 /* Every single item in the control should start with a w and end in .c. */
1241 for (i = 0; i < itemCount; i++)
1243 memset(pathBuffer, 0, MAX_PATH);
1244 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1245 p = pathBuffer + strlen(pathBuffer);
1247 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1248 (*(p-1) == 'c' || *(p-1) == 'C') &&
1249 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1252 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
1253 strcpy(pathBuffer, wildcard);
1254 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1255 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1256 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08lx\n", GetLastError());
1258 /* There should be some content in the listbox. In particular, there should
1259 * be at least one element before, since the string "[-c-]" should
1260 * have been added. Depending on the user setting, more drives might have
1261 * been added.
1263 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1264 ok (itemCount >= 1,
1265 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
1266 itemCount, 1);
1267 itemCount_justDrives = itemCount;
1268 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1270 /* Every single item in the control should fit the format [-c-] */
1271 for (i = 0; i < itemCount; i++)
1273 memset(pathBuffer, 0, MAX_PATH);
1274 driveletter = '\0';
1275 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1276 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1277 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1278 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1279 if (!(driveletter >= 'a' && driveletter <= 'z'))
1281 /* Correct after invalid entry is found */
1282 itemCount_justDrives--;
1286 /* This tests behavior when no files match the wildcard */
1287 strcpy(pathBuffer, BAD_EXTENSION);
1288 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1289 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1290 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1291 BAD_EXTENSION, res, itemCount_justDrives -1);
1293 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1294 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
1295 itemCount, itemCount_justDrives);
1297 /* Test DDL_DRIVES. */
1298 strcpy(pathBuffer, wildcard);
1299 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1300 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1301 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08lx\n", GetLastError());
1303 /* There should be some content in the listbox. In particular, there should
1304 * be at least one element before, since the string "[-c-]" should
1305 * have been added. Depending on the user setting, more drives might have
1306 * been added.
1308 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1309 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
1310 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
1311 itemCount, itemCount_justDrives + itemCount_allFiles);
1312 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
1314 /* This tests behavior when no files match the wildcard */
1315 strcpy(pathBuffer, BAD_EXTENSION);
1316 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1317 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1318 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
1319 BAD_EXTENSION, res, itemCount_justDrives -1);
1321 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1322 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1324 /* Test DDL_DRIVES. */
1325 strcpy(pathBuffer, "w*.c");
1326 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1327 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1328 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08lx\n", GetLastError());
1330 /* There should be some content in the listbox. In particular, there should
1331 * be at least one element before, since the string "[-c-]" should
1332 * have been added. Depending on the user setting, more drives might have
1333 * been added.
1335 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1336 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1337 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1338 itemCount, itemCount_justDrives + itemCount_justFiles);
1339 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1341 /* Every single item in the control should fit the format [-c-], or w*.c */
1342 for (i = 0; i < itemCount; i++)
1344 memset(pathBuffer, 0, MAX_PATH);
1345 driveletter = '\0';
1346 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1347 p = pathBuffer + strlen(pathBuffer);
1348 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1350 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1351 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1353 else
1356 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1357 (*(p-1) == 'c' || *(p-1) == 'C') &&
1358 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1362 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1363 strcpy(pathBuffer, wildcard);
1364 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1365 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1366 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08lx\n", GetLastError());
1368 /* There should be some content in the listbox. In particular, there should
1369 * be exactly the number of plain files, plus the number of mapped drives.
1371 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1372 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1373 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1374 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1375 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1377 /* Every single item in the control should start with a w and end in .c,
1378 * except for the "[..]" string, which should appear exactly as it is,
1379 * and the mapped drives in the format "[-X-]".
1381 for (i = 0; i < itemCount; i++)
1383 memset(pathBuffer, 0, MAX_PATH);
1384 driveletter = '\0';
1385 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1386 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1387 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1390 /* This tests behavior when no files match the wildcard */
1391 strcpy(pathBuffer, BAD_EXTENSION);
1392 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1393 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1394 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1395 BAD_EXTENSION, res, itemCount_justDrives -1);
1397 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1398 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1400 /* Test DDL_DIRECTORY|DDL_DRIVES. */
1401 strcpy(pathBuffer, "w*.c");
1402 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1403 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1404 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08lx\n", GetLastError());
1406 /* There should be some content in the listbox. In particular, there should
1407 * be exactly the number of plain files, plus the number of mapped drives.
1409 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1410 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1411 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1412 itemCount, itemCount_justFiles + itemCount_justDrives);
1413 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1415 /* Every single item in the control should start with a w and end in .c,
1416 * except the mapped drives in the format "[-X-]". The "[..]" directory
1417 * should not appear.
1419 for (i = 0; i < itemCount; i++)
1421 memset(pathBuffer, 0, MAX_PATH);
1422 driveletter = '\0';
1423 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1424 p = pathBuffer + strlen(pathBuffer);
1425 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1426 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1427 else
1429 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1430 (*(p-1) == 'c' || *(p-1) == 'C') &&
1431 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1434 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1435 strcpy(pathBuffer, wildcard);
1436 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1437 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1438 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %lu\n",
1439 GetLastError());
1441 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1442 ok (itemCount == itemCount_allDirs,
1443 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1444 itemCount, itemCount_allDirs);
1445 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1447 if (itemCount)
1449 memset(pathBuffer, 0, MAX_PATH);
1450 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1451 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1454 /* This tests behavior when no files match the wildcard */
1455 strcpy(pathBuffer, BAD_EXTENSION);
1456 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1457 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1458 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1459 BAD_EXTENSION, res, -1);
1461 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1462 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1465 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1466 strcpy(pathBuffer, "w*.c");
1467 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1468 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1469 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1471 /* There should be no elements, since "[..]" does not fit w*.c */
1472 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1473 ok (itemCount == 0,
1474 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1475 itemCount, 0);
1477 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1478 strcpy(pathBuffer, wildcard);
1479 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1480 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1481 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08lx\n", GetLastError());
1483 /* There should be no plain files on the listbox */
1484 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1485 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1486 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1487 itemCount, itemCount_justDrives + itemCount_allDirs);
1488 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1490 for (i = 0; i < itemCount; i++)
1492 memset(pathBuffer, 0, MAX_PATH);
1493 driveletter = '\0';
1494 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1495 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1496 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1497 else
1498 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1499 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1502 /* This tests behavior when no files match the wildcard */
1503 strcpy(pathBuffer, BAD_EXTENSION);
1504 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1505 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1506 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1507 BAD_EXTENSION, res, itemCount_justDrives -1);
1509 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1510 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1512 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1513 strcpy(pathBuffer, "w*.c");
1514 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1515 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1516 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08lx\n", GetLastError());
1518 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1519 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1520 ok (itemCount == itemCount_justDrives,
1521 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1522 itemCount, itemCount_justDrives);
1523 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1525 for (i = 0; i < itemCount; i++)
1527 memset(pathBuffer, 0, MAX_PATH);
1528 driveletter = '\0';
1529 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1530 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1531 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1533 DestroyWindow(hList);
1535 DeleteFileA( "wtest1.tmp.c" );
1536 RemoveDirectoryA("lb_dir_test");
1538 SetCurrentDirectoryA(curdir);
1541 static HWND g_listBox;
1542 static HWND g_label;
1544 #define ID_TEST_LABEL 1001
1545 #define ID_TEST_LISTBOX 1002
1547 static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs)
1549 g_label = CreateWindowA(WC_STATICA, "Contents of static control before DlgDirList.",
1550 WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1551 if (!g_label) return FALSE;
1553 g_listBox = CreateWindowA(WC_LISTBOXA, "DlgDirList test",
1554 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256,
1555 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1556 if (!g_listBox) return FALSE;
1558 return TRUE;
1561 static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1563 LRESULT result = 0;
1565 switch (uiMsg)
1567 case WM_DESTROY:
1568 PostQuitMessage(0);
1569 break;
1570 case WM_CREATE:
1571 result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1;
1572 break;
1573 default:
1574 result = DefWindowProcA(hwnd, uiMsg, wParam, lParam);
1575 break;
1577 return result;
1580 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1582 WNDCLASSA cls;
1584 cls.style = 0;
1585 cls.cbClsExtra = 0;
1586 cls.cbWndExtra = 0;
1587 cls.hInstance = hInst;
1588 cls.hIcon = NULL;
1589 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1590 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1591 cls.lpszMenuName = NULL;
1592 cls.lpfnWndProc = listbox_container_window_procA;
1593 cls.lpszClassName = "ListboxContainerClass";
1594 if (!RegisterClassA (&cls)) return FALSE;
1596 return TRUE;
1599 static void test_listbox_dlgdir(void)
1601 HINSTANCE hInst;
1602 HWND hWnd;
1603 int res, itemCount;
1604 int itemCount_allDirs;
1605 int itemCount_justFiles;
1606 int itemCount_justDrives;
1607 int i;
1608 char pathBuffer[MAX_PATH];
1609 char itemBuffer[MAX_PATH];
1610 char tempBuffer[MAX_PATH];
1611 char * p;
1612 char driveletter;
1613 HANDLE file;
1614 BOOL ret;
1616 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1617 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %ld\n", GetLastError());
1618 CloseHandle( file );
1620 /* NOTE: for this test to succeed, there must be no subdirectories
1621 under the current directory. In addition, there must be at least
1622 one file that fits the wildcard w*.c . Normally, the test
1623 directory itself satisfies both conditions.
1626 hInst = GetModuleHandleA(0);
1627 ret = RegisterListboxWindowClass(hInst);
1628 ok(ret, "Failed to register test class.\n");
1630 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1631 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1632 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1633 NULL, NULL, hInst, 0);
1634 ok(hWnd != NULL, "Failed to create container window.\n");
1636 /* Test for standard usage */
1638 /* The following should be overwritten by the directory path */
1639 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1641 /* This should list all the w*.c files in the test directory
1642 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1644 strcpy(pathBuffer, "w*.c");
1645 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1646 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08lx\n", res, GetLastError());
1648 /* Path specification gets converted to uppercase */
1649 ok (!strcmp(pathBuffer, "W*.C"),
1650 "expected conversion to uppercase, got %s\n", pathBuffer);
1652 /* Loaded path should have overwritten the label text */
1653 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1654 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1656 /* There should be some content in the listbox */
1657 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1658 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1659 itemCount_justFiles = itemCount;
1661 /* Every single item in the control should start with a w and end in .c */
1662 for (i = 0; i < itemCount; i++)
1664 memset(pathBuffer, 0, MAX_PATH);
1665 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1666 p = pathBuffer + strlen(pathBuffer);
1667 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1668 (*(p-1) == 'c' || *(p-1) == 'C') &&
1669 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1672 /* Test behavior when no files match the wildcard */
1673 strcpy(pathBuffer, BAD_EXTENSION);
1674 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1675 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1677 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1678 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1680 /* Test DDL_DIRECTORY */
1681 strcpy(pathBuffer, "w*.c");
1682 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1683 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08lx\n", GetLastError());
1685 /* There should be some content in the listbox. In particular, there should
1686 * be exactly more elements than before, since the directories should
1687 * have been added.
1689 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1690 itemCount_allDirs = itemCount - itemCount_justFiles;
1691 ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1692 itemCount, itemCount_justFiles);
1694 /* Every single item in the control should start with a w and end in .c,
1695 * except for the "[..]" string, which should appear exactly as it is.
1697 for (i = 0; i < itemCount; i++)
1699 memset(pathBuffer, 0, MAX_PATH);
1700 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1701 p = pathBuffer + strlen(pathBuffer);
1702 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1703 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1704 (*(p-1) == 'c' || *(p-1) == 'C') &&
1705 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1708 /* Test behavior when no files match the wildcard */
1709 strcpy(pathBuffer, BAD_EXTENSION);
1710 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1711 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1713 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1714 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1715 itemCount_allDirs, itemCount);
1716 for (i = 0; i < itemCount; i++)
1718 memset(pathBuffer, 0, MAX_PATH);
1719 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1720 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1721 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1724 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1725 strcpy(pathBuffer, "w*.c");
1726 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1727 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08lx\n", GetLastError());
1729 /* There should be some content in the listbox. In particular, there should
1730 * be at least one element before, since the string "[-c-]" should
1731 * have been added. Depending on the user setting, more drives might have
1732 * been added.
1734 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1735 ok (itemCount >= 1,
1736 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1737 itemCount, 1);
1738 itemCount_justDrives = itemCount;
1740 /* Every single item in the control should fit the format [-c-] */
1741 for (i = 0; i < itemCount; i++)
1743 memset(pathBuffer, 0, MAX_PATH);
1744 driveletter = '\0';
1745 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1746 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1747 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1748 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1749 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1750 /* Correct after invalid entry is found */
1751 trace("removing count of invalid entry %s\n", pathBuffer);
1752 itemCount_justDrives--;
1756 /* Test behavior when no files match the wildcard */
1757 strcpy(pathBuffer, BAD_EXTENSION);
1758 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1759 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1761 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1762 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1764 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1765 strcpy(pathBuffer, "w*.c");
1766 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1767 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08lx\n", GetLastError());
1769 /* There should be some content in the listbox. In particular, there should
1770 * be exactly the number of plain files, plus the number of mapped drives,
1771 * plus one "[..]"
1773 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1774 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1775 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1776 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1778 /* Every single item in the control should start with a w and end in .c,
1779 * except for the "[..]" string, which should appear exactly as it is,
1780 * and the mapped drives in the format "[-X-]".
1782 for (i = 0; i < itemCount; i++)
1784 memset(pathBuffer, 0, MAX_PATH);
1785 driveletter = '\0';
1786 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1787 p = pathBuffer + strlen(pathBuffer);
1788 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1789 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1790 else
1791 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1792 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1793 (*(p-1) == 'c' || *(p-1) == 'C') &&
1794 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1797 /* Test behavior when no files match the wildcard */
1798 strcpy(pathBuffer, BAD_EXTENSION);
1799 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1800 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1802 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1803 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1804 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1805 itemCount_justDrives + itemCount_allDirs, itemCount);
1807 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1808 strcpy(pathBuffer, "w*.c");
1809 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1810 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08lx\n", GetLastError());
1812 /* There should be exactly one element: "[..]" */
1813 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1814 ok (itemCount == itemCount_allDirs,
1815 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1816 itemCount, itemCount_allDirs);
1818 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1820 memset(pathBuffer, 0, MAX_PATH);
1821 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1822 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1825 /* Test behavior when no files match the wildcard */
1826 strcpy(pathBuffer, BAD_EXTENSION);
1827 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1828 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1830 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1831 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1833 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1834 strcpy(pathBuffer, "w*.c");
1835 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1836 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08lx\n", GetLastError());
1838 /* There should be no plain files on the listbox */
1839 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1840 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1841 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1842 itemCount, itemCount_justDrives + itemCount_allDirs);
1844 for (i = 0; i < itemCount; i++)
1846 memset(pathBuffer, 0, MAX_PATH);
1847 driveletter = '\0';
1848 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1849 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1850 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1851 else
1852 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1853 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1856 /* Test behavior when no files match the wildcard */
1857 strcpy(pathBuffer, BAD_EXTENSION);
1858 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1859 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1861 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1862 ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1864 /* Now test DlgDirSelectEx() in normal operation */
1865 /* Fill with everything - drives, directory and all plain files. */
1866 strcpy(pathBuffer, "*");
1867 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1868 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08lx\n", GetLastError());
1870 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1871 memset(pathBuffer, 0, MAX_PATH);
1872 SetLastError(0xdeadbeef);
1873 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1874 ok (GetLastError() == 0xdeadbeef,
1875 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08lx\n",
1876 GetLastError());
1877 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1878 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1880 ok (!*pathBuffer, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1882 /* Test proper drive/dir/file recognition */
1883 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1884 for (i = 0; i < itemCount; i++)
1886 memset(itemBuffer, 0, MAX_PATH);
1887 memset(pathBuffer, 0, MAX_PATH);
1888 memset(tempBuffer, 0, MAX_PATH);
1889 driveletter = '\0';
1890 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1891 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1892 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1893 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1895 /* Current item is a drive letter */
1896 SetLastError(0xdeadbeef);
1897 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1898 ok (GetLastError() == 0xdeadbeef,
1899 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
1900 i, GetLastError());
1901 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1903 /* For drive letters, DlgDirSelectEx tacks on a colon */
1904 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1905 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1907 else if (itemBuffer[0] == '[')
1909 /* Current item is the parent directory */
1910 SetLastError(0xdeadbeef);
1911 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1912 ok (GetLastError() == 0xdeadbeef,
1913 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
1914 i, GetLastError());
1915 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1917 /* For directories, DlgDirSelectEx tacks on a backslash */
1918 p = pathBuffer + strlen(pathBuffer);
1919 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1921 tempBuffer[0] = '[';
1922 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1923 strcat(tempBuffer, "]");
1924 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1926 else
1928 /* Current item is a plain file */
1929 SetLastError(0xdeadbeef);
1930 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1931 ok (GetLastError() == 0xdeadbeef,
1932 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
1933 i, GetLastError());
1934 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1936 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1937 * for example, "Makefile", which gets reported as "Makefile."
1939 strcpy(tempBuffer, itemBuffer);
1940 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1941 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1945 DeleteFileA( "wtest1.tmp.c" );
1947 /* Now test DlgDirSelectEx() in abnormal operation */
1948 /* Fill list with bogus entries, that look somewhat valid */
1949 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1950 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1951 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1952 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1953 for (i = 0; i < itemCount; i++)
1955 memset(itemBuffer, 0, MAX_PATH);
1956 memset(pathBuffer, 0, MAX_PATH);
1957 memset(tempBuffer, 0, MAX_PATH);
1958 driveletter = '\0';
1959 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1960 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1961 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1962 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1964 /* Current item is a drive letter */
1965 SetLastError(0xdeadbeef);
1966 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1967 ok (GetLastError() == 0xdeadbeef,
1968 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
1969 i, GetLastError());
1970 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1972 /* For drive letters, DlgDirSelectEx tacks on a colon */
1973 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1974 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1976 else if (itemBuffer[0] == '[')
1978 /* Current item is the parent directory */
1979 SetLastError(0xdeadbeef);
1980 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1981 ok (GetLastError() == 0xdeadbeef,
1982 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
1983 i, GetLastError());
1984 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1986 /* For directories, DlgDirSelectEx tacks on a backslash */
1987 p = pathBuffer + strlen(pathBuffer);
1988 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1990 tempBuffer[0] = '[';
1991 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1992 strcat(tempBuffer, "]");
1993 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1995 else
1997 /* Current item is a plain file */
1998 SetLastError(0xdeadbeef);
1999 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
2000 ok (GetLastError() == 0xdeadbeef,
2001 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08lx\n",
2002 i, GetLastError());
2003 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
2005 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
2006 * This affects for example, "Makefile", which gets reported as "Makefile."
2008 strcpy(tempBuffer, itemBuffer);
2009 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
2010 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
2014 /* Test behavior when loading folders from root with and without wildcard */
2015 strcpy(pathBuffer, "C:\\");
2016 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
2017 ok(res, "DlgDirList failed to list C:\\ folders\n");
2018 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
2020 strcpy(pathBuffer, "C:\\*");
2021 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
2022 ok(res, "DlgDirList failed to list C:\\* folders\n");
2023 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
2025 /* Try loading files from an invalid folder */
2026 SetLastError(0xdeadbeef);
2027 strcpy(pathBuffer, "C:\\INVALID$$DIR");
2028 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
2029 ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
2030 ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
2031 "GetLastError should return 0x589, got 0x%lX\n",GetLastError());
2033 DestroyWindow(hWnd);
2036 static void test_set_count( void )
2038 static const DWORD styles[] =
2040 LBS_OWNERDRAWFIXED,
2041 LBS_HASSTRINGS,
2043 HWND parent, listbox;
2044 unsigned int i;
2045 LONG ret;
2046 RECT r;
2048 parent = create_parent();
2049 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
2051 UpdateWindow( listbox );
2052 GetUpdateRect( listbox, &r, TRUE );
2053 ok( IsRectEmpty( &r ), "got non-empty rect\n");
2055 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
2056 ok( ret == 0, "got %ld\n", ret );
2057 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
2058 ok( ret == 100, "got %ld\n", ret );
2060 GetUpdateRect( listbox, &r, TRUE );
2061 ok( !IsRectEmpty( &r ), "got empty rect\n");
2063 ValidateRect( listbox, NULL );
2064 GetUpdateRect( listbox, &r, TRUE );
2065 ok( IsRectEmpty( &r ), "got non-empty rect\n");
2067 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
2068 ok( ret == 0, "got %ld\n", ret );
2070 GetUpdateRect( listbox, &r, TRUE );
2071 ok( !IsRectEmpty( &r ), "got empty rect\n");
2073 ret = SendMessageA( listbox, LB_SETCOUNT, -5, 0 );
2074 ok( ret == 0, "got %ld\n", ret );
2075 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
2076 ok( ret == -5, "got %ld\n", ret );
2078 DestroyWindow( listbox );
2080 for (i = 0; i < ARRAY_SIZE(styles); ++i)
2082 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
2084 SetLastError( 0xdeadbeef );
2085 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
2086 ok( ret == LB_ERR, "expected %d, got %ld\n", LB_ERR, ret );
2087 ok( GetLastError() == 0xdeadbeef, "Unexpected error %ld.\n", GetLastError() );
2089 DestroyWindow( listbox );
2092 DestroyWindow( parent );
2095 static void test_GetListBoxInfo(void)
2097 static const struct message getlistboxinfo_seq[] =
2099 { LB_GETLISTBOXINFO, sent },
2100 { 0 }
2102 HWND listbox, parent;
2103 DWORD ret;
2105 parent = create_parent();
2106 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2108 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2109 ret = GetListBoxInfo(listbox);
2110 ok(ret > 0, "got %ld\n", ret);
2111 ok_sequence(sequences, LB_SEQ_INDEX, getlistboxinfo_seq, "GetListBoxInfo()", FALSE);
2113 DestroyWindow(listbox);
2114 DestroyWindow(parent);
2117 static void test_init_storage( void )
2119 static const DWORD styles[] =
2121 LBS_HASSTRINGS,
2122 LBS_NODATA | LBS_OWNERDRAWFIXED,
2124 HWND parent, listbox;
2125 LONG ret, items_size;
2126 int i, j;
2128 parent = create_parent();
2129 for (i = 0; i < ARRAY_SIZE(styles); i++)
2131 listbox = CreateWindowA(WC_LISTBOXA, "TestList", styles[i] | WS_CHILD,
2132 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
2134 items_size = SendMessageA(listbox, LB_INITSTORAGE, 100, 0);
2135 ok(items_size >= 100, "expected at least 100, got %ld\n", items_size);
2137 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
2138 ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret);
2140 /* it doesn't grow since the space was already reserved */
2141 ret = SendMessageA(listbox, LB_INITSTORAGE, items_size, 0);
2142 ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret);
2144 /* it doesn't shrink the reserved space */
2145 ret = SendMessageA(listbox, LB_INITSTORAGE, 42, 0);
2146 ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret);
2148 /* now populate almost all of it so it's not reserved anymore */
2149 if (styles[i] & LBS_NODATA)
2151 ret = SendMessageA(listbox, LB_SETCOUNT, items_size - 1, 0);
2152 ok(ret == 0, "unexpected return value %ld\n", ret);
2154 else
2156 for (j = 0; j < items_size - 1; j++)
2158 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2159 ok(ret == j, "expected %d, got %ld\n", j, ret);
2163 /* we still have one more reserved slot, so it doesn't grow yet */
2164 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2165 ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret);
2167 /* fill the slot and check again, it should grow this time */
2168 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, (LPARAM)"");
2169 ok(ret == items_size - 1, "expected %ld, got %ld\n", items_size - 1, ret);
2170 ret = SendMessageA(listbox, LB_INITSTORAGE, 0, 0);
2171 ok(ret == items_size, "expected %ld, got %ld\n", items_size, ret);
2172 ret = SendMessageA(listbox, LB_INITSTORAGE, 1, 0);
2173 ok(ret > items_size, "expected it to grow past %ld, got %ld\n", items_size, ret);
2175 DestroyWindow(listbox);
2177 DestroyWindow(parent);
2180 static void test_missing_lbuttonup(void)
2182 HWND listbox, parent, capture;
2184 parent = create_parent();
2185 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2187 /* Send button down without a corresponding button up */
2188 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10));
2189 capture = GetCapture();
2190 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
2192 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
2193 got_selchange = 0;
2194 SetFocus(NULL);
2195 capture = GetCapture();
2196 ok(capture == NULL, "got %p\n", capture);
2197 ok(got_selchange, "got %d\n", got_selchange);
2199 DestroyWindow(listbox);
2200 DestroyWindow(parent);
2203 static void test_extents(void)
2205 HWND listbox, parent;
2206 SCROLLINFO sinfo;
2207 DWORD res;
2208 BOOL br;
2210 parent = create_parent();
2212 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
2214 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2215 ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res);
2217 sinfo.cbSize = sizeof(sinfo);
2218 sinfo.fMask = SIF_RANGE;
2219 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2220 ok(br == TRUE, "GetScrollInfo failed\n");
2221 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2222 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2223 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2224 "List box should not have a horizontal scroll bar\n");
2226 /* horizontal extent < width */
2227 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2229 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2230 ok(res == 64, "Got wrong horizontal extent: %lu\n", res);
2232 sinfo.cbSize = sizeof(sinfo);
2233 sinfo.fMask = SIF_RANGE;
2234 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2235 ok(br == TRUE, "GetScrollInfo failed\n");
2236 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2237 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2238 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2239 "List box should not have a horizontal scroll bar\n");
2241 /* horizontal extent > width */
2242 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2244 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2245 ok(res == 184, "Got wrong horizontal extent: %lu\n", res);
2247 sinfo.cbSize = sizeof(sinfo);
2248 sinfo.fMask = SIF_RANGE;
2249 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2250 ok(br == TRUE, "GetScrollInfo failed\n");
2251 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2252 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2253 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2254 "List box should not have a horizontal scroll bar\n");
2256 DestroyWindow(listbox);
2258 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
2260 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2261 ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res);
2263 sinfo.cbSize = sizeof(sinfo);
2264 sinfo.fMask = SIF_RANGE;
2265 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2266 ok(br == TRUE, "GetScrollInfo failed\n");
2267 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2268 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
2269 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2270 "List box should not have a horizontal scroll bar\n");
2272 /* horizontal extent < width */
2273 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2275 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2276 ok(res == 64, "Got wrong horizontal extent: %lu\n", res);
2278 sinfo.cbSize = sizeof(sinfo);
2279 sinfo.fMask = SIF_RANGE;
2280 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2281 ok(br == TRUE, "GetScrollInfo failed\n");
2282 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2283 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2284 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2285 "List box should not have a horizontal scroll bar\n");
2287 /* horizontal extent > width */
2288 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2290 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2291 ok(res == 184, "Got wrong horizontal extent: %lu\n", res);
2293 sinfo.cbSize = sizeof(sinfo);
2294 sinfo.fMask = SIF_RANGE;
2295 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2296 ok(br == TRUE, "GetScrollInfo failed\n");
2297 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2298 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2299 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2300 "List box should have a horizontal scroll bar\n");
2302 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2304 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2305 ok(res == 0, "Got wrong horizontal extent: %lu\n", res);
2307 sinfo.cbSize = sizeof(sinfo);
2308 sinfo.fMask = SIF_RANGE;
2309 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2310 ok(br == TRUE, "GetScrollInfo failed\n");
2311 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2312 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2313 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
2314 "List box should not have a horizontal scroll bar\n");
2316 DestroyWindow(listbox);
2319 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
2321 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2322 ok(res == 0, "Got wrong initial horizontal extent: %lu\n", res);
2324 sinfo.cbSize = sizeof(sinfo);
2325 sinfo.fMask = SIF_RANGE;
2326 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2327 ok(br == TRUE, "GetScrollInfo failed\n");
2328 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2329 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2330 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2331 "List box should have a horizontal scroll bar\n");
2333 /* horizontal extent < width */
2334 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2336 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2337 ok(res == 64, "Got wrong horizontal extent: %lu\n", res);
2339 sinfo.cbSize = sizeof(sinfo);
2340 sinfo.fMask = SIF_RANGE;
2341 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2342 ok(br == TRUE, "GetScrollInfo failed\n");
2343 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2344 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2345 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2346 "List box should have a horizontal scroll bar\n");
2348 /* horizontal extent > width */
2349 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2351 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2352 ok(res == 184, "Got wrong horizontal extent: %lu\n", res);
2354 sinfo.cbSize = sizeof(sinfo);
2355 sinfo.fMask = SIF_RANGE;
2356 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2357 ok(br == TRUE, "GetScrollInfo failed\n");
2358 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2359 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2360 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2361 "List box should have a horizontal scroll bar\n");
2363 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2365 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2366 ok(res == 0, "Got wrong horizontal extent: %lu\n", res);
2368 sinfo.cbSize = sizeof(sinfo);
2369 sinfo.fMask = SIF_RANGE;
2370 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2371 ok(br == TRUE, "GetScrollInfo failed\n");
2372 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2373 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2374 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2375 "List box should have a horizontal scroll bar\n");
2377 DestroyWindow(listbox);
2379 DestroyWindow(parent);
2382 static void test_listbox(void)
2384 static const struct listbox_test SS =
2385 /* {add_style} */
2386 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2387 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2388 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2389 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2391 /* {selected, anchor, caret, selcount}{TODO fields} */
2392 static const struct listbox_test SS_NS =
2393 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2394 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2395 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2396 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2398 static const struct listbox_test MS =
2399 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2400 { 1, 1, 1, 1}, {0,0,0,0},
2401 { 2, 1, 2, 1}, {0,0,0,0},
2402 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2404 static const struct listbox_test MS_NS =
2405 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2406 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2407 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2408 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2410 static const struct listbox_test ES =
2411 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2412 { 1, 1, 1, 1}, {0,0,0,0},
2413 { 2, 2, 2, 1}, {0,0,0,0},
2414 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2416 static const struct listbox_test ES_NS =
2417 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2418 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2419 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2420 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2422 static const struct listbox_test EMS =
2423 {{ 0, LB_ERR, 0, 0}, {0,0,0,0},
2424 { 1, 1, 1, 1}, {0,0,0,0},
2425 { 2, 2, 2, 1}, {0,0,0,0},
2426 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2428 static const struct listbox_test EMS_NS =
2429 {{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2430 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2431 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2432 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2434 run_test(0, SS);
2435 run_test(LBS_NOSEL, SS_NS);
2436 run_test(LBS_MULTIPLESEL, MS);
2437 run_test(LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2438 run_test(LBS_EXTENDEDSEL, ES);
2439 run_test(LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2440 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2441 run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2443 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
2444 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
2445 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
2446 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
2447 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
2448 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
2449 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
2450 run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
2453 static const struct message lb_addstring_ownerdraw_parent_seq[] =
2455 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2456 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2457 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2458 { 0 }
2461 static const struct message lb_addstring_sort_parent_seq[] =
2463 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2464 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
2465 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2466 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
2467 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
2468 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2469 { 0 }
2472 static const struct message empty_seq[] =
2474 { 0 }
2477 static void test_WM_MEASUREITEM(void)
2479 HWND parent, listbox;
2480 LRESULT data, ret;
2482 parent = create_parent();
2483 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2485 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2486 ok(data == (LRESULT)strings[0], "data = %08Ix, expected %p\n", data, strings[0]);
2487 DestroyWindow(parent);
2489 parent = create_parent();
2490 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2492 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2493 ok(!data, "data = %08Ix\n", data);
2495 /* LBS_HASSTRINGS */
2496 parent = create_parent();
2497 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2498 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
2499 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2501 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2503 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2504 ok(ret == 0, "expected 0, got %Id\n", ret);
2505 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2506 ok(ret == 1, "expected 1, got %Id\n", ret);
2507 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2508 ok(ret == 2, "expected 2, got %Id\n", ret);
2510 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
2511 "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
2512 DestroyWindow(listbox);
2514 /* LBS_SORT, no LBS_HASSTRINGS */
2515 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2516 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
2517 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2519 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2521 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2522 ok(ret == 0, "expected 0, got %Id\n", ret);
2523 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2524 ok(ret == 1, "expected 1, got %Id\n", ret);
2525 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2526 ok(ret == 2, "expected 2, got %Id\n", ret);
2528 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", FALSE);
2529 DestroyWindow(listbox);
2531 /* LBS_HASSTRINGS */
2532 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2533 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
2534 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2536 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2538 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2539 ok(ret == 0, "expected 0, got %Id\n", ret);
2540 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2541 ok(ret == 1, "expected 1, got %Id\n", ret);
2542 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2543 ok(ret == 2, "expected 2, got %Id\n", ret);
2545 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
2546 DestroyWindow(listbox);
2548 /* LBS_HASSTRINGS, LBS_SORT */
2549 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2550 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
2551 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2553 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2555 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2556 ok(ret == 0, "expected 0, got %Id\n", ret);
2557 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2558 ok(ret == 0, "expected 0, got %Id\n", ret);
2559 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2560 ok(ret == 1, "expected 1, got %Id\n", ret);
2562 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
2563 DestroyWindow(listbox);
2565 DestroyWindow(parent);
2568 static void test_LBS_NODATA(void)
2570 static const DWORD invalid_styles[] =
2573 LBS_OWNERDRAWVARIABLE,
2574 LBS_SORT,
2575 LBS_HASSTRINGS,
2576 LBS_OWNERDRAWFIXED | LBS_SORT,
2577 LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
2579 static const UINT invalid_idx[] = { -2, 2 };
2580 static const UINT valid_idx[] = { 0, 1 };
2581 static const ULONG_PTR zero_data;
2582 HWND listbox, parent;
2583 INT ret, text_len;
2584 unsigned int i;
2585 ULONG_PTR data;
2586 BOOL is_wow64;
2588 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
2589 0, 0, 100, 100, NULL, NULL, NULL, 0);
2590 ok(listbox != NULL, "Failed to create ListBox window.\n");
2592 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2593 ok(ret == 0, "Unexpected return value %d.\n", ret);
2594 ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
2595 ok(ret == 1, "Unexpected return value %d.\n", ret);
2596 ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
2597 ok(ret == 2, "Unexpected return value %d.\n", ret);
2599 /* Invalid indices. */
2600 for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
2602 ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
2603 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2604 ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
2605 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2606 if (ret == LB_ERR)
2608 ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
2609 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2611 ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
2612 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2615 IsWow64Process(GetCurrentProcess(), &is_wow64);
2616 #ifdef _WIN64
2617 text_len = 8;
2618 #else
2619 text_len = is_wow64 ? 8 : 4;
2620 #endif
2622 /* Valid indices. */
2623 for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
2625 ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
2626 ok(ret == TRUE, "Unexpected return value %d.\n", ret);
2627 ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
2628 todo_wine_if(is_wow64)
2629 ok(ret == text_len, "Unexpected return value %d.\n", ret);
2631 memset(&data, 0xee, sizeof(data));
2632 ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
2633 ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
2634 ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
2636 ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
2637 ok(ret == 0, "Unexpected return value %d.\n", ret);
2640 /* More messages that don't work with LBS_NODATA. */
2641 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0);
2642 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2643 ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
2644 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2645 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0);
2646 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2647 ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
2648 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2649 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0);
2650 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2651 ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
2652 ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
2654 DestroyWindow(listbox);
2656 /* Invalid window style combinations. */
2657 parent = create_parent();
2658 ok(parent != NULL, "Failed to create parent window.\n");
2660 for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
2662 DWORD style;
2664 listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
2665 0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
2666 ok(listbox != NULL, "Failed to create a listbox.\n");
2668 style = GetWindowLongA(listbox, GWL_STYLE);
2669 ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#lx.\n", i, style);
2670 ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
2671 ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
2672 DestroyWindow(listbox);
2675 DestroyWindow(parent);
2678 START_TEST(listbox)
2680 ULONG_PTR ctx_cookie;
2681 HANDLE hCtx;
2683 if (!load_v6_module(&ctx_cookie, &hCtx))
2684 return;
2686 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2688 test_listbox();
2689 test_item_height();
2690 test_ownerdraw();
2691 test_LB_SELITEMRANGE();
2692 test_LB_SETCURSEL();
2693 test_listbox_height();
2694 test_changing_selection_styles();
2695 test_itemfrompoint();
2696 test_listbox_item_data();
2697 test_listbox_LB_DIR();
2698 test_listbox_dlgdir();
2699 test_set_count();
2700 test_init_storage();
2701 test_GetListBoxInfo();
2702 test_missing_lbuttonup();
2703 test_extents();
2704 test_WM_MEASUREITEM();
2705 test_LB_SETSEL();
2706 test_LBS_NODATA();
2708 unload_v6_module(ctx_cookie, hCtx);