comctl32/tests: Add more Listbox tests for ownerdraw styles.
[wine.git] / dlls / comctl32 / tests / listbox.c
blobc118047b4f7d4f810b8e47cf27942040a5196349
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);
437 /* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
438 hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE, 0, 0, 100, 100,
439 NULL, NULL, NULL, 0);
440 ok(hLB != NULL, "last error 0x%08x\n", GetLastError());
442 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
443 ok(ret == 0, "Unexpected return value %d.\n", ret);
444 ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
445 ok(ret == 1, "Unexpected return value %d.\n", ret);
447 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
448 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
450 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
451 ok(ret == 13, "Unexpected item height %d.\n", ret);
453 ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
454 ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
456 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
457 todo_wine
458 ok(ret == 42, "Unexpected item height %d.\n", ret);
460 ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
461 ok(ret == 42, "Unexpected item height %d.\n", ret);
463 DestroyWindow (hLB);
465 DestroyWindow(parent);
468 #define listbox_test_query(exp, got) \
469 ok(exp.selected == got.selected, "expected selected %d, got %d\n", exp.selected, got.selected); \
470 ok(exp.anchor == got.anchor, "expected anchor %d, got %d\n", exp.anchor, got.anchor); \
471 ok(exp.caret == got.caret, "expected caret %d, got %d\n", exp.caret, got.caret); \
472 ok(exp.selcount == got.selcount, "expected selcount %d, got %d\n", exp.selcount, got.selcount);
474 static void test_LB_SELITEMRANGE(void)
476 static const struct listbox_stat test_nosel = { 0, LB_ERR, 0, 0 };
477 static const struct listbox_stat test_1 = { 0, LB_ERR, 0, 2 };
478 static const struct listbox_stat test_2 = { 0, LB_ERR, 0, 3 };
479 static const struct listbox_stat test_3 = { 0, LB_ERR, 0, 4 };
480 struct listbox_stat answer;
481 HWND hLB;
482 INT ret;
484 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
485 ok(hLB != NULL, "Failed to create listbox window.\n");
487 listbox_query(hLB, &answer);
488 listbox_test_query(test_nosel, answer);
490 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
491 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
492 listbox_query(hLB, &answer);
493 listbox_test_query(test_1, answer);
495 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
496 listbox_query(hLB, &answer);
497 listbox_test_query(test_nosel, answer);
499 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(0, 4));
500 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
501 listbox_query(hLB, &answer);
502 listbox_test_query(test_3, answer);
504 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
505 listbox_query(hLB, &answer);
506 listbox_test_query(test_nosel, answer);
508 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(-5, 5));
509 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
510 listbox_query(hLB, &answer);
511 listbox_test_query(test_nosel, answer);
513 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
514 listbox_query(hLB, &answer);
515 listbox_test_query(test_nosel, answer);
517 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(2, 10));
518 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
519 listbox_query(hLB, &answer);
520 listbox_test_query(test_1, answer);
522 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
523 listbox_query(hLB, &answer);
524 listbox_test_query(test_nosel, answer);
526 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(4, 10));
527 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
528 listbox_query(hLB, &answer);
529 listbox_test_query(test_nosel, answer);
531 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
532 listbox_query(hLB, &answer);
533 listbox_test_query(test_nosel, answer);
535 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(10, 1));
536 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
537 listbox_query(hLB, &answer);
538 listbox_test_query(test_2, answer);
540 SendMessageA(hLB, LB_SETSEL, FALSE, -1);
541 listbox_query(hLB, &answer);
542 listbox_test_query(test_nosel, answer);
544 ret = SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, -1));
545 ok(ret == LB_OKAY, "LB_SELITEMRANGE returned %d instead of LB_OKAY\n", ret);
546 listbox_query(hLB, &answer);
547 listbox_test_query(test_2, answer);
549 DestroyWindow(hLB);
552 static void test_LB_SETCURSEL(void)
554 HWND parent, hLB;
555 INT ret;
557 parent = create_parent();
558 ok(parent != NULL, "Failed to create parent window.\n");
560 hLB = create_listbox(LBS_NOINTEGRALHEIGHT | WS_CHILD, parent);
561 ok(hLB != NULL, "Failed to create listbox.\n");
563 SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
565 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
566 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
568 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
569 ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
570 ret = GetScrollPos(hLB, SB_VERT);
571 ok(ret == 0, "expected vscroll 0, got %d\n", ret);
573 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
574 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
576 ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
577 ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
578 ret = GetScrollPos(hLB, SB_VERT);
579 ok(ret == 1, "expected vscroll 1, got %d\n", ret);
581 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
582 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
584 DestroyWindow(hLB);
586 hLB = create_listbox(0, 0);
587 ok(hLB != NULL, "Failed to create ListBox window.\n");
589 ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
590 ok(ret == 1, "Unexpected return value %d.\n", ret);
592 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
593 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
595 DestroyWindow(hLB);
597 /* LBS_EXTENDEDSEL */
598 hLB = create_listbox(LBS_EXTENDEDSEL, 0);
599 ok(hLB != NULL, "Failed to create listbox.\n");
601 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
602 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
604 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
605 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
607 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
608 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
610 DestroyWindow(hLB);
612 /* LBS_MULTIPLESEL */
613 hLB = create_listbox(LBS_MULTIPLESEL, 0);
614 ok(hLB != NULL, "Failed to create listbox.\n");
616 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
617 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
619 ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
620 ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
622 ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
623 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
625 DestroyWindow(hLB);
628 static void test_LB_SETSEL(void)
630 HWND list;
631 int ret;
633 /* LBS_EXTENDEDSEL */
634 list = create_listbox(LBS_EXTENDEDSEL, 0);
635 ok(list != NULL, "Failed to create ListBox window.\n");
637 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
638 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
640 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
641 ok(ret == 0, "Unexpected return value %d.\n", ret);
642 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
643 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
645 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
646 ok(ret == 0, "Unexpected return value %d.\n", ret);
647 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
648 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
650 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
651 ok(ret == 0, "Unexpected return value %d.\n", ret);
652 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
653 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
655 DestroyWindow(list);
657 /* LBS_MULTIPLESEL */
658 list = create_listbox(LBS_MULTIPLESEL, 0);
659 ok(list != NULL, "Failed to create ListBox window.\n");
661 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
662 ok(ret == -1, "Unexpected anchor index %d.\n", ret);
664 ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
665 ok(ret == 0, "Unexpected return value %d.\n", ret);
666 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
667 ok(ret == 0, "Unexpected anchor index %d.\n", ret);
669 ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
670 ok(ret == 0, "Unexpected return value %d.\n", ret);
671 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
672 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
674 ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
675 ok(ret == 0, "Unexpected return value %d.\n", ret);
676 ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
677 ok(ret == 1, "Unexpected anchor index %d.\n", ret);
679 DestroyWindow(list);
682 static void test_listbox_height(void)
684 HWND hList;
685 int r, id;
687 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
688 1, 1, 600, 100, NULL, NULL, NULL, NULL );
689 ok( hList != NULL, "failed to create listbox\n");
691 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
692 ok( id == 0, "item id wrong\n");
694 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 20, 0 ));
695 ok( r == 0, "send message failed\n");
697 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
698 ok( r == 20, "height wrong\n");
700 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0, 30 ));
701 ok( r == -1, "send message failed\n");
703 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
704 ok( r == 20, "height wrong\n");
706 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 256, 0 ));
707 ok( r == -1, "Failed to set item height, %d.\n", r);
709 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
710 ok( r == 20, "Unexpected item height %d.\n", r);
712 r = SendMessageA( hList, LB_SETITEMHEIGHT, 0, MAKELPARAM( 0xff, 0 ));
713 ok( r == 0, "send message failed\n");
715 r = SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0 );
716 ok( r == 0xff, "height wrong\n");
718 DestroyWindow( hList );
721 static void test_itemfrompoint(void)
723 /* WS_POPUP is required in order to have a more accurate size calculation (
724 without caption). LBS_NOINTEGRALHEIGHT is required in order to test
725 behavior of partially-displayed item.
727 HWND hList = CreateWindowA( WC_LISTBOXA, "list test",
728 WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
729 1, 1, 600, 100, NULL, NULL, NULL, NULL );
730 ULONG r, id;
731 RECT rc;
733 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
734 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
736 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
737 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
739 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
740 ok( r == MAKELPARAM(0xffff, 1), "Unexpected ret value %#x.\n", r );
742 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
743 ok( id == 0, "item id wrong\n");
744 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi1");
745 ok( id == 1, "item id wrong\n");
747 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
748 ok( r == 0x1, "ret %x\n", r );
750 r = SendMessageA(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
751 ok( r == MAKELPARAM(1, 1), "Unexpected ret value %#x.\n", r );
753 /* Resize control so that below assertions about sizes are valid */
754 r = SendMessageA( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
755 ok( r == 1, "ret %x\n", r);
756 r = MoveWindow(hList, 1, 1, 600, (rc.bottom - rc.top + 1) * 9 / 2, TRUE);
757 ok( r != 0, "ret %x\n", r);
759 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi2");
760 ok( id == 2, "item id wrong\n");
761 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi3");
762 ok( id == 3, "item id wrong\n");
763 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi4");
764 ok( id == 4, "item id wrong\n");
765 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi5");
766 ok( id == 5, "item id wrong\n");
767 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi6");
768 ok( id == 6, "item id wrong\n");
769 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi7");
770 ok( id == 7, "item id wrong\n");
772 /* Set the listbox up so that id 1 is at the top, this leaves 5
773 partially visible at the bottom and 6, 7 are invisible */
775 SendMessageA( hList, LB_SETTOPINDEX, 1, 0);
776 r = SendMessageA( hList, LB_GETTOPINDEX, 0, 0);
777 ok( r == 1, "top %d\n", r);
779 r = SendMessageA( hList, LB_GETITEMRECT, 5, (LPARAM)&rc);
780 ok( r == 1, "ret %x\n", r);
781 r = SendMessageA( hList, LB_GETITEMRECT, 6, (LPARAM)&rc);
782 ok( r == 0, "ret %x\n", r);
784 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(/* x */ 10, /* y */ 10) );
785 ok( r == 1, "ret %x\n", r);
787 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
788 ok( r == 0x10001, "ret %x\n", r );
790 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
791 ok( r == 0x10001, "ret %x\n", r );
793 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
794 ok( r == 0x10005, "item %x\n", r );
796 r = SendMessageA( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
797 ok( r == 0x10005, "item %x\n", r );
799 DestroyWindow( hList );
802 static void test_listbox_item_data(void)
804 HWND hList;
805 int r, id;
807 hList = CreateWindowA( WC_LISTBOXA, "list test", 0,
808 1, 1, 600, 100, NULL, NULL, NULL, NULL );
809 ok( hList != NULL, "failed to create listbox\n");
811 id = SendMessageA( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
812 ok( id == 0, "item id wrong\n");
814 r = SendMessageA( hList, LB_SETITEMDATA, 0, MAKELPARAM( 20, 0 ));
815 ok(r == TRUE, "LB_SETITEMDATA returned %d instead of TRUE\n", r);
817 r = SendMessageA( hList, LB_GETITEMDATA, 0, 0);
818 ok( r == 20, "get item data failed\n");
820 DestroyWindow( hList );
823 static void test_listbox_LB_DIR(void)
825 char path[MAX_PATH], curdir[MAX_PATH];
826 HWND hList;
827 int res, itemCount;
828 int itemCount_justFiles;
829 int itemCount_justDrives;
830 int itemCount_allFiles;
831 int itemCount_allDirs;
832 int i;
833 char pathBuffer[MAX_PATH];
834 char * p;
835 char driveletter;
836 const char *wildcard = "*";
837 HANDLE file;
838 BOOL ret;
840 GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
842 GetTempPathA(ARRAY_SIZE(path), path);
843 ret = SetCurrentDirectoryA(path);
844 ok(ret, "Failed to set current directory.\n");
846 ret = CreateDirectoryA("lb_dir_test", NULL);
847 ok(ret, "Failed to create test directory.\n");
849 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
850 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
851 CloseHandle( file );
853 /* NOTE: for this test to succeed, there must be no subdirectories
854 under the current directory. In addition, there must be at least
855 one file that fits the wildcard w*.c . Normally, the test
856 directory itself satisfies both conditions.
858 hList = CreateWindowA( WC_LISTBOXA, "list test", WS_VISIBLE|WS_POPUP,
859 1, 1, 600, 100, NULL, NULL, NULL, NULL );
860 ok(hList != NULL, "Failed to create listbox window.\n");
862 /* Test for standard usage */
864 /* This should list all the files in the test directory. */
865 strcpy(pathBuffer, wildcard);
866 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
867 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
868 if (res == -1) /* "*" wildcard doesn't work on win9x */
870 wildcard = "*.*";
871 strcpy(pathBuffer, wildcard);
872 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
874 ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
876 /* There should be some content in the listbox */
877 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
878 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
879 itemCount_allFiles = itemCount;
880 ok(res + 1 == itemCount,
881 "SendMessage(LB_DIR, 0, *) returned incorrect index (expected %d got %d)!\n",
882 itemCount - 1, res);
884 /* This tests behavior when no files match the wildcard */
885 strcpy(pathBuffer, BAD_EXTENSION);
886 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
887 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
888 ok (res == -1, "SendMessage(LB_DIR, 0, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
890 /* There should be NO content in the listbox */
891 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
892 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
895 /* This should list all the w*.c files in the test directory
896 * As of this writing, this includes win.c, winstation.c, wsprintf.c
898 strcpy(pathBuffer, "w*.c");
899 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
900 res = SendMessageA(hList, LB_DIR, 0, (LPARAM)pathBuffer);
901 ok (res >= 0, "SendMessage(LB_DIR, 0, w*.c) failed - 0x%08x\n", GetLastError());
903 /* Path specification does NOT converted to uppercase */
904 ok (!strcmp(pathBuffer, "w*.c"),
905 "expected no change to pathBuffer, got %s\n", pathBuffer);
907 /* There should be some content in the listbox */
908 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
909 ok (itemCount > 0, "SendMessage(LB_DIR) did NOT fill the listbox!\n");
910 itemCount_justFiles = itemCount;
911 ok(res + 1 == itemCount,
912 "SendMessage(LB_DIR, 0, w*.c) returned incorrect index (expected %d got %d)!\n",
913 itemCount - 1, res);
915 /* Every single item in the control should start with a w and end in .c */
916 for (i = 0; i < itemCount; i++)
918 memset(pathBuffer, 0, MAX_PATH);
919 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
920 p = pathBuffer + strlen(pathBuffer);
921 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
922 (*(p-1) == 'c' || *(p-1) == 'C') &&
923 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
926 /* Test DDL_DIRECTORY */
927 strcpy(pathBuffer, wildcard);
928 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
929 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
930 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
932 /* There should be some content in the listbox.
933 * All files plus "[..]"
935 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
936 itemCount_allDirs = itemCount - itemCount_allFiles;
937 ok (itemCount >= itemCount_allFiles,
938 "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
939 itemCount, itemCount_allFiles);
940 ok(res + 1 == itemCount,
941 "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
942 itemCount - 1, res);
944 /* This tests behavior when no files match the wildcard */
945 strcpy(pathBuffer, BAD_EXTENSION);
946 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
947 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
948 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY, %s) returned %d, expected -1\n", BAD_EXTENSION, res);
950 /* There should be NO content in the listbox */
951 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
952 ok (itemCount == 0, "SendMessage(LB_DIR) DID fill the listbox!\n");
954 /* Test DDL_DIRECTORY */
955 strcpy(pathBuffer, "w*.c");
956 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
957 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
958 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) failed - 0x%08x\n", GetLastError());
960 /* There should be some content in the listbox. Since the parent directory does not
961 * fit w*.c, there should be exactly the same number of items as without DDL_DIRECTORY
963 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
964 ok (itemCount == itemCount_justFiles,
965 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) filled with %d entries, expected %d\n",
966 itemCount, itemCount_justFiles);
967 ok(res + 1 == itemCount,
968 "SendMessage(LB_DIR, DDL_DIRECTORY, w*.c) returned incorrect index (expected %d got %d)!\n",
969 itemCount - 1, res);
971 /* Every single item in the control should start with a w and end in .c. */
972 for (i = 0; i < itemCount; i++)
974 memset(pathBuffer, 0, MAX_PATH);
975 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
976 p = pathBuffer + strlen(pathBuffer);
978 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
979 (*(p-1) == 'c' || *(p-1) == 'C') &&
980 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
983 /* Test DDL_DRIVES|DDL_EXCLUSIVE */
984 strcpy(pathBuffer, wildcard);
985 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
986 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
987 ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
989 /* There should be some content in the listbox. In particular, there should
990 * be at least one element before, since the string "[-c-]" should
991 * have been added. Depending on the user setting, more drives might have
992 * been added.
994 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
995 ok (itemCount >= 1,
996 "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) filled with %d entries, expected at least %d\n",
997 itemCount, 1);
998 itemCount_justDrives = itemCount;
999 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1001 /* Every single item in the control should fit the format [-c-] */
1002 for (i = 0; i < itemCount; i++)
1004 memset(pathBuffer, 0, MAX_PATH);
1005 driveletter = '\0';
1006 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1007 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1008 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1009 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1010 if (!(driveletter >= 'a' && driveletter <= 'z'))
1012 /* Correct after invalid entry is found */
1013 itemCount_justDrives--;
1017 /* This tests behavior when no files match the wildcard */
1018 strcpy(pathBuffer, BAD_EXTENSION);
1019 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1020 res = SendMessageA(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1021 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1022 BAD_EXTENSION, res, itemCount_justDrives -1);
1024 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1025 ok (itemCount == itemCount_justDrives, "SendMessage(LB_DIR) returned %d expected %d\n",
1026 itemCount, itemCount_justDrives);
1028 /* Test DDL_DRIVES. */
1029 strcpy(pathBuffer, wildcard);
1030 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1031 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1032 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1034 /* There should be some content in the listbox. In particular, there should
1035 * be at least one element before, since the string "[-c-]" should
1036 * have been added. Depending on the user setting, more drives might have
1037 * been added.
1039 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1040 ok (itemCount == itemCount_justDrives + itemCount_allFiles,
1041 "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
1042 itemCount, itemCount_justDrives + itemCount_allFiles);
1043 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
1045 /* This tests behavior when no files match the wildcard */
1046 strcpy(pathBuffer, BAD_EXTENSION);
1047 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1048 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1049 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DRIVES, %s) returned %d, expected %d\n",
1050 BAD_EXTENSION, res, itemCount_justDrives -1);
1052 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1053 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1055 /* Test DDL_DRIVES. */
1056 strcpy(pathBuffer, "w*.c");
1057 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1058 res = SendMessageA(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer);
1059 ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1061 /* There should be some content in the listbox. In particular, there should
1062 * be at least one element before, since the string "[-c-]" should
1063 * have been added. Depending on the user setting, more drives might have
1064 * been added.
1066 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1067 ok (itemCount == itemCount_justDrives + itemCount_justFiles,
1068 "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
1069 itemCount, itemCount_justDrives + itemCount_justFiles);
1070 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
1072 /* Every single item in the control should fit the format [-c-], or w*.c */
1073 for (i = 0; i < itemCount; i++)
1075 memset(pathBuffer, 0, MAX_PATH);
1076 driveletter = '\0';
1077 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1078 p = pathBuffer + strlen(pathBuffer);
1079 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1081 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1082 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1084 else
1087 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1088 (*(p-1) == 'c' || *(p-1) == 'C') &&
1089 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1093 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1094 strcpy(pathBuffer, wildcard);
1095 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1096 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1097 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError());
1099 /* There should be some content in the listbox. In particular, there should
1100 * be exactly the number of plain files, plus the number of mapped drives.
1102 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1103 ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs,
1104 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1105 itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
1106 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1108 /* Every single item in the control should start with a w and end in .c,
1109 * except for the "[..]" string, which should appear exactly as it is,
1110 * and the mapped drives in the format "[-X-]".
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 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1118 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1121 /* This tests behavior when no files match the wildcard */
1122 strcpy(pathBuffer, BAD_EXTENSION);
1123 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1124 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1125 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, %s) returned %d, expected %d\n",
1126 BAD_EXTENSION, res, itemCount_justDrives -1);
1128 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1129 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1131 /* Test DDL_DIRECTORY|DDL_DRIVES. */
1132 strcpy(pathBuffer, "w*.c");
1133 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1134 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer);
1135 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) failed - 0x%08x\n", GetLastError());
1137 /* There should be some content in the listbox. In particular, there should
1138 * be exactly the number of plain files, plus the number of mapped drives.
1140 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1141 ok (itemCount == itemCount_justFiles + itemCount_justDrives,
1142 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1143 itemCount, itemCount_justFiles + itemCount_justDrives);
1144 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
1146 /* Every single item in the control should start with a w and end in .c,
1147 * except the mapped drives in the format "[-X-]". The "[..]" directory
1148 * should not appear.
1150 for (i = 0; i < itemCount; i++)
1152 memset(pathBuffer, 0, MAX_PATH);
1153 driveletter = '\0';
1154 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1155 p = pathBuffer + strlen(pathBuffer);
1156 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1157 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1158 else
1160 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1161 (*(p-1) == 'c' || *(p-1) == 'C') &&
1162 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1165 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1166 strcpy(pathBuffer, wildcard);
1167 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1168 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1169 ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n",
1170 GetLastError());
1172 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1173 ok (itemCount == itemCount_allDirs,
1174 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1175 itemCount, itemCount_allDirs);
1176 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
1178 if (itemCount)
1180 memset(pathBuffer, 0, MAX_PATH);
1181 SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1182 ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
1185 /* This tests behavior when no files match the wildcard */
1186 strcpy(pathBuffer, BAD_EXTENSION);
1187 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1188 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1189 ok (res == -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1190 BAD_EXTENSION, res, -1);
1192 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1193 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1196 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1197 strcpy(pathBuffer, "w*.c");
1198 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1199 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1200 ok (res == LB_ERR, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, w*.c) returned %d expected %d\n", res, LB_ERR);
1202 /* There should be no elements, since "[..]" does not fit w*.c */
1203 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1204 ok (itemCount == 0,
1205 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1206 itemCount, 0);
1208 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1209 strcpy(pathBuffer, wildcard);
1210 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1211 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1212 ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1214 /* There should be no plain files on the listbox */
1215 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1216 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1217 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1218 itemCount, itemCount_justDrives + itemCount_allDirs);
1219 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1221 for (i = 0; i < itemCount; i++)
1223 memset(pathBuffer, 0, MAX_PATH);
1224 driveletter = '\0';
1225 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1226 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1227 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1228 else
1229 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1230 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1233 /* This tests behavior when no files match the wildcard */
1234 strcpy(pathBuffer, BAD_EXTENSION);
1235 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1236 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1237 ok (res == itemCount_justDrives -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, %s) returned %d, expected %d\n",
1238 BAD_EXTENSION, res, itemCount_justDrives -1);
1240 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1241 ok (itemCount == res + 1, "SendMessage(LB_DIR) returned %d expected %d\n", itemCount, res + 1);
1243 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1244 strcpy(pathBuffer, "w*.c");
1245 SendMessageA(hList, LB_RESETCONTENT, 0, 0);
1246 res = SendMessageA(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
1247 ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
1249 /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
1250 itemCount = SendMessageA(hList, LB_GETCOUNT, 0, 0);
1251 ok (itemCount == itemCount_justDrives,
1252 "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1253 itemCount, itemCount_justDrives);
1254 ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
1256 for (i = 0; i < itemCount; i++)
1258 memset(pathBuffer, 0, MAX_PATH);
1259 driveletter = '\0';
1260 SendMessageA(hList, LB_GETTEXT, i, (LPARAM)pathBuffer);
1261 ok (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1262 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1264 DestroyWindow(hList);
1266 DeleteFileA( "wtest1.tmp.c" );
1267 RemoveDirectoryA("lb_dir_test");
1269 SetCurrentDirectoryA(curdir);
1272 static HWND g_listBox;
1273 static HWND g_label;
1275 #define ID_TEST_LABEL 1001
1276 #define ID_TEST_LISTBOX 1002
1278 static BOOL on_listbox_container_create(HWND hwnd, CREATESTRUCTA *lpcs)
1280 g_label = CreateWindowA(WC_STATICA, "Contents of static control before DlgDirList.",
1281 WS_CHILD | WS_VISIBLE, 10, 10, 512, 32, hwnd, (HMENU)ID_TEST_LABEL, NULL, 0);
1282 if (!g_label) return FALSE;
1284 g_listBox = CreateWindowA(WC_LISTBOXA, "DlgDirList test",
1285 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL, 10, 60, 256, 256,
1286 hwnd, (HMENU)ID_TEST_LISTBOX, NULL, 0);
1287 if (!g_listBox) return FALSE;
1289 return TRUE;
1292 static LRESULT CALLBACK listbox_container_window_procA(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1294 LRESULT result = 0;
1296 switch (uiMsg)
1298 case WM_DESTROY:
1299 PostQuitMessage(0);
1300 break;
1301 case WM_CREATE:
1302 result = on_listbox_container_create(hwnd, (CREATESTRUCTA *)lParam) ? 0 : (LRESULT)-1;
1303 break;
1304 default:
1305 result = DefWindowProcA(hwnd, uiMsg, wParam, lParam);
1306 break;
1308 return result;
1311 static BOOL RegisterListboxWindowClass(HINSTANCE hInst)
1313 WNDCLASSA cls;
1315 cls.style = 0;
1316 cls.cbClsExtra = 0;
1317 cls.cbWndExtra = 0;
1318 cls.hInstance = hInst;
1319 cls.hIcon = NULL;
1320 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
1321 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1322 cls.lpszMenuName = NULL;
1323 cls.lpfnWndProc = listbox_container_window_procA;
1324 cls.lpszClassName = "ListboxContainerClass";
1325 if (!RegisterClassA (&cls)) return FALSE;
1327 return TRUE;
1330 static void test_listbox_dlgdir(void)
1332 HINSTANCE hInst;
1333 HWND hWnd;
1334 int res, itemCount;
1335 int itemCount_allDirs;
1336 int itemCount_justFiles;
1337 int itemCount_justDrives;
1338 int i;
1339 char pathBuffer[MAX_PATH];
1340 char itemBuffer[MAX_PATH];
1341 char tempBuffer[MAX_PATH];
1342 char * p;
1343 char driveletter;
1344 HANDLE file;
1345 BOOL ret;
1347 file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
1348 ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
1349 CloseHandle( file );
1351 /* NOTE: for this test to succeed, there must be no subdirectories
1352 under the current directory. In addition, there must be at least
1353 one file that fits the wildcard w*.c . Normally, the test
1354 directory itself satisfies both conditions.
1357 hInst = GetModuleHandleA(0);
1358 ret = RegisterListboxWindowClass(hInst);
1359 ok(ret, "Failed to register test class.\n");
1361 hWnd = CreateWindowA("ListboxContainerClass", "ListboxContainerClass",
1362 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1363 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1364 NULL, NULL, hInst, 0);
1365 ok(hWnd != NULL, "Failed to create container window.\n");
1367 /* Test for standard usage */
1369 /* The following should be overwritten by the directory path */
1370 SendMessageA(g_label, WM_SETTEXT, 0, (LPARAM)"default contents");
1372 /* This should list all the w*.c files in the test directory
1373 * As of this writing, this includes win.c, winstation.c, wsprintf.c
1375 strcpy(pathBuffer, "w*.c");
1376 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1377 ok (res == 1, "DlgDirList(*.c, 0) returned %d - expected 1 - 0x%08x\n", res, GetLastError());
1379 /* Path specification gets converted to uppercase */
1380 ok (!strcmp(pathBuffer, "W*.C"),
1381 "expected conversion to uppercase, got %s\n", pathBuffer);
1383 /* Loaded path should have overwritten the label text */
1384 SendMessageA(g_label, WM_GETTEXT, MAX_PATH, (LPARAM)pathBuffer);
1385 ok (strcmp("default contents", pathBuffer), "DlgDirList() did not modify static control!\n");
1387 /* There should be some content in the listbox */
1388 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1389 ok (itemCount > 0, "DlgDirList() did NOT fill the listbox!\n");
1390 itemCount_justFiles = itemCount;
1392 /* Every single item in the control should start with a w and end in .c */
1393 for (i = 0; i < itemCount; i++)
1395 memset(pathBuffer, 0, MAX_PATH);
1396 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1397 p = pathBuffer + strlen(pathBuffer);
1398 ok(((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1399 (*(p-1) == 'c' || *(p-1) == 'C') &&
1400 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1403 /* Test behavior when no files match the wildcard */
1404 strcpy(pathBuffer, BAD_EXTENSION);
1405 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, 0);
1406 ok (res == 1, "DlgDirList(%s, 0) returned %d expected 1\n", BAD_EXTENSION, res);
1408 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1409 ok (itemCount == 0, "DlgDirList() DID fill the listbox!\n");
1411 /* Test DDL_DIRECTORY */
1412 strcpy(pathBuffer, "w*.c");
1413 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1414 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
1416 /* There should be some content in the listbox. In particular, there should
1417 * be exactly more elements than before, since the directories should
1418 * have been added.
1420 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1421 itemCount_allDirs = itemCount - itemCount_justFiles;
1422 ok (itemCount >= itemCount_justFiles, "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
1423 itemCount, itemCount_justFiles);
1425 /* Every single item in the control should start with a w and end in .c,
1426 * except for the "[..]" string, which should appear exactly as it is.
1428 for (i = 0; i < itemCount; i++)
1430 memset(pathBuffer, 0, MAX_PATH);
1431 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1432 p = pathBuffer + strlen(pathBuffer);
1433 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1434 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1435 (*(p-1) == 'c' || *(p-1) == 'C') &&
1436 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1439 /* Test behavior when no files match the wildcard */
1440 strcpy(pathBuffer, BAD_EXTENSION);
1441 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY);
1442 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
1444 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1445 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1446 itemCount_allDirs, itemCount);
1447 for (i = 0; i < itemCount; i++)
1449 memset(pathBuffer, 0, MAX_PATH);
1450 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1451 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1452 "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
1455 /* Test DDL_DRIVES. At least on WinXP-SP2, this implies DDL_EXCLUSIVE */
1456 strcpy(pathBuffer, "w*.c");
1457 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1458 ok (res == 1, "DlgDirList(*.c, DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1460 /* There should be some content in the listbox. In particular, there should
1461 * be at least one element before, since the string "[-c-]" should
1462 * have been added. Depending on the user setting, more drives might have
1463 * been added.
1465 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1466 ok (itemCount >= 1,
1467 "DlgDirList(DDL_DRIVES) filled with %d entries, expected at least %d\n",
1468 itemCount, 1);
1469 itemCount_justDrives = itemCount;
1471 /* Every single item in the control should fit the format [-c-] */
1472 for (i = 0; i < itemCount; i++)
1474 memset(pathBuffer, 0, MAX_PATH);
1475 driveletter = '\0';
1476 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1477 ok( strlen(pathBuffer) == 5, "Length of drive string is not 5\n" );
1478 ok( sscanf(pathBuffer, "[-%c-]", &driveletter) == 1, "Element %d (%s) does not fit [-X-]\n", i, pathBuffer);
1479 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1480 if (!(driveletter >= 'a' && driveletter <= 'z')) {
1481 /* Correct after invalid entry is found */
1482 trace("removing count of invalid entry %s\n", pathBuffer);
1483 itemCount_justDrives--;
1487 /* Test behavior when no files match the wildcard */
1488 strcpy(pathBuffer, BAD_EXTENSION);
1489 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DRIVES);
1490 ok (res == 1, "DlgDirList(%s, DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1492 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1493 ok (itemCount == itemCount_justDrives, "DlgDirList() incorrectly filled the listbox!\n");
1495 /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */
1496 strcpy(pathBuffer, "w*.c");
1497 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1498 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1500 /* There should be some content in the listbox. In particular, there should
1501 * be exactly the number of plain files, plus the number of mapped drives,
1502 * plus one "[..]"
1504 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1505 ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
1506 "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
1507 itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
1509 /* Every single item in the control should start with a w and end in .c,
1510 * except for the "[..]" string, which should appear exactly as it is,
1511 * and the mapped drives in the format "[-X-]".
1513 for (i = 0; i < itemCount; i++)
1515 memset(pathBuffer, 0, MAX_PATH);
1516 driveletter = '\0';
1517 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1518 p = pathBuffer + strlen(pathBuffer);
1519 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1520 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1521 else
1522 ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
1523 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
1524 (*(p-1) == 'c' || *(p-1) == 'C') &&
1525 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
1528 /* Test behavior when no files match the wildcard */
1529 strcpy(pathBuffer, BAD_EXTENSION);
1530 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1531 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
1533 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1534 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1535 "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
1536 itemCount_justDrives + itemCount_allDirs, itemCount);
1538 /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */
1539 strcpy(pathBuffer, "w*.c");
1540 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1541 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1543 /* There should be exactly one element: "[..]" */
1544 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1545 ok (itemCount == itemCount_allDirs,
1546 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1547 itemCount, itemCount_allDirs);
1549 if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
1551 memset(pathBuffer, 0, MAX_PATH);
1552 SendMessageA(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
1553 ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
1556 /* Test behavior when no files match the wildcard */
1557 strcpy(pathBuffer, BAD_EXTENSION);
1558 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_EXCLUSIVE);
1559 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1561 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1562 ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1564 /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
1565 strcpy(pathBuffer, "w*.c");
1566 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1567 ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) failed - 0x%08x\n", GetLastError());
1569 /* There should be no plain files on the listbox */
1570 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1571 ok (itemCount == itemCount_justDrives + itemCount_allDirs,
1572 "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
1573 itemCount, itemCount_justDrives + itemCount_allDirs);
1575 for (i = 0; i < itemCount; i++)
1577 memset(pathBuffer, 0, MAX_PATH);
1578 driveletter = '\0';
1579 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
1580 if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1)
1581 ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
1582 else
1583 ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
1584 "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
1587 /* Test behavior when no files match the wildcard */
1588 strcpy(pathBuffer, BAD_EXTENSION);
1589 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE);
1590 ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
1592 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1593 ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
1595 /* Now test DlgDirSelectEx() in normal operation */
1596 /* Fill with everything - drives, directory and all plain files. */
1597 strcpy(pathBuffer, "*");
1598 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, ID_TEST_LABEL, DDL_DIRECTORY|DDL_DRIVES);
1599 ok (res != 0, "DlgDirList(*, DDL_DIRECTORY|DDL_DRIVES) failed - 0x%08x\n", GetLastError());
1601 SendMessageA(g_listBox, LB_SETCURSEL, -1, 0); /* Unselect any current selection */
1602 memset(pathBuffer, 0, MAX_PATH);
1603 SetLastError(0xdeadbeef);
1604 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1605 ok (GetLastError() == 0xdeadbeef,
1606 "DlgDirSelectEx() with no selection modified last error code from 0xdeadbeef to 0x%08x\n",
1607 GetLastError());
1608 ok (res == 0, "DlgDirSelectEx() with no selection returned %d, expected 0\n", res);
1609 /* WinXP-SP2 leaves pathBuffer untouched, but Win98 fills it with garbage. */
1611 ok (strlen(pathBuffer) == 0, "DlgDirSelectEx() with no selection filled buffer with %s\n", pathBuffer);
1613 /* Test proper drive/dir/file recognition */
1614 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1615 for (i = 0; i < itemCount; i++)
1617 memset(itemBuffer, 0, MAX_PATH);
1618 memset(pathBuffer, 0, MAX_PATH);
1619 memset(tempBuffer, 0, MAX_PATH);
1620 driveletter = '\0';
1621 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1622 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1623 ok (res == i, "SendMessageA(LB_SETCURSEL, %d) failed\n", i);
1624 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1626 /* Current item is a drive letter */
1627 SetLastError(0xdeadbeef);
1628 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1629 ok (GetLastError() == 0xdeadbeef,
1630 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1631 i, GetLastError());
1632 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1634 /* For drive letters, DlgDirSelectEx tacks on a colon */
1635 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1636 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1638 else if (itemBuffer[0] == '[')
1640 /* Current item is the parent directory */
1641 SetLastError(0xdeadbeef);
1642 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1643 ok (GetLastError() == 0xdeadbeef,
1644 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1645 i, GetLastError());
1646 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1648 /* For directories, DlgDirSelectEx tacks on a backslash */
1649 p = pathBuffer + strlen(pathBuffer);
1650 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1652 tempBuffer[0] = '[';
1653 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1654 strcat(tempBuffer, "]");
1655 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1657 else
1659 /* Current item is a plain file */
1660 SetLastError(0xdeadbeef);
1661 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1662 ok (GetLastError() == 0xdeadbeef,
1663 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1664 i, GetLastError());
1665 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1667 /* NOTE: WinXP tacks a period on all files that lack an extension. This affects
1668 * for example, "Makefile", which gets reported as "Makefile."
1670 strcpy(tempBuffer, itemBuffer);
1671 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1672 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1676 DeleteFileA( "wtest1.tmp.c" );
1678 /* Now test DlgDirSelectEx() in abnormal operation */
1679 /* Fill list with bogus entries, that look somewhat valid */
1680 SendMessageA(g_listBox, LB_RESETCONTENT, 0, 0);
1681 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"[notexist.dir]");
1682 SendMessageA(g_listBox, LB_ADDSTRING, 0, (LPARAM)"notexist.fil");
1683 itemCount = SendMessageA(g_listBox, LB_GETCOUNT, 0, 0);
1684 for (i = 0; i < itemCount; i++)
1686 memset(itemBuffer, 0, MAX_PATH);
1687 memset(pathBuffer, 0, MAX_PATH);
1688 memset(tempBuffer, 0, MAX_PATH);
1689 driveletter = '\0';
1690 SendMessageA(g_listBox, LB_GETTEXT, i, (LPARAM)itemBuffer);
1691 res = SendMessageA(g_listBox, LB_SETCURSEL, i, 0);
1692 ok (res == i, "SendMessage(LB_SETCURSEL, %d) failed\n", i);
1693 if (sscanf(itemBuffer, "[-%c-]", &driveletter) == 1)
1695 /* Current item is a drive letter */
1696 SetLastError(0xdeadbeef);
1697 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1698 ok (GetLastError() == 0xdeadbeef,
1699 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1700 i, GetLastError());
1701 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1703 /* For drive letters, DlgDirSelectEx tacks on a colon */
1704 ok (pathBuffer[0] == driveletter && pathBuffer[1] == ':' && pathBuffer[2] == '\0',
1705 "%d: got \"%s\" expected \"%c:\"\n", i, pathBuffer, driveletter);
1707 else if (itemBuffer[0] == '[')
1709 /* Current item is the parent directory */
1710 SetLastError(0xdeadbeef);
1711 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1712 ok (GetLastError() == 0xdeadbeef,
1713 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1714 i, GetLastError());
1715 ok(res == 1, "DlgDirSelectEx() thinks %s (%s) is not a drive/directory!\n", itemBuffer, pathBuffer);
1717 /* For directories, DlgDirSelectEx tacks on a backslash */
1718 p = pathBuffer + strlen(pathBuffer);
1719 ok (*(p-1) == '\\', "DlgDirSelectEx did NOT tack on a backslash to dir, got %s\n", pathBuffer);
1721 tempBuffer[0] = '[';
1722 lstrcpynA(tempBuffer + 1, pathBuffer, strlen(pathBuffer));
1723 strcat(tempBuffer, "]");
1724 ok (!strcmp(tempBuffer, itemBuffer), "Formatted directory should be %s, got %s\n", tempBuffer, itemBuffer);
1726 else
1728 /* Current item is a plain file */
1729 SetLastError(0xdeadbeef);
1730 res = DlgDirSelectExA(hWnd, pathBuffer, MAX_PATH, ID_TEST_LISTBOX);
1731 ok (GetLastError() == 0xdeadbeef,
1732 "DlgDirSelectEx() with selection at %d modified last error code from 0xdeadbeef to 0x%08x\n",
1733 i, GetLastError());
1734 ok(res == 0, "DlgDirSelectEx() thinks %s (%s) is a drive/directory!\n", itemBuffer, pathBuffer);
1736 /* NOTE: WinXP and Win98 tack a period on all files that lack an extension.
1737 * This affects for example, "Makefile", which gets reported as "Makefile."
1739 strcpy(tempBuffer, itemBuffer);
1740 if (strchr(tempBuffer, '.') == NULL) strcat(tempBuffer, ".");
1741 ok (!strcmp(pathBuffer, tempBuffer), "Formatted file should be %s, got %s\n", tempBuffer, pathBuffer);
1745 /* Test behavior when loading folders from root with and without wildcard */
1746 strcpy(pathBuffer, "C:\\");
1747 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1748 ok(res, "DlgDirList failed to list C:\\ folders\n");
1749 todo_wine ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1751 strcpy(pathBuffer, "C:\\*");
1752 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1753 ok(res, "DlgDirList failed to list C:\\* folders\n");
1754 ok(!strcmp(pathBuffer, "*"), "DlgDirList set the invalid path spec '%s', expected '*'\n", pathBuffer);
1756 /* Try loading files from an invalid folder */
1757 SetLastError(0xdeadbeef);
1758 strcpy(pathBuffer, "C:\\INVALID$$DIR");
1759 res = DlgDirListA(hWnd, pathBuffer, ID_TEST_LISTBOX, 0, DDL_DIRECTORY | DDL_EXCLUSIVE);
1760 todo_wine ok(!res, "DlgDirList should have failed with 0 but %d was returned\n", res);
1761 todo_wine ok(GetLastError() == ERROR_NO_WILDCARD_CHARACTERS,
1762 "GetLastError should return 0x589, got 0x%X\n",GetLastError());
1764 DestroyWindow(hWnd);
1767 static void test_set_count( void )
1769 static const DWORD styles[] =
1771 LBS_OWNERDRAWFIXED,
1772 LBS_HASSTRINGS,
1774 HWND parent, listbox;
1775 unsigned int i;
1776 LONG ret;
1777 RECT r;
1779 parent = create_parent();
1780 listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent );
1782 UpdateWindow( listbox );
1783 GetUpdateRect( listbox, &r, TRUE );
1784 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1786 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1787 ok( ret == 0, "got %d\n", ret );
1788 ret = SendMessageA( listbox, LB_GETCOUNT, 0, 0 );
1789 ok( ret == 100, "got %d\n", ret );
1791 GetUpdateRect( listbox, &r, TRUE );
1792 ok( !IsRectEmpty( &r ), "got empty rect\n");
1794 ValidateRect( listbox, NULL );
1795 GetUpdateRect( listbox, &r, TRUE );
1796 ok( IsRectEmpty( &r ), "got non-empty rect\n");
1798 ret = SendMessageA( listbox, LB_SETCOUNT, 99, 0 );
1799 ok( ret == 0, "got %d\n", ret );
1801 GetUpdateRect( listbox, &r, TRUE );
1802 ok( !IsRectEmpty( &r ), "got empty rect\n");
1804 DestroyWindow( listbox );
1806 for (i = 0; i < ARRAY_SIZE(styles); ++i)
1808 listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
1810 SetLastError( 0xdeadbeef );
1811 ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
1812 todo_wine_if(i == 0)
1813 ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
1814 todo_wine_if(i == 1)
1815 ok( GetLastError() == 0xdeadbeef, "Unexpected error %d.\n", GetLastError() );
1817 DestroyWindow( listbox );
1820 DestroyWindow( parent );
1823 static int lb_getlistboxinfo;
1825 static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1827 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1829 if (message == LB_GETLISTBOXINFO)
1830 lb_getlistboxinfo++;
1832 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
1835 static void test_GetListBoxInfo(void)
1837 HWND listbox, parent;
1838 WNDPROC oldproc;
1839 DWORD ret;
1841 parent = create_parent();
1842 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1844 oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
1845 SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
1847 lb_getlistboxinfo = 0;
1848 ret = GetListBoxInfo(listbox);
1849 ok(ret > 0, "got %d\n", ret);
1850 ok(lb_getlistboxinfo == 1, "got %d\n", lb_getlistboxinfo);
1852 DestroyWindow(listbox);
1853 DestroyWindow(parent);
1856 static void test_missing_lbuttonup(void)
1858 HWND listbox, parent, capture;
1860 parent = create_parent();
1861 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1863 /* Send button down without a corresponding button up */
1864 SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(10, 10));
1865 capture = GetCapture();
1866 ok(capture == listbox, "got %p expected %p\n", capture, listbox);
1868 /* Capture is released and LBN_SELCHANGE sent during WM_KILLFOCUS */
1869 got_selchange = 0;
1870 SetFocus(NULL);
1871 capture = GetCapture();
1872 ok(capture == NULL, "got %p\n", capture);
1873 ok(got_selchange, "got %d\n", got_selchange);
1875 DestroyWindow(listbox);
1876 DestroyWindow(parent);
1879 static void test_extents(void)
1881 HWND listbox, parent;
1882 SCROLLINFO sinfo;
1883 DWORD res;
1884 BOOL br;
1886 parent = create_parent();
1888 listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
1890 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1891 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1893 sinfo.cbSize = sizeof(sinfo);
1894 sinfo.fMask = SIF_RANGE;
1895 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1896 ok(br == TRUE, "GetScrollInfo failed\n");
1897 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1898 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1899 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1900 "List box should not have a horizontal scroll bar\n");
1902 /* horizontal extent < width */
1903 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1905 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1906 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1908 sinfo.cbSize = sizeof(sinfo);
1909 sinfo.fMask = SIF_RANGE;
1910 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1911 ok(br == TRUE, "GetScrollInfo failed\n");
1912 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1913 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1914 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1915 "List box should not have a horizontal scroll bar\n");
1917 /* horizontal extent > width */
1918 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1920 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1921 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1923 sinfo.cbSize = sizeof(sinfo);
1924 sinfo.fMask = SIF_RANGE;
1925 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1926 ok(br == TRUE, "GetScrollInfo failed\n");
1927 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1928 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1929 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1930 "List box should not have a horizontal scroll bar\n");
1932 DestroyWindow(listbox);
1934 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL, parent);
1936 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1937 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
1939 sinfo.cbSize = sizeof(sinfo);
1940 sinfo.fMask = SIF_RANGE;
1941 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1942 ok(br == TRUE, "GetScrollInfo failed\n");
1943 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1944 ok(sinfo.nMax == 100, "got wrong max: %u\n", sinfo.nMax);
1945 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1946 "List box should not have a horizontal scroll bar\n");
1948 /* horizontal extent < width */
1949 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
1951 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1952 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
1954 sinfo.cbSize = sizeof(sinfo);
1955 sinfo.fMask = SIF_RANGE;
1956 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1957 ok(br == TRUE, "GetScrollInfo failed\n");
1958 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1959 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
1960 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1961 "List box should not have a horizontal scroll bar\n");
1963 /* horizontal extent > width */
1964 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
1966 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1967 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
1969 sinfo.cbSize = sizeof(sinfo);
1970 sinfo.fMask = SIF_RANGE;
1971 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1972 ok(br == TRUE, "GetScrollInfo failed\n");
1973 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1974 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
1975 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
1976 "List box should have a horizontal scroll bar\n");
1978 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
1980 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1981 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
1983 sinfo.cbSize = sizeof(sinfo);
1984 sinfo.fMask = SIF_RANGE;
1985 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
1986 ok(br == TRUE, "GetScrollInfo failed\n");
1987 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
1988 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
1989 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) == 0,
1990 "List box should not have a horizontal scroll bar\n");
1992 DestroyWindow(listbox);
1995 listbox = create_listbox(WS_CHILD | WS_VISIBLE | WS_HSCROLL | LBS_DISABLENOSCROLL, parent);
1997 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
1998 ok(res == 0, "Got wrong initial horizontal extent: %u\n", res);
2000 sinfo.cbSize = sizeof(sinfo);
2001 sinfo.fMask = SIF_RANGE;
2002 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2003 ok(br == TRUE, "GetScrollInfo failed\n");
2004 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2005 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2006 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2007 "List box should have a horizontal scroll bar\n");
2009 /* horizontal extent < width */
2010 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 64, 0);
2012 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2013 ok(res == 64, "Got wrong horizontal extent: %u\n", res);
2015 sinfo.cbSize = sizeof(sinfo);
2016 sinfo.fMask = SIF_RANGE;
2017 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2018 ok(br == TRUE, "GetScrollInfo failed\n");
2019 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2020 ok(sinfo.nMax == 63, "got wrong max: %u\n", sinfo.nMax);
2021 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2022 "List box should have a horizontal scroll bar\n");
2024 /* horizontal extent > width */
2025 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 184, 0);
2027 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2028 ok(res == 184, "Got wrong horizontal extent: %u\n", res);
2030 sinfo.cbSize = sizeof(sinfo);
2031 sinfo.fMask = SIF_RANGE;
2032 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2033 ok(br == TRUE, "GetScrollInfo failed\n");
2034 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2035 ok(sinfo.nMax == 183, "got wrong max: %u\n", sinfo.nMax);
2036 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2037 "List box should have a horizontal scroll bar\n");
2039 SendMessageA(listbox, LB_SETHORIZONTALEXTENT, 0, 0);
2041 res = SendMessageA(listbox, LB_GETHORIZONTALEXTENT, 0, 0);
2042 ok(res == 0, "Got wrong horizontal extent: %u\n", res);
2044 sinfo.cbSize = sizeof(sinfo);
2045 sinfo.fMask = SIF_RANGE;
2046 br = GetScrollInfo(listbox, SB_HORZ, &sinfo);
2047 ok(br == TRUE, "GetScrollInfo failed\n");
2048 ok(sinfo.nMin == 0, "got wrong min: %u\n", sinfo.nMin);
2049 ok(sinfo.nMax == 0, "got wrong max: %u\n", sinfo.nMax);
2050 ok((GetWindowLongA(listbox, GWL_STYLE) & WS_HSCROLL) != 0,
2051 "List box should have a horizontal scroll bar\n");
2053 DestroyWindow(listbox);
2055 DestroyWindow(parent);
2058 static void test_listbox(void)
2060 static const struct listbox_test SS =
2061 /* {add_style} */
2062 {{0},
2063 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2064 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2065 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2066 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2068 /* {selected, anchor, caret, selcount}{TODO fields} */
2069 static const struct listbox_test SS_NS =
2070 {{LBS_NOSEL},
2071 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2072 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2073 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2074 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2076 static const struct listbox_test MS =
2077 {{LBS_MULTIPLESEL},
2078 { 0, LB_ERR, 0, 0}, {0,0,0,0},
2079 { 1, 1, 1, 1}, {0,0,0,0},
2080 { 2, 1, 2, 1}, {0,0,0,0},
2081 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2083 static const struct listbox_test MS_NS =
2084 {{LBS_MULTIPLESEL | LBS_NOSEL},
2085 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2086 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2087 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2088 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2090 static const struct listbox_test ES =
2091 {{LBS_EXTENDEDSEL},
2092 { 0, LB_ERR, 0, 0}, {0,0,0,0},
2093 { 1, 1, 1, 1}, {0,0,0,0},
2094 { 2, 2, 2, 1}, {0,0,0,0},
2095 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2097 static const struct listbox_test ES_NS =
2098 {{LBS_EXTENDEDSEL | LBS_NOSEL},
2099 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2100 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2101 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2102 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2104 static const struct listbox_test EMS =
2105 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
2106 { 0, LB_ERR, 0, 0}, {0,0,0,0},
2107 { 1, 1, 1, 1}, {0,0,0,0},
2108 { 2, 2, 2, 1}, {0,0,0,0},
2109 { 0, LB_ERR, 0, 2}, {0,0,0,0}};
2111 static const struct listbox_test EMS_NS =
2112 {{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
2113 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
2114 { 1, 1, 1, LB_ERR}, {0,0,0,0},
2115 { 2, 2, 2, LB_ERR}, {0,0,0,0},
2116 {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
2118 run_test(SS);
2119 run_test(SS_NS);
2120 run_test(MS);
2121 run_test(MS_NS);
2122 run_test(ES);
2123 run_test(ES_NS);
2124 run_test(EMS);
2125 run_test(EMS_NS);
2128 static const struct message lb_addstring_ownerdraw_parent_seq[] =
2130 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2131 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2132 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2133 { 0 }
2136 static const struct message lb_addstring_sort_parent_seq[] =
2138 { WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
2139 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
2140 { WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
2141 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
2142 { WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
2143 { WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
2144 { 0 }
2147 static const struct message empty_seq[] =
2149 { 0 }
2152 static void test_WM_MEASUREITEM(void)
2154 HWND parent, listbox;
2155 LRESULT data, ret;
2157 parent = create_parent();
2158 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
2160 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2161 ok(data == (LRESULT)strings[0], "data = %08lx, expected %p\n", data, strings[0]);
2162 DestroyWindow(parent);
2164 parent = create_parent();
2165 listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS, parent);
2167 data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
2168 ok(!data, "data = %08lx\n", data);
2170 /* LBS_HASSTRINGS */
2171 parent = create_parent();
2172 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2173 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
2174 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2176 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2178 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2179 ok(ret == 0, "expected 0, got %ld\n", ret);
2180 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2181 ok(ret == 1, "expected 1, got %ld\n", ret);
2182 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2183 ok(ret == 2, "expected 2, got %ld\n", ret);
2185 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
2186 "LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
2187 DestroyWindow(listbox);
2189 /* LBS_SORT, no LBS_HASSTRINGS */
2190 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2191 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
2192 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2194 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2196 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2197 ok(ret == 0, "expected 0, got %ld\n", ret);
2198 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2199 ok(ret == 1, "expected 1, got %ld\n", ret);
2200 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2201 ok(ret == 2, "expected 2, got %ld\n", ret);
2203 ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", FALSE);
2204 DestroyWindow(listbox);
2206 /* LBS_HASSTRINGS */
2207 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2208 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
2209 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2211 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2213 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2214 ok(ret == 0, "expected 0, got %ld\n", ret);
2215 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2216 ok(ret == 1, "expected 1, got %ld\n", ret);
2217 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2218 ok(ret == 2, "expected 2, got %ld\n", ret);
2220 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
2221 DestroyWindow(listbox);
2223 /* LBS_HASSTRINGS, LBS_SORT */
2224 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
2225 WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
2226 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
2228 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2230 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
2231 ok(ret == 0, "expected 0, got %ld\n", ret);
2232 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
2233 ok(ret == 0, "expected 0, got %ld\n", ret);
2234 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
2235 ok(ret == 1, "expected 1, got %ld\n", ret);
2237 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
2238 DestroyWindow(listbox);
2240 DestroyWindow(parent);
2243 START_TEST(listbox)
2245 ULONG_PTR ctx_cookie;
2246 HANDLE hCtx;
2248 if (!load_v6_module(&ctx_cookie, &hCtx))
2249 return;
2251 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2253 test_listbox();
2254 test_item_height();
2255 test_ownerdraw();
2256 test_LB_SELITEMRANGE();
2257 test_LB_SETCURSEL();
2258 test_listbox_height();
2259 test_itemfrompoint();
2260 test_listbox_item_data();
2261 test_listbox_LB_DIR();
2262 test_listbox_dlgdir();
2263 test_set_count();
2264 test_GetListBoxInfo();
2265 test_missing_lbuttonup();
2266 test_extents();
2267 test_WM_MEASUREITEM();
2268 test_LB_SETSEL();
2270 unload_v6_module(ctx_cookie, hCtx);