comctl32/listbox: Fix order of items passed in WM_COMPAREITEM data.
[wine.git] / dlls / comctl32 / tests / listbox.c
blob69d3381cc977f73a2d8c5600662c1cf19c2888d9
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/heap.h"
31 #include "wine/test.h"
32 #include "v6util.h"
33 #include "msg.h"
35 enum 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 HWND create_listbox(DWORD add_style, HWND parent)
95 INT_PTR ctl_id = 0;
96 HWND handle;
98 if (parent)
99 ctl_id = ID_LISTBOX;
101 handle = CreateWindowA(WC_LISTBOXA, "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100,
102 parent, (HMENU)ctl_id, NULL, 0);
103 ok(handle != NULL, "Failed to create listbox window.\n");
105 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[0]);
106 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[1]);
107 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
108 SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
110 return handle;
113 struct listbox_prop
115 DWORD add_style;
118 struct listbox_stat
120 int selected, anchor, caret, selcount;
123 struct listbox_test
125 struct listbox_prop prop;
126 struct listbox_stat init, init_todo;
127 struct listbox_stat click, click_todo;
128 struct listbox_stat step, step_todo;
129 struct listbox_stat sel, sel_todo;
132 static void listbox_query(HWND handle, struct listbox_stat *results)
134 results->selected = SendMessageA(handle, LB_GETCURSEL, 0, 0);
135 results->anchor = SendMessageA(handle, LB_GETANCHORINDEX, 0, 0);
136 results->caret = SendMessageA(handle, LB_GETCARETINDEX, 0, 0);
137 results->selcount = SendMessageA(handle, LB_GETSELCOUNT, 0, 0);
140 static void buttonpress(HWND handle, WORD x, WORD y)
142 LPARAM lp = x + (y << 16);
144 SendMessageA(handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
145 SendMessageA(handle, WM_LBUTTONUP, 0, lp);
148 static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
150 LPARAM lp = 1 + (scancode << 16) + (extended ? KEYEVENTF_EXTENDEDKEY : 0);
152 SendMessageA(handle, WM_KEYDOWN, keycode, lp);
153 SendMessageA(handle, WM_KEYUP , keycode, lp | 0xc000000);
156 #define listbox_field_ok(t, s, f, got) \
157 ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
158 ": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
159 t.s.f, got.f)
161 #define listbox_todo_field_ok(t, s, f, got) \
162 todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
164 #define listbox_ok(t, s, got) \
165 listbox_todo_field_ok(t, s, selected, got); \
166 listbox_todo_field_ok(t, s, anchor, got); \
167 listbox_todo_field_ok(t, s, caret, got); \
168 listbox_todo_field_ok(t, s, selcount, got)
170 static void run_test(const struct listbox_test test)
172 struct listbox_stat answer;
173 HWND hLB=create_listbox (test.prop.add_style, 0);
174 RECT second_item;
175 int i, res;
177 listbox_query (hLB, &answer);
178 listbox_ok (test, init, answer);
180 SendMessageA(hLB, LB_GETITEMRECT, 1, (LPARAM) &second_item);
181 buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top);
183 listbox_query(hLB, &answer);
184 listbox_ok(test, click, answer);
186 keypress(hLB, VK_DOWN, 0x50, TRUE);
188 listbox_query(hLB, &answer);
189 listbox_ok(test, step, answer);
191 DestroyWindow(hLB);
193 hLB = create_listbox(test.prop.add_style, 0);
195 SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
196 listbox_query(hLB, &answer);
197 listbox_ok(test, sel, answer);
199 for (i = 0; i < 4; i++)
201 DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
202 int resA, resW;
203 WCHAR *txtw;
204 CHAR *txt;
206 txt = heap_alloc_zero(size + 1);
207 resA = SendMessageA(hLB, LB_GETTEXT, i, (LPARAM)txt);
208 ok(!strcmp(txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
210 txtw = heap_alloc_zero((size + 1) * sizeof(*txtw));
211 resW = SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
212 if (resA != resW)
213 trace("SendMessageW(LB_GETTEXT) not supported on this platform (resA=%d resW=%d), skipping...\n", resA, resW);
214 else
216 WideCharToMultiByte(CP_ACP, 0, txtw, -1, txt, size, NULL, NULL);
217 ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
220 heap_free(txtw);
221 heap_free(txt);
224 /* Confirm the count of items, and that an invalid delete does not remove anything */
225 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
226 ok(res == 4, "Expected 4 items, got %d\n", res);
227 res = SendMessageA(hLB, LB_DELETESTRING, -1, 0);
228 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
229 res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
230 ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
231 res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
232 ok(res == 4, "Expected 4 items, got %d\n", res);
234 DestroyWindow(hLB);
237 static void test_item_height(void)
239 INT itemHeight;
240 TEXTMETRICA tm;
241 HFONT font;
242 HWND hLB;
243 HDC hdc;
245 hLB = create_listbox (0, 0);
246 ok ((hdc = GetDCEx( hLB, 0, DCX_CACHE )) != 0, "Can't get hdc\n");
247 ok ((font = GetCurrentObject(hdc, OBJ_FONT)) != 0, "Can't get the current font\n");
248 ok (GetTextMetricsA( hdc, &tm ), "Can't read font metrics\n");
249 ReleaseDC( hLB, hdc);
251 ok (SendMessageA(hLB, WM_SETFONT, (WPARAM)font, 0) == 0, "Can't set font\n");
253 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
254 ok (itemHeight == tm.tmHeight, "Item height wrong, got %d, expecting %d\n", itemHeight, tm.tmHeight);
256 DestroyWindow (hLB);
258 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100, NULL, NULL, NULL, 0);
260 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
261 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
262 itemHeight, tm.tmHeight);
263 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, 5, 0);
264 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
265 itemHeight, tm.tmHeight);
266 itemHeight = SendMessageA(hLB, LB_GETITEMHEIGHT, -5, 0);
267 ok(itemHeight > 0 && itemHeight <= tm.tmHeight, "Unexpected item height %d, expected %d.\n",
268 itemHeight, tm.tmHeight);
270 DestroyWindow (hLB);
273 static int got_selchange;
275 static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
277 static LONG defwndproc_counter = 0;
278 struct message m = { 0 };
279 LRESULT ret;
281 m.message = msg;
282 m.flags = sent|wparam|lparam;
283 if (defwndproc_counter) m.flags |= defwinproc;
284 m.wParam = wParam;
285 m.lParam = lParam;
287 switch (msg)
289 case WM_MEASUREITEM:
291 MEASUREITEMSTRUCT *mis = (void *)lParam;
292 BOOL is_unicode_data = FALSE;
293 MEASURE_ITEM_STRUCT mi;
295 if (mis->CtlType == ODT_LISTBOX)
297 HWND ctrl = GetDlgItem(hwnd, mis->CtlID);
298 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
301 mi.u.wp = 0;
302 mi.u.item.CtlType = mis->CtlType;
303 mi.u.item.CtlID = mis->CtlID;
304 mi.u.item.itemID = mis->itemID;
305 mi.u.item.wParam = wParam;
307 m.wParam = mi.u.wp;
308 if (is_unicode_data)
309 m.lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
310 else
311 m.lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
312 add_message(sequences, PARENT_SEQ_INDEX, &m);
314 ok(wParam == mis->CtlID, "got wParam=%08lx, expected %08x\n", wParam, mis->CtlID);
315 ok(mis->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mis->CtlType);
316 ok(mis->CtlID == 1, "mi->CtlID = %u\n", mis->CtlID);
317 ok(mis->itemHeight, "mi->itemHeight = 0\n");
319 break;
321 case WM_COMPAREITEM:
323 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lParam;
324 HWND ctrl = GetDlgItem(hwnd, cis->CtlID);
325 BOOL is_unicode_data = TRUE;
327 ok(wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, wParam);
328 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
329 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
330 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
332 if (cis->CtlType == ODT_LISTBOX)
333 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
335 if (is_unicode_data)
337 m.wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
338 m.lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
340 else
342 m.wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
343 m.lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
345 add_message(sequences, PARENT_SEQ_INDEX, &m);
346 break;
348 case WM_DRAWITEM:
350 RECT rc_item, rc_client, rc_clip;
351 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
353 ok(wParam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wParam, dis->CtlID);
354 ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
356 GetClientRect(dis->hwndItem, &rc_client);
357 GetClipBox(dis->hDC, &rc_clip);
358 ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
359 "client rect of the listbox should be equal to the clip box,"
360 "or the clip box should be empty\n");
362 SendMessageA(dis->hwndItem, LB_GETITEMRECT, dis->itemID, (LPARAM)&rc_item);
363 ok(EqualRect(&dis->rcItem, &rc_item), "item rects are not equal\n");
365 break;
368 case WM_COMMAND:
369 if (HIWORD( wParam ) == LBN_SELCHANGE) got_selchange++;
370 break;
372 default:
373 break;
376 defwndproc_counter++;
377 ret = DefWindowProcA(hwnd, msg, wParam, lParam);
378 defwndproc_counter--;
380 return msg == WM_COMPAREITEM ? -1 : ret;
383 static HWND create_parent( void )
385 static ATOM class;
386 WNDCLASSA cls;
388 if (!class)
390 cls.style = 0;
391 cls.lpfnWndProc = main_window_proc;
392 cls.cbClsExtra = 0;
393 cls.cbWndExtra = 0;
394 cls.hInstance = GetModuleHandleA(NULL);
395 cls.hIcon = 0;
396 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
397 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
398 cls.lpszMenuName = NULL;
399 cls.lpszClassName = "main_window_class";
400 class = RegisterClassA( &cls );
403 return CreateWindowExA(0, "main_window_class", NULL, WS_POPUP | WS_VISIBLE, 100, 100, 400, 400, GetDesktopWindow(),
404 0, GetModuleHandleA(NULL), NULL);
407 static void test_ownerdraw(void)
409 HWND parent, hLB;
410 INT ret;
411 RECT rc;
413 parent = create_parent();
414 ok(parent != NULL, "Failed to create parent window.\n");
416 hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
417 ok(hLB != NULL, "Failed to create listbox window.\n");
419 SetForegroundWindow(hLB);
420 UpdateWindow(hLB);
422 /* make height short enough */
423 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
424 SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, SWP_NOZORDER | SWP_NOMOVE);
426 /* make 0 item invisible */
427 SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
428 ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
429 ok(ret == 1, "wrong top index %d\n", ret);
431 SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
432 ok(!IsRectEmpty(&rc), "empty item rect\n");
433 ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
435 DestroyWindow(hLB);
436 DestroyWindow(parent);
439 #define listbox_test_query(exp, got) \
440 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
441 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
442 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
443 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
445 static void test_LB_SELITEMRANGE(void)
447 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
448 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
449 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
450 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
451 struct listbox_stat answer;
452 HWND hLB;
453 INT ret;
455 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
456 ok(hLB != NULL, "Failed to create listbox window.\n");
458 listbox_query(hLB, &answer);
459 listbox_test_query(test_nosel, answer);
461 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
462 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
463 listbox_query(hLB, &answer);
464 listbox_test_query(test_1, answer);
466 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
467 listbox_query(hLB, &answer);
468 listbox_test_query(test_nosel, answer);
470 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
471 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
472 listbox_query(hLB, &answer);
473 listbox_test_query(test_3, answer);
475 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
476 listbox_query(hLB, &answer);
477 listbox_test_query(test_nosel, answer);
479 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
480 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
481 listbox_query(hLB, &answer);
482 listbox_test_query(test_nosel, answer);
484 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
485 listbox_query(hLB, &answer);
486 listbox_test_query(test_nosel, answer);
488 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
489 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
490 listbox_query(hLB, &answer);
491 listbox_test_query(test_1, answer);
493 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
494 listbox_query(hLB, &answer);
495 listbox_test_query(test_nosel, answer);
497 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
498 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
499 listbox_query(hLB, &answer);
500 listbox_test_query(test_nosel, answer);
502 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
503 listbox_query(hLB, &answer);
504 listbox_test_query(test_nosel, answer);
506 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
507 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
508 listbox_query(hLB, &answer);
509 listbox_test_query(test_2, answer);
511 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
512 listbox_query(hLB, &answer);
513 listbox_test_query(test_nosel, answer);
515 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
516 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
517 listbox_query(hLB, &answer);
518 listbox_test_query(test_2, answer);
520 DestroyWindow(hLB);
523 static void test_LB_SETCURSEL(void)
525 HWND parent, hLB;
526 INT ret;
528 parent = create_parent();
529 ok(parent != NULL, "Failed to create parent window.\n");
531 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
532 ok(hLB != NULL, "Failed to create listbox.\n");
534 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
536 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
537 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
538 ret = GetScrollPos(hLB, SB_VERT);
539 ok(ret == 0, "expected vscroll 0, got %d\n", ret);
541 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
542 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
543 ret = GetScrollPos(hLB, SB_VERT);
544 ok(ret == 1, "expected vscroll 1, got %d\n", ret);
546 DestroyWindow(hLB);
549 static void test_listbox_height(void)
551 HWND hList;
552 int r, id;
554 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
555 1, 1, 600, 100, NULL, NULL, NULL, NULL );
556 ok( hList != NULL, "failed to create listbox\n");
558 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
559 ok( id == 0, "item id wrong\n");
561 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
562 ok( r == 0, "send message failed\n");
564 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
565 ok( r == 20, "height wrong\n");
567 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
568 ok( r == -1, "send message failed\n");
570 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
571 ok( r == 20, "height wrong\n");
573 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 256, 0 ));
574 ok( r == -1, "Failed to set item height, %d.\n", r);
576 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
577 ok( r == 20, "Unexpected item height %d.\n", r);
579 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
580 ok( r == 0, "send message failed\n");
582 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
583 ok( r == 0xff, "height wrong\n");
585 DestroyWindow( hList );
588 static void test_itemfrompoint(void)
590 /* WS_POPUP is required in order to have a more accurate size calculation (
591 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
592 behavior of partially-displayed item.
594 HWND hList = CreateWindowA( WC_LISTBOXA, "list test",
595 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
596 1, 1, 600, 100, NULL, NULL, NULL, NULL );
597 ULONG r, id;
598 RECT rc;
600 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
601 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
603 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
604 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
606 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
607 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
609 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
610 ok( id == 0, "item id wrong\n");
611 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
612 ok( id == 1, "item id wrong\n");
614 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
615 ok( r == 0x1, "ret %x\n", r );
617 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
618 ok( r == MAKELPARAM(1, 1), "Unexpected ret value %#x.\n", r );
620 /* Resize control so that below assertions about sizes are valid */
621 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
622 ok( r == 1, "ret %x\n", r);
623 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
624 ok( r != 0, "ret %x\n", r);
626 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
627 ok( id == 2, "item id wrong\n");
628 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
629 ok( id == 3, "item id wrong\n");
630 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
631 ok( id == 4, "item id wrong\n");
632 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
633 ok( id == 5, "item id wrong\n");
634 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
635 ok( id == 6, "item id wrong\n");
636 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
637 ok( id == 7, "item id wrong\n");
639 /* Set the listbox up so that id 1 is at the top, this leaves 5
640 partially visible at the bottom and 6, 7 are invisible */
642 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
643 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
644 ok( r == 1, "top %d\n", r);
646 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
647 ok( r == 1, "ret %x\n", r);
648 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
649 ok( r == 0, "ret %x\n", r);
651 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
652 ok( r == 1, "ret %x\n", r);
654 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
655 ok( r == 0x10001, "ret %x\n", r );
657 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
658 ok( r == 0x10001, "ret %x\n", r );
660 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
661 ok( r == 0x10005, "item %x\n", r );
663 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
664 ok( r == 0x10005, "item %x\n", r );
666 DestroyWindow( hList );
669 static void test_listbox_item_data(void)
671 HWND hList;
672 int r, id;
674 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
675 1, 1, 600, 100, NULL, NULL, NULL, NULL );
676 ok( hList != NULL, "failed to create listbox\n");
678 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
679 ok( id == 0, "item id wrong\n");
681 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
682 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
684 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
685 ok( r == 20, "get item data failed\n");
687 DestroyWindow( hList );
690 static void test_listbox_LB_DIR(void)
692 HWND hList;
693 int res, itemCount;
694 int itemCount_justFiles;
695 int itemCount_justDrives;
696 int itemCount_allFiles;
697 int itemCount_allDirs;
698 int i;
699 char pathBuffer[MAX_PATH];
700 char * p;
701 char driveletter;
702 const char *wildcard = "*";
703 HANDLE file;
705 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
706 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
707 CloseHandle( file );
709 /* NOTE: for this test to succeed, there must be no subdirectories
710 under the current directory. In addition, there must be at least
711 one file that fits the wildcard w*.c . Normally, the test
712 directory itself satisfies both conditions.
714 hList = CreateWindowA( WC_LISTBOXA, "list test", WS_VISIBLE|WS_POPUP,
715 1, 1, 600, 100, NULL, NULL, NULL, NULL );
716 ok(hList != NULL, "Failed to create listbox window.\n");
718 /* Test for standard usage */
720 /* This should list all the files in the test directory. */
721 strcpy(pathBuffer, wildcard);
722 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
723 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
724 if (res == -1) /* "*" wildcard doesn't work on win9x */
726 wildcard = "*.*";
727 strcpy(pathBuffer, wildcard);
728 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
730 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
732 /* There should be some content in the listbox */
733 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
734 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
735 itemCount_allFiles = itemCount;
736 ok(res + 1 == itemCount,
737 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
738 itemCount - 1, res);
740 /* This tests behavior when no files match the wildcard */
741 strcpy(pathBuffer, BAD_EXTENSION);
742 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
743 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
744 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
746 /* There should be NO content in the listbox */
747 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
748 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
751 /* This should list all the w*.c files in the test directory
752 * As of this writing, this includes win.c, winstation.c, wsprintf.c
754 strcpy(pathBuffer, "w*.c");
755 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
756 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
757 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
759 /* Path specification does NOT converted to uppercase */
760 ok (!strcmp(pathBuffer, "w*.c"),
761 "expected no change to pathBuffer, got %s\n", pathBuffer);
763 /* There should be some content in the listbox */
764 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
765 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
766 itemCount_justFiles = itemCount;
767 ok(res + 1 == itemCount,
768 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
769 itemCount - 1, res);
771 /* Every single item in the control should start with a w and end in .c */
772 for (i = 0; i < itemCount; i++)
774 memset(pathBuffer, 0, MAX_PATH);
775 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
776 p = pathBuffer + strlen(pathBuffer);
777 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
778 (*(p-1) == 'c' || *(p-1) == 'C') &&
779 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
782 /* Test DDL_DIRECTORY */
783 strcpy(pathBuffer, wildcard);
784 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
785 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
786 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
788 /* There should be some content in the listbox.
789 * All files plus "[..]"
791 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
792 itemCount_allDirs = itemCount - itemCount_allFiles;
793 ok (itemCount >= itemCount_allFiles,
794 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
795 itemCount, itemCount_allFiles);
796 ok(res + 1 == itemCount,
797 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
798 itemCount - 1, res);
800 /* This tests behavior when no files match the wildcard */
801 strcpy(pathBuffer, BAD_EXTENSION);
802 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
803 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
804 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
806 /* There should be NO content in the listbox */
807 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
808 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
810 /* Test DDL_DIRECTORY */
811 strcpy(pathBuffer, "w*.c");
812 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
813 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
814 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
816 /* There should be some content in the listbox. Since the parent directory does not
817 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
819 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
820 ok (itemCount == itemCount_justFiles,
821 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
822 itemCount, itemCount_justFiles);
823 ok(res + 1 == itemCount,
824 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
825 itemCount - 1, res);
827 /* Every single item in the control should start with a w and end in .c. */
828 for (i = 0; i < itemCount; i++)
830 memset(pathBuffer, 0, MAX_PATH);
831 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
832 p = pathBuffer + strlen(pathBuffer);
834 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
835 (*(p-1) == 'c' || *(p-1) == 'C') &&
836 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
839 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
840 strcpy(pathBuffer, wildcard);
841 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
842 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
843 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
845 /* There should be some content in the listbox. In particular, there should
846 * be at least one element before, since the string "[-c-]" should
847 * have been added. Depending on the user setting, more drives might have
848 * been added.
850 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
851 ok (itemCount >= 1,
852 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
853 itemCount, 1);
854 itemCount_justDrives = itemCount;
855 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
857 /* Every single item in the control should fit the format [-c-] */
858 for (i = 0; i < itemCount; i++)
860 memset(pathBuffer, 0, MAX_PATH);
861 driveletter = '\0';
862 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
863 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
864 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
865 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
866 if (!(driveletter >= 'a' && driveletter <= 'z'))
868 /* Correct after invalid entry is found */
869 itemCount_justDrives--;
873 /* This tests behavior when no files match the wildcard */
874 strcpy(pathBuffer, BAD_EXTENSION);
875 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
876 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
877 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
878 BAD_EXTENSION, res, itemCount_justDrives -1);
880 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
881 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
882 itemCount, itemCount_justDrives);
884 /* Test DDL_DRIVES. */
885 strcpy(pathBuffer, wildcard);
886 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
887 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
888 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
890 /* There should be some content in the listbox. In particular, there should
891 * be at least one element before, since the string "[-c-]" should
892 * have been added. Depending on the user setting, more drives might have
893 * been added.
895 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
896 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
897 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
898 itemCount, itemCount_justDrives + itemCount_allFiles);
899 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
901 /* This tests behavior when no files match the wildcard */
902 strcpy(pathBuffer, BAD_EXTENSION);
903 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
904 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
905 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
906 BAD_EXTENSION, res, itemCount_justDrives -1);
908 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
909 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
911 /* Test DDL_DRIVES. */
912 strcpy(pathBuffer, "w*.c");
913 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
914 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
915 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
917 /* There should be some content in the listbox. In particular, there should
918 * be at least one element before, since the string "[-c-]" should
919 * have been added. Depending on the user setting, more drives might have
920 * been added.
922 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
923 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
924 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
925 itemCount, itemCount_justDrives + itemCount_justFiles);
926 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
928 /* Every single item in the control should fit the format [-c-], or w*.c */
929 for (i = 0; i < itemCount; i++)
931 memset(pathBuffer, 0, MAX_PATH);
932 driveletter = '\0';
933 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
934 p = pathBuffer + strlen(pathBuffer);
935 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
937 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
938 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
940 else
943 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
944 (*(p-1) == 'c' || *(p-1) == 'C') &&
945 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
949 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
950 strcpy(pathBuffer, wildcard);
951 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
952 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
953 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
955 /* There should be some content in the listbox. In particular, there should
956 * be exactly the number of plain files, plus the number of mapped drives.
958 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
959 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
960 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
961 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
962 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
964 /* Every single item in the control should start with a w and end in .c,
965 * except for the "[..]" string, which should appear exactly as it is,
966 * and the mapped drives in the format "[-X-]".
968 for (i = 0; i < itemCount; i++)
970 memset(pathBuffer, 0, MAX_PATH);
971 driveletter = '\0';
972 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
973 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
974 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
977 /* This tests behavior when no files match the wildcard */
978 strcpy(pathBuffer, BAD_EXTENSION);
979 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
980 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
981 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
982 BAD_EXTENSION, res, itemCount_justDrives -1);
984 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
985 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
987 /* Test DDL_DIRECTORY|DDL_DRIVES. */
988 strcpy(pathBuffer, "w*.c");
989 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
990 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
991 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
993 /* There should be some content in the listbox. In particular, there should
994 * be exactly the number of plain files, plus the number of mapped drives.
996 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
997 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
998 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
999 itemCount, itemCount_justFiles + itemCount_justDrives);
1000 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1002 /* Every single item in the control should start with a w and end in .c,
1003 * except the mapped drives in the format "[-X-]". The "[..]" directory
1004 * should not appear.
1006 for (i = 0; i < itemCount; i++)
1008 memset(pathBuffer, 0, MAX_PATH);
1009 driveletter = '\0';
1010 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1011 p = pathBuffer + strlen(pathBuffer);
1012 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1013 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1014 else
1016 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1017 (*(p-1) == 'c' || *(p-1) == 'C') &&
1018 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1021 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1022 strcpy(pathBuffer, wildcard);
1023 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1024 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1025 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n",
1026 GetLastError());
1028 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1029 ok (itemCount == itemCount_allDirs,
1030 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1031 itemCount, itemCount_allDirs);
1032 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1034 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1036 memset(pathBuffer, 0, MAX_PATH);
1037 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1038 ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
1041 /* This tests behavior when no files match the wildcard */
1042 strcpy(pathBuffer, BAD_EXTENSION);
1043 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1044 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1045 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1046 BAD_EXTENSION, res, -1);
1048 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1049 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1052 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1053 strcpy(pathBuffer, "w*.c");
1054 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1055 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1056 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1058 /* There should be no elements, since "[..]" does not fit w*.c */
1059 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1060 ok (itemCount == 0,
1061 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1062 itemCount, 0);
1064 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1065 strcpy(pathBuffer, wildcard);
1066 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1067 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1068 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1070 /* There should be no plain files on the listbox */
1071 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1072 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1073 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1074 itemCount, itemCount_justDrives + itemCount_allDirs);
1075 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1077 for (i = 0; i < itemCount; i++)
1079 memset(pathBuffer, 0, MAX_PATH);
1080 driveletter = '\0';
1081 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1082 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1083 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1084 else
1085 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1086 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1089 /* This tests behavior when no files match the wildcard */
1090 strcpy(pathBuffer, BAD_EXTENSION);
1091 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1092 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1093 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1094 BAD_EXTENSION, res, itemCount_justDrives -1);
1096 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1097 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1099 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1100 strcpy(pathBuffer, "w*.c");
1101 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1102 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1103 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1105 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1106 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1107 ok (itemCount == itemCount_justDrives,
1108 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1109 itemCount, itemCount_justDrives);
1110 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1112 for (i = 0; i < itemCount; i++)
1114 memset(pathBuffer, 0, MAX_PATH);
1115 driveletter = '\0';
1116 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1117 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1118 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1120 DestroyWindow(hList);
1122 DeleteFileA( "wtest1.tmp.c" );
1125 static HWND g_listBox;
1126 static HWND g_label;
1128 #define ID_TEST_LABEL 1001
1129 #define ID_TEST_LISTBOX 1002
1131 static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs)
1133 g_label = CreateWindowA(WC_STATICA, "Contents of static control before DlgDirList.",
1134 WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1135 if (!g_label) return FALSE;
1137 g_listBox = CreateWindowA(WC_LISTBOXA, "DlgDirList test",
1138 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256,
1139 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1140 if (!g_listBox) return FALSE;
1142 return TRUE;
1145 static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1147 LRESULT result = 0;
1149 switch (uiMsg)
1151 case WM_DESTROY:
1152 PostQuitMessage(0);
1153 break;
1154 case WM_CREATE:
1155 result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1;
1156 break;
1157 default:
1158 result = DefWindowProcA(hwnd, uiMsg, wParam, lParam);
1159 break;
1161 return result;
1164 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1166 WNDCLASSA cls;
1168 cls.style = 0;
1169 cls.cbClsExtra = 0;
1170 cls.cbWndExtra = 0;
1171 cls.hInstance = hInst;
1172 cls.hIcon = NULL;
1173 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1174 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1175 cls.lpszMenuName = NULL;
1176 cls.lpfnWndProc = listbox_container_window_procA;
1177 cls.lpszClassName = "ListboxContainerClass";
1178 if (!RegisterClassA (&cls)) return FALSE;
1180 return TRUE;
1183 static void test_listbox_dlgdir(void)
1185 HINSTANCE hInst;
1186 HWND hWnd;
1187 int res, itemCount;
1188 int itemCount_allDirs;
1189 int itemCount_justFiles;
1190 int itemCount_justDrives;
1191 int i;
1192 char pathBuffer[MAX_PATH];
1193 char itemBuffer[MAX_PATH];
1194 char tempBuffer[MAX_PATH];
1195 char * p;
1196 char driveletter;
1197 HANDLE file;
1198 BOOL ret;
1200 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1201 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1202 CloseHandle( file );
1204 /* NOTE: for this test to succeed, there must be no subdirectories
1205 under the current directory. In addition, there must be at least
1206 one file that fits the wildcard w*.c . Normally, the test
1207 directory itself satisfies both conditions.
1210 hInst = GetModuleHandleA(0);
1211 ret = RegisterListboxWindowClass(hInst);
1212 ok(ret, "Failed to register test class.\n");
1214 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1215 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1216 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1217 NULL, NULL, hInst, 0);
1218 ok(hWnd != NULL, "Failed to create container window.\n");
1220 /* Test for standard usage */
1222 /* The following should be overwritten by the directory path */
1223 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1225 /* This should list all the w*.c files in the test directory
1226 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1228 strcpy(pathBuffer, "w*.c");
1229 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1230 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1232 /* Path specification gets converted to uppercase */
1233 ok (!strcmp(pathBuffer, "W*.C"),
1234 "expected conversion to uppercase, got %s\n", pathBuffer);
1236 /* Loaded path should have overwritten the label text */
1237 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1238 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1240 /* There should be some content in the listbox */
1241 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1242 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1243 itemCount_justFiles = itemCount;
1245 /* Every single item in the control should start with a w and end in .c */
1246 for (i = 0; i < itemCount; i++)
1248 memset(pathBuffer, 0, MAX_PATH);
1249 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1250 p = pathBuffer + strlen(pathBuffer);
1251 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1252 (*(p-1) == 'c' || *(p-1) == 'C') &&
1253 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1256 /* Test behavior when no files match the wildcard */
1257 strcpy(pathBuffer, BAD_EXTENSION);
1258 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1259 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1261 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1262 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1264 /* Test DDL_DIRECTORY */
1265 strcpy(pathBuffer, "w*.c");
1266 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1267 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1269 /* There should be some content in the listbox. In particular, there should
1270 * be exactly more elements than before, since the directories should
1271 * have been added.
1273 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1274 itemCount_allDirs = itemCount - itemCount_justFiles;
1275 ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1276 itemCount, itemCount_justFiles);
1278 /* Every single item in the control should start with a w and end in .c,
1279 * except for the "[..]" string, which should appear exactly as it is.
1281 for (i = 0; i < itemCount; i++)
1283 memset(pathBuffer, 0, MAX_PATH);
1284 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1285 p = pathBuffer + strlen(pathBuffer);
1286 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1287 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1288 (*(p-1) == 'c' || *(p-1) == 'C') &&
1289 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1292 /* Test behavior when no files match the wildcard */
1293 strcpy(pathBuffer, BAD_EXTENSION);
1294 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1295 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1297 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1298 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1299 itemCount_allDirs, itemCount);
1300 for (i = 0; i < itemCount; i++)
1302 memset(pathBuffer, 0, MAX_PATH);
1303 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1304 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1305 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1308 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1309 strcpy(pathBuffer, "w*.c");
1310 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1311 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1313 /* There should be some content in the listbox. In particular, there should
1314 * be at least one element before, since the string "[-c-]" should
1315 * have been added. Depending on the user setting, more drives might have
1316 * been added.
1318 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1319 ok (itemCount >= 1,
1320 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1321 itemCount, 1);
1322 itemCount_justDrives = itemCount;
1324 /* Every single item in the control should fit the format [-c-] */
1325 for (i = 0; i < itemCount; i++)
1327 memset(pathBuffer, 0, MAX_PATH);
1328 driveletter = '\0';
1329 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1330 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1331 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1332 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1333 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1334 /* Correct after invalid entry is found */
1335 trace("removing count of invalid entry %s\n", pathBuffer);
1336 itemCount_justDrives--;
1340 /* Test behavior when no files match the wildcard */
1341 strcpy(pathBuffer, BAD_EXTENSION);
1342 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1343 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1345 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1346 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1348 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1349 strcpy(pathBuffer, "w*.c");
1350 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1351 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1353 /* There should be some content in the listbox. In particular, there should
1354 * be exactly the number of plain files, plus the number of mapped drives,
1355 * plus one "[..]"
1357 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1358 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1359 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1360 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1362 /* Every single item in the control should start with a w and end in .c,
1363 * except for the "[..]" string, which should appear exactly as it is,
1364 * and the mapped drives in the format "[-X-]".
1366 for (i = 0; i < itemCount; i++)
1368 memset(pathBuffer, 0, MAX_PATH);
1369 driveletter = '\0';
1370 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1371 p = pathBuffer + strlen(pathBuffer);
1372 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1373 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1374 else
1375 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1376 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1377 (*(p-1) == 'c' || *(p-1) == 'C') &&
1378 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1381 /* Test behavior when no files match the wildcard */
1382 strcpy(pathBuffer, BAD_EXTENSION);
1383 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1384 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1386 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1387 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1388 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1389 itemCount_justDrives + itemCount_allDirs, itemCount);
1391 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1392 strcpy(pathBuffer, "w*.c");
1393 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1394 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1396 /* There should be exactly one element: "[..]" */
1397 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1398 ok (itemCount == itemCount_allDirs,
1399 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1400 itemCount, itemCount_allDirs);
1402 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1404 memset(pathBuffer, 0, MAX_PATH);
1405 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1406 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1409 /* Test behavior when no files match the wildcard */
1410 strcpy(pathBuffer, BAD_EXTENSION);
1411 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1412 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1414 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1415 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1417 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1418 strcpy(pathBuffer, "w*.c");
1419 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1420 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1422 /* There should be no plain files on the listbox */
1423 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1424 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1425 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1426 itemCount, itemCount_justDrives + itemCount_allDirs);
1428 for (i = 0; i < itemCount; i++)
1430 memset(pathBuffer, 0, MAX_PATH);
1431 driveletter = '\0';
1432 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1433 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1434 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1435 else
1436 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1437 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1440 /* Test behavior when no files match the wildcard */
1441 strcpy(pathBuffer, BAD_EXTENSION);
1442 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1443 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1445 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1446 ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1448 /* Now test DlgDirSelectEx() in normal operation */
1449 /* Fill with everything - drives, directory and all plain files. */
1450 strcpy(pathBuffer, "*");
1451 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1452 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1454 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1455 memset(pathBuffer, 0, MAX_PATH);
1456 SetLastError(0xdeadbeef);
1457 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1458 ok (GetLastError() == 0xdeadbeef,
1459 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1460 GetLastError());
1461 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1462 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1464 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1466 /* Test proper drive/dir/file recognition */
1467 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1468 for (i = 0; i < itemCount; i++)
1470 memset(itemBuffer, 0, MAX_PATH);
1471 memset(pathBuffer, 0, MAX_PATH);
1472 memset(tempBuffer, 0, MAX_PATH);
1473 driveletter = '\0';
1474 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1475 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1476 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1477 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1479 /* Current item is a drive letter */
1480 SetLastError(0xdeadbeef);
1481 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1482 ok (GetLastError() == 0xdeadbeef,
1483 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1484 i, GetLastError());
1485 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1487 /* For drive letters, DlgDirSelectEx tacks on a colon */
1488 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1489 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1491 else if (itemBuffer[0] == '[')
1493 /* Current item is the parent directory */
1494 SetLastError(0xdeadbeef);
1495 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1496 ok (GetLastError() == 0xdeadbeef,
1497 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1498 i, GetLastError());
1499 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1501 /* For directories, DlgDirSelectEx tacks on a backslash */
1502 p = pathBuffer + strlen(pathBuffer);
1503 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1505 tempBuffer[0] = '[';
1506 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1507 strcat(tempBuffer, "]");
1508 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1510 else
1512 /* Current item is a plain file */
1513 SetLastError(0xdeadbeef);
1514 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1515 ok (GetLastError() == 0xdeadbeef,
1516 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1517 i, GetLastError());
1518 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1520 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1521 * for example, "Makefile", which gets reported as "Makefile."
1523 strcpy(tempBuffer, itemBuffer);
1524 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1525 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1529 DeleteFileA( "wtest1.tmp.c" );
1531 /* Now test DlgDirSelectEx() in abnormal operation */
1532 /* Fill list with bogus entries, that look somewhat valid */
1533 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1534 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1535 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1536 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1537 for (i = 0; i < itemCount; i++)
1539 memset(itemBuffer, 0, MAX_PATH);
1540 memset(pathBuffer, 0, MAX_PATH);
1541 memset(tempBuffer, 0, MAX_PATH);
1542 driveletter = '\0';
1543 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1544 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1545 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1546 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1548 /* Current item is a drive letter */
1549 SetLastError(0xdeadbeef);
1550 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1551 ok (GetLastError() == 0xdeadbeef,
1552 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1553 i, GetLastError());
1554 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1556 /* For drive letters, DlgDirSelectEx tacks on a colon */
1557 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1558 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1560 else if (itemBuffer[0] == '[')
1562 /* Current item is the parent directory */
1563 SetLastError(0xdeadbeef);
1564 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1565 ok (GetLastError() == 0xdeadbeef,
1566 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1567 i, GetLastError());
1568 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1570 /* For directories, DlgDirSelectEx tacks on a backslash */
1571 p = pathBuffer + strlen(pathBuffer);
1572 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1574 tempBuffer[0] = '[';
1575 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1576 strcat(tempBuffer, "]");
1577 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1579 else
1581 /* Current item is a plain file */
1582 SetLastError(0xdeadbeef);
1583 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1584 ok (GetLastError() == 0xdeadbeef,
1585 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1586 i, GetLastError());
1587 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1589 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1590 * This affects for example, "Makefile", which gets reported as "Makefile."
1592 strcpy(tempBuffer, itemBuffer);
1593 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1594 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1598 /* Test behavior when loading folders from root with and without wildcard */
1599 strcpy(pathBuffer, "C:\\");
1600 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1601 ok(res, "DlgDirList failed to list C:\\ folders\n");
1602 todo_wine ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1604 strcpy(pathBuffer, "C:\\*");
1605 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1606 ok(res, "DlgDirList failed to list C:\\* folders\n");
1607 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1609 /* Try loading files from an invalid folder */
1610 SetLastError(0xdeadbeef);
1611 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1612 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1613 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1614 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1615 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1617 DestroyWindow(hWnd);
1620 static void test_set_count( void )
1622 HWND parent, listbox;
1623 LONG ret;
1624 RECT r;
1626 parent = create_parent();
1627 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1629 UpdateWindow( listbox );
1630 GetUpdateRect( listbox, &r, TRUE );
1631 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1633 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1634 ok( ret == 0, "got %d\n", ret );
1635 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1636 ok( ret == 100, "got %d\n", ret );
1638 GetUpdateRect( listbox, &r, TRUE );
1639 ok( !IsRectEmpty( &r ), "got empty rect\n");
1641 ValidateRect( listbox, NULL );
1642 GetUpdateRect( listbox, &r, TRUE );
1643 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1645 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1646 ok( ret == 0, "got %d\n", ret );
1648 GetUpdateRect( listbox, &r, TRUE );
1649 ok( !IsRectEmpty( &r ), "got empty rect\n");
1651 DestroyWindow( listbox );
1652 DestroyWindow( parent );
1655 static int lb_getlistboxinfo;
1657 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1659 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1661 if (message == LB_GETLISTBOXINFO)
1662 lb_getlistboxinfo++;
1664 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1667 static void test_GetListBoxInfo(void)
1669 HWND listbox, parent;
1670 WNDPROC oldproc;
1671 DWORD ret;
1673 parent = create_parent();
1674 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1676 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1677 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1679 lb_getlistboxinfo = 0;
1680 ret = GetListBoxInfo(listbox);
1681 ok(ret > 0, "got %d\n", ret);
1682 ok(lb_getlistboxinfo == 1, "got %d\n", lb_getlistboxinfo);
1684 DestroyWindow(listbox);
1685 DestroyWindow(parent);
1688 static void test_missing_lbuttonup(void)
1690 HWND listbox, parent, capture;
1692 parent = create_parent();
1693 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1695 /* Send button down without a corresponding button up */
1696 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10));
1697 capture = GetCapture();
1698 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1700 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1701 got_selchange = 0;
1702 SetFocus(NULL);
1703 capture = GetCapture();
1704 ok(capture == NULL, "got %p\n", capture);
1705 ok(got_selchange, "got %d\n", got_selchange);
1707 DestroyWindow(listbox);
1708 DestroyWindow(parent);
1711 static void test_extents(void)
1713 HWND listbox, parent;
1714 SCROLLINFO sinfo;
1715 DWORD res;
1716 BOOL br;
1718 parent = create_parent();
1720 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1722 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1723 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1725 sinfo.cbSize = sizeof(sinfo);
1726 sinfo.fMask = SIF_RANGE;
1727 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1728 ok(br == TRUE, "GetScrollInfo failed\n");
1729 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1730 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1731 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1732 "List box should not have a horizontal scroll bar\n");
1734 /* horizontal extent < width */
1735 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1737 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1738 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1740 sinfo.cbSize = sizeof(sinfo);
1741 sinfo.fMask = SIF_RANGE;
1742 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1743 ok(br == TRUE, "GetScrollInfo failed\n");
1744 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1745 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1746 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1747 "List box should not have a horizontal scroll bar\n");
1749 /* horizontal extent > width */
1750 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1752 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1753 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1755 sinfo.cbSize = sizeof(sinfo);
1756 sinfo.fMask = SIF_RANGE;
1757 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1758 ok(br == TRUE, "GetScrollInfo failed\n");
1759 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1760 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1761 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1762 "List box should not have a horizontal scroll bar\n");
1764 DestroyWindow(listbox);
1766 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1768 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1769 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1771 sinfo.cbSize = sizeof(sinfo);
1772 sinfo.fMask = SIF_RANGE;
1773 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1774 ok(br == TRUE, "GetScrollInfo failed\n");
1775 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1776 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1777 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1778 "List box should not have a horizontal scroll bar\n");
1780 /* horizontal extent < width */
1781 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1783 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1784 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1786 sinfo.cbSize = sizeof(sinfo);
1787 sinfo.fMask = SIF_RANGE;
1788 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1789 ok(br == TRUE, "GetScrollInfo failed\n");
1790 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1791 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1792 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1793 "List box should not have a horizontal scroll bar\n");
1795 /* horizontal extent > width */
1796 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1798 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1799 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1801 sinfo.cbSize = sizeof(sinfo);
1802 sinfo.fMask = SIF_RANGE;
1803 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1804 ok(br == TRUE, "GetScrollInfo failed\n");
1805 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1806 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1807 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1808 "List box should have a horizontal scroll bar\n");
1810 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1812 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1813 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1815 sinfo.cbSize = sizeof(sinfo);
1816 sinfo.fMask = SIF_RANGE;
1817 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1818 ok(br == TRUE, "GetScrollInfo failed\n");
1819 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1820 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1821 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1822 "List box should not have a horizontal scroll bar\n");
1824 DestroyWindow(listbox);
1827 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
1829 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1830 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1832 sinfo.cbSize = sizeof(sinfo);
1833 sinfo.fMask = SIF_RANGE;
1834 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1835 ok(br == TRUE, "GetScrollInfo failed\n");
1836 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1837 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1838 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1839 "List box should have a horizontal scroll bar\n");
1841 /* horizontal extent < width */
1842 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1844 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1845 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1847 sinfo.cbSize = sizeof(sinfo);
1848 sinfo.fMask = SIF_RANGE;
1849 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1850 ok(br == TRUE, "GetScrollInfo failed\n");
1851 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1852 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1853 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1854 "List box should have a horizontal scroll bar\n");
1856 /* horizontal extent > width */
1857 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1859 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1860 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1862 sinfo.cbSize = sizeof(sinfo);
1863 sinfo.fMask = SIF_RANGE;
1864 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1865 ok(br == TRUE, "GetScrollInfo failed\n");
1866 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1867 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1868 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1869 "List box should have a horizontal scroll bar\n");
1871 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1873 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1874 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1876 sinfo.cbSize = sizeof(sinfo);
1877 sinfo.fMask = SIF_RANGE;
1878 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1879 ok(br == TRUE, "GetScrollInfo failed\n");
1880 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1881 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1882 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1883 "List box should have a horizontal scroll bar\n");
1885 DestroyWindow(listbox);
1887 DestroyWindow(parent);
1890 static void test_listbox(void)
1892 static const struct listbox_test SS =
1893 /* {add_style} */
1894 {{0},
1895 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1896 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1897 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1898 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1900 /* {selected, anchor, caret, selcount}{TODO fields} */
1901 static const struct listbox_test SS_NS =
1902 {{LBS_NOSEL},
1903 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1904 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1905 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1906 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1908 static const struct listbox_test MS =
1909 {{LBS_MULTIPLESEL},
1910 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1911 { 1, 1, 1, 1}, {0,0,0,0},
1912 { 2, 1, 2, 1}, {0,0,0,0},
1913 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1915 static const struct listbox_test MS_NS =
1916 {{LBS_MULTIPLESEL | LBS_NOSEL},
1917 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1918 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1919 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1920 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1922 static const struct listbox_test ES =
1923 {{LBS_EXTENDEDSEL},
1924 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1925 { 1, 1, 1, 1}, {0,0,0,0},
1926 { 2, 2, 2, 1}, {0,0,0,0},
1927 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1929 static const struct listbox_test ES_NS =
1930 {{LBS_EXTENDEDSEL | LBS_NOSEL},
1931 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1932 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1933 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1934 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1936 static const struct listbox_test EMS =
1937 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
1938 { 0, LB_ERR, 0, 0}, {0,0,0,0},
1939 { 1, 1, 1, 1}, {0,0,0,0},
1940 { 2, 2, 2, 1}, {0,0,0,0},
1941 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
1943 static const struct listbox_test EMS_NS =
1944 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
1945 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
1946 { 1, 1, 1, LB_ERR}, {0,0,0,0},
1947 { 2, 2, 2, LB_ERR}, {0,0,0,0},
1948 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
1950 run_test(SS);
1951 run_test(SS_NS);
1952 run_test(MS);
1953 run_test(MS_NS);
1954 run_test(ES);
1955 run_test(ES_NS);
1956 run_test(EMS);
1957 run_test(EMS_NS);
1960 static const struct message lb_addstring_ownerdraw_parent_seq[] =
1962 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
1963 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
1964 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
1965 { 0 }
1968 static const struct message lb_addstring_sort_parent_seq[] =
1970 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
1971 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
1972 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
1973 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
1974 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
1975 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
1976 { 0 }
1979 static const struct message empty_seq[] =
1981 { 0 }
1984 static void test_WM_MEASUREITEM(void)
1986 HWND parent, listbox;
1987 LRESULT data, ret;
1989 parent = create_parent();
1990 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
1992 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
1993 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
1994 DestroyWindow(parent);
1996 parent = create_parent();
1997 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
1999 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2000 ok(!data, "data = %08lx\n", data);
2002 /* LBS_HASSTRINGS */
2003 parent = create_parent();
2004 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2005 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
2006 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2008 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2010 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2011 ok(ret == 0, "expected 0, got %ld\n", ret);
2012 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2013 ok(ret == 1, "expected 1, got %ld\n", ret);
2014 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2015 ok(ret == 2, "expected 2, got %ld\n", ret);
2017 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
2018 "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
2019 DestroyWindow(listbox);
2021 /* LBS_SORT, no LBS_HASSTRINGS */
2022 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2023 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
2024 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2026 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2028 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2029 ok(ret == 0, "expected 0, got %ld\n", ret);
2030 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2031 ok(ret == 1, "expected 1, got %ld\n", ret);
2032 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2033 ok(ret == 2, "expected 2, got %ld\n", ret);
2035 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", TRUE);
2036 DestroyWindow(listbox);
2038 /* LBS_HASSTRINGS */
2039 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2040 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
2041 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2043 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2045 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2046 ok(ret == 0, "expected 0, got %ld\n", ret);
2047 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2048 ok(ret == 1, "expected 1, got %ld\n", ret);
2049 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2050 ok(ret == 2, "expected 2, got %ld\n", ret);
2052 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
2053 DestroyWindow(listbox);
2055 /* LBS_HASSTRINGS, LBS_SORT */
2056 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2057 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
2058 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2060 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2062 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2063 ok(ret == 0, "expected 0, got %ld\n", ret);
2064 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2065 ok(ret == 0, "expected 0, got %ld\n", ret);
2066 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2067 ok(ret == 1, "expected 1, got %ld\n", ret);
2069 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
2070 DestroyWindow(listbox);
2072 DestroyWindow(parent);
2075 START_TEST(listbox)
2077 ULONG_PTR ctx_cookie;
2078 HANDLE hCtx;
2080 if (!load_v6_module(&ctx_cookie, &hCtx))
2081 return;
2083 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2085 test_listbox();
2086 test_item_height();
2087 test_ownerdraw();
2088 test_LB_SELITEMRANGE();
2089 test_LB_SETCURSEL();
2090 test_listbox_height();
2091 test_itemfrompoint();
2092 test_listbox_item_data();
2093 test_listbox_LB_DIR();
2094 test_listbox_dlgdir();
2095 test_set_count();
2096 test_GetListBoxInfo();
2097 test_missing_lbuttonup();
2098 test_extents();
2099 test_WM_MEASUREITEM();
2101 unload_v6_module(ctx_cookie, hCtx);