[USER32_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / user32 / combo.c
1 /* Unit test suite for combo boxes.
2 *
3 * Copyright 2007 Mikolaj Zalewski
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "precomp.h"
21
22 #define COMBO_ID 1995
23
24 static HWND hMainWnd;
25
26 #define expect_eq(expr, value, type, fmt); { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); }
27 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
28 r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \
29 wine_dbgstr_rect(&r), _left, _top, _right, _bottom);
30
31 static HWND build_combo(DWORD style)
32 {
33 return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
34 }
35
36 static int font_height(HFONT hFont)
37 {
38 TEXTMETRICA tm;
39 HFONT hFontOld;
40 HDC hDC;
41
42 hDC = CreateCompatibleDC(NULL);
43 hFontOld = SelectObject(hDC, hFont);
44 GetTextMetricsA(hDC, &tm);
45 SelectObject(hDC, hFontOld);
46 DeleteDC(hDC);
47
48 return tm.tmHeight;
49 }
50
51 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
52 {
53 return 0;
54 }
55
56 static BOOL is_font_installed(const char *name)
57 {
58 HDC hdc = GetDC(NULL);
59 BOOL ret = !EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0);
60 ReleaseDC(NULL, hdc);
61 return ret;
62 }
63
64 static void test_setitemheight(DWORD style)
65 {
66 HWND hCombo = build_combo(style);
67 RECT r;
68 int i;
69
70 trace("Style %x\n", style);
71 GetClientRect(hCombo, &r);
72 expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
73 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
74 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
75 todo_wine expect_rect(r, 5, 5, 105, 105);
76
77 for (i = 1; i < 30; i++)
78 {
79 SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, i);
80 GetClientRect(hCombo, &r);
81 expect_eq(r.bottom - r.top, i + 6, int, "%d");
82 }
83
84 DestroyWindow(hCombo);
85 }
86
87 static void test_setfont(DWORD style)
88 {
89 HWND hCombo;
90 HFONT hFont1, hFont2;
91 RECT r;
92 int i;
93
94 if (!is_font_installed("Marlett"))
95 {
96 skip("Marlett font not available\n");
97 return;
98 }
99
100 trace("Style %x\n", style);
101
102 hCombo = build_combo(style);
103 hFont1 = CreateFontA(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
104 hFont2 = CreateFontA(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
105
106 GetClientRect(hCombo, &r);
107 expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
108 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
109 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
110 todo_wine expect_rect(r, 5, 5, 105, 105);
111
112 /* The size of the dropped control is initially equal to the size
113 of the window when it was created. The size of the calculated
114 dropped area changes only by how much the selection area
115 changes, not by how much the list area changes. */
116 if (font_height(hFont1) == 10 && font_height(hFont2) == 8)
117 {
118 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
119 GetClientRect(hCombo, &r);
120 expect_rect(r, 0, 0, 100, 18);
121 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
122 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
123 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1)));
124
125 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE);
126 GetClientRect(hCombo, &r);
127 expect_rect(r, 0, 0, 100, 16);
128 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
129 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
130 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont2)));
131
132 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
133 GetClientRect(hCombo, &r);
134 expect_rect(r, 0, 0, 100, 18);
135 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
136 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
137 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1)));
138 }
139 else
140 {
141 ok(0, "Expected Marlett font heights 10/8, got %d/%d\n",
142 font_height(hFont1), font_height(hFont2));
143 }
144
145 for (i = 1; i < 30; i++)
146 {
147 HFONT hFont = CreateFontA(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
148 int height = font_height(hFont);
149
150 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE);
151 GetClientRect(hCombo, &r);
152 expect_eq(r.bottom - r.top, height + 8, int, "%d");
153 SendMessageA(hCombo, WM_SETFONT, 0, FALSE);
154 DeleteObject(hFont);
155 }
156
157 DestroyWindow(hCombo);
158 DeleteObject(hFont1);
159 DeleteObject(hFont2);
160 }
161
162 static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
163 static LPCSTR expected_edit_text;
164 static LPCSTR expected_list_text;
165 static BOOL selchange_fired;
166
167 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
168 {
169 switch (msg)
170 {
171 case WM_COMMAND:
172 switch (wparam)
173 {
174 case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE):
175 {
176 HWND hCombo = (HWND)lparam;
177 int idx;
178 char list[20], edit[20];
179
180 memset(list, 0, sizeof(list));
181 memset(edit, 0, sizeof(edit));
182
183 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
184 SendMessageA(hCombo, CB_GETLBTEXT, idx, (LPARAM)list);
185 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
186
187 ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n",
188 edit, expected_edit_text);
189 ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n",
190 list, expected_list_text);
191
192 selchange_fired = TRUE;
193 }
194 break;
195 }
196 break;
197 }
198
199 return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam);
200 }
201
202 static void test_selection(DWORD style, const char * const text[],
203 const int *edit, const int *list)
204 {
205 INT idx;
206 HWND hCombo;
207
208 hCombo = build_combo(style);
209
210 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]);
211 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]);
212 SendMessageA(hCombo, CB_SETCURSEL, -1, 0);
213
214 old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
215
216 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
217 ok(idx == -1, "expected selection -1, got %d\n", idx);
218
219 /* keyboard navigation */
220
221 expected_list_text = text[list[0]];
222 expected_edit_text = text[edit[0]];
223 selchange_fired = FALSE;
224 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
225 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
226
227 expected_list_text = text[list[1]];
228 expected_edit_text = text[edit[1]];
229 selchange_fired = FALSE;
230 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
231 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
232
233 expected_list_text = text[list[2]];
234 expected_edit_text = text[edit[2]];
235 selchange_fired = FALSE;
236 SendMessageA(hCombo, WM_KEYDOWN, VK_UP, 0);
237 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
238
239 /* programmatic navigation */
240
241 expected_list_text = text[list[3]];
242 expected_edit_text = text[edit[3]];
243 selchange_fired = FALSE;
244 SendMessageA(hCombo, CB_SETCURSEL, list[3], 0);
245 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
246
247 expected_list_text = text[list[4]];
248 expected_edit_text = text[edit[4]];
249 selchange_fired = FALSE;
250 SendMessageA(hCombo, CB_SETCURSEL, list[4], 0);
251 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
252
253 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
254 DestroyWindow(hCombo);
255 }
256
257 static void test_CBN_SELCHANGE(void)
258 {
259 static const char * const text[] = { "alpha", "beta", "" };
260 static const int sel_1[] = { 2, 0, 1, 0, 1 };
261 static const int sel_2[] = { 0, 1, 0, 0, 1 };
262
263 test_selection(CBS_SIMPLE, text, sel_1, sel_2);
264 test_selection(CBS_DROPDOWN, text, sel_1, sel_2);
265 test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
266 }
267
268 static void test_WM_LBUTTONDOWN(void)
269 {
270 HWND hCombo, hEdit, hList;
271 COMBOBOXINFO cbInfo;
272 UINT x, y, item_height;
273 LRESULT result;
274 int i, idx;
275 RECT rect;
276 CHAR buffer[3];
277 static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
278 static const CHAR stringFormat[] = "%2d";
279 BOOL ret;
280 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
281
282 pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
283 if (!pGetComboBoxInfo){
284 win_skip("GetComboBoxInfo is not available\n");
285 return;
286 }
287
288 hCombo = CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|CBS_DROPDOWN,
289 0, 0, 200, 150, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
290
291 for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
292 sprintf(buffer, stringFormat, choices[i]);
293 result = SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer);
294 ok(result == i,
295 "Failed to add item %d\n", i);
296 }
297
298 cbInfo.cbSize = sizeof(COMBOBOXINFO);
299 SetLastError(0xdeadbeef);
300 ret = pGetComboBoxInfo(hCombo, &cbInfo);
301 ok(ret, "Failed to get combobox info structure. LastError=%d\n",
302 GetLastError());
303 hEdit = cbInfo.hwndItem;
304 hList = cbInfo.hwndList;
305
306 trace("hMainWnd=%p, hCombo=%p, hList=%p, hEdit=%p\n", hMainWnd, hCombo, hList, hEdit);
307 ok(GetFocus() == hMainWnd, "Focus not on Main Window, instead on %p\n", GetFocus());
308
309 /* Click on the button to drop down the list */
310 x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
311 y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
312 result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
313 ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
314 GetLastError());
315 ok(SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0),
316 "The dropdown list should have appeared after clicking the button.\n");
317
318 ok(GetFocus() == hEdit,
319 "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
320 result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
321 ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
322 GetLastError());
323 ok(GetFocus() == hEdit,
324 "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
325
326 /* Click on the 5th item in the list */
327 item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0);
328 ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
329 x = rect.left + (rect.right-rect.left)/2;
330 y = item_height/2 + item_height*4;
331 result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
332 ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
333 GetLastError());
334 ok(GetFocus() == hEdit,
335 "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
336
337 result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
338 ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
339 GetLastError());
340 ok(GetFocus() == hEdit,
341 "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
342 ok(SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0),
343 "The dropdown list should still be visible.\n");
344
345 result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
346 ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
347 GetLastError());
348 ok(GetFocus() == hEdit,
349 "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
350 ok(!SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0),
351 "The dropdown list should have been rolled up.\n");
352 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
353 ok(idx, "Current Selection: expected %d, got %d\n", 4, idx);
354
355 DestroyWindow(hCombo);
356 }
357
358 static void test_changesize( DWORD style)
359 {
360 HWND hCombo = build_combo(style);
361 RECT rc;
362 INT ddheight, clheight, ddwidth, clwidth;
363 /* get initial measurements */
364 GetClientRect( hCombo, &rc);
365 clheight = rc.bottom - rc.top;
366 clwidth = rc.right - rc.left;
367 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
368 ddheight = rc.bottom - rc.top;
369 ddwidth = rc.right - rc.left;
370 /* use MoveWindow to move & resize the combo */
371 /* first make it slightly smaller */
372 MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE);
373 GetClientRect( hCombo, &rc);
374 ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n",
375 rc.right - rc.left, clwidth - 2);
376 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
377 rc.bottom - rc.top, clheight);
378 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
379 ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n",
380 rc.right - rc.left, clwidth - 2);
381 ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n",
382 rc.bottom - rc.top, ddheight);
383 ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n",
384 rc.right - rc.left, ddwidth - 2);
385 /* new cx, cy is slightly bigger than the initial values */
386 MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE);
387 GetClientRect( hCombo, &rc);
388 ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n",
389 rc.right - rc.left, clwidth + 2);
390 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
391 rc.bottom - rc.top, clheight);
392 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
393 ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n",
394 rc.right - rc.left, clwidth + 2);
395 todo_wine {
396 ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n",
397 rc.bottom - rc.top, clheight + 2);
398 }
399
400 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0);
401 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
402 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
403 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
404
405 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
406 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
407 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
408 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
409
410 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0);
411 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
412 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
413 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
414
415 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0);
416 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
417 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
418 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
419
420 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
421 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
422 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
423 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
424
425 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0);
426 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
427 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
428 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
429
430 DestroyWindow(hCombo);
431 }
432
433 static void test_editselection(void)
434 {
435 HWND hCombo;
436 INT start,end;
437 HWND hEdit;
438 COMBOBOXINFO cbInfo;
439 BOOL ret;
440 DWORD len;
441 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
442 char edit[20];
443
444 pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
445 if (!pGetComboBoxInfo){
446 win_skip("GetComboBoxInfo is not available\n");
447 return;
448 }
449
450 /* Build a combo */
451 hCombo = build_combo(CBS_SIMPLE);
452 cbInfo.cbSize = sizeof(COMBOBOXINFO);
453 SetLastError(0xdeadbeef);
454 ret = pGetComboBoxInfo(hCombo, &cbInfo);
455 ok(ret, "Failed to get combobox info structure. LastError=%d\n",
456 GetLastError());
457 hEdit = cbInfo.hwndItem;
458
459 /* Initially combo selection is empty*/
460 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
461 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
462 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
463
464 /* Set some text, and press a key to replace it */
465 edit[0] = 0x00;
466 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1");
467 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
468 ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit);
469
470 /* Now what is the selection - still empty */
471 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
472 ok(start==0, "Unexpected start position for selection %d\n", start);
473 ok(end==0, "Unexpected end position for selection %d\n", end);
474 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
475 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
476 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
477
478 /* Give it focus, and it gets selected */
479 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
480 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
481 ok(start==0, "Unexpected start position for selection %d\n", start);
482 ok(end==6, "Unexpected end position for selection %d\n", end);
483 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
484 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
485 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
486
487 /* Now emulate a key press */
488 edit[0] = 0x00;
489 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
490 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
491 ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit);
492
493 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
494 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
495 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
496
497 /* Now what happens when it gets more focus a second time - it doesn't reselect */
498 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
499 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
500 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
501 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
502 DestroyWindow(hCombo);
503
504 /* Start again - Build a combo */
505 hCombo = build_combo(CBS_SIMPLE);
506 cbInfo.cbSize = sizeof(COMBOBOXINFO);
507 SetLastError(0xdeadbeef);
508 ret = pGetComboBoxInfo(hCombo, &cbInfo);
509 ok(ret, "Failed to get combobox info structure. LastError=%d\n",
510 GetLastError());
511 hEdit = cbInfo.hwndItem;
512
513 /* Set some text and give focus so it gets selected */
514 edit[0] = 0x00;
515 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2");
516 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
517 ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit);
518
519 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
520
521 /* Now what is the selection */
522 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
523 ok(start==0, "Unexpected start position for selection %d\n", start);
524 ok(end==6, "Unexpected end position for selection %d\n", end);
525 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
526 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
527 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
528
529 /* Now change the selection to the apparently invalid start -1, end -1 and
530 show it means no selection (ie start -1) but cursor at end */
531 SendMessageA(hCombo, CB_SETEDITSEL, 0, -1);
532 edit[0] = 0x00;
533 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
534 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
535 ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit);
536 DestroyWindow(hCombo);
537 }
538
539 static WNDPROC edit_window_proc;
540 static long setsel_start = 1, setsel_end = 1;
541 static HWND hCBN_SetFocus, hCBN_KillFocus;
542
543 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
544 {
545 if (msg == EM_SETSEL)
546 {
547 setsel_start = wParam;
548 setsel_end = lParam;
549 }
550 return CallWindowProcA(edit_window_proc, hwnd, msg, wParam, lParam);
551 }
552
553 static LRESULT CALLBACK test_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
554 {
555 switch (msg)
556 {
557 case WM_COMMAND:
558 switch (HIWORD(wParam))
559 {
560 case CBN_SETFOCUS:
561 hCBN_SetFocus = (HWND)lParam;
562 break;
563 case CBN_KILLFOCUS:
564 hCBN_KillFocus = (HWND)lParam;
565 break;
566 }
567 break;
568 case WM_NEXTDLGCTL:
569 SetFocus((HWND)wParam);
570 break;
571 }
572 return CallWindowProcA(old_parent_proc, hwnd, msg, wParam, lParam);
573 }
574
575 static void test_editselection_focus(DWORD style)
576 {
577 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
578 HWND hCombo, hEdit, hButton;
579 COMBOBOXINFO cbInfo;
580 BOOL ret;
581 const char wine_test[] = "Wine Test";
582 char buffer[16] = {0};
583 DWORD len;
584
585 pGetComboBoxInfo = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
586 if (!pGetComboBoxInfo)
587 {
588 win_skip("GetComboBoxInfo is not available\n");
589 return;
590 }
591
592 hCombo = build_combo(style);
593 cbInfo.cbSize = sizeof(COMBOBOXINFO);
594 SetLastError(0xdeadbeef);
595 ret = pGetComboBoxInfo(hCombo, &cbInfo);
596 ok(ret, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
597 hEdit = cbInfo.hwndItem;
598
599 hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
600 5, 50, 100, 20, hMainWnd, NULL,
601 (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL);
602
603 old_parent_proc = (WNDPROC)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)test_window_proc);
604 edit_window_proc = (WNDPROC)SetWindowLongPtrA(hEdit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
605
606 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
607 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
608 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
609 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
610 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
611
612 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
613 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
614 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
615 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
616 ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
617
618 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)wine_test);
619 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hCombo, TRUE);
620 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
621 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
622 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
623 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
624 SendMessageA(hCombo, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
625 ok(!strcmp(buffer, wine_test), "Unexpected text in edit control; got '%s'\n", buffer);
626
627 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
628 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
629 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
630 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
631 ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
632 len = SendMessageA(hCombo, CB_GETEDITSEL, 0, 0);
633 ok(len == 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len), HIWORD(len));
634
635 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
636 DestroyWindow(hButton);
637 DestroyWindow(hCombo);
638 }
639
640 static void test_listbox_styles(DWORD cb_style)
641 {
642 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
643 HWND combo;
644 COMBOBOXINFO info;
645 DWORD style, exstyle, expect_style, expect_exstyle;
646 BOOL ret;
647
648 pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
649 if (!pGetComboBoxInfo){
650 win_skip("GetComboBoxInfo is not available\n");
651 return;
652 }
653
654 expect_style = WS_CHILD|WS_CLIPSIBLINGS|LBS_COMBOBOX|LBS_HASSTRINGS|LBS_NOTIFY;
655 if (cb_style == CBS_SIMPLE)
656 {
657 expect_style |= WS_VISIBLE;
658 expect_exstyle = WS_EX_CLIENTEDGE;
659 }
660 else
661 {
662 expect_style |= WS_BORDER;
663 expect_exstyle = WS_EX_TOOLWINDOW;
664 }
665
666 combo = build_combo(cb_style);
667 info.cbSize = sizeof(COMBOBOXINFO);
668 SetLastError(0xdeadbeef);
669 ret = pGetComboBoxInfo(combo, &info);
670 ok(ret, "Failed to get combobox info structure.\n");
671
672 style = GetWindowLongW( info.hwndList, GWL_STYLE );
673 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
674 ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
675 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
676
677 if (cb_style != CBS_SIMPLE)
678 expect_exstyle |= WS_EX_TOPMOST;
679
680 SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 );
681 style = GetWindowLongW( info.hwndList, GWL_STYLE );
682 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
683 ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style);
684 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
685
686 SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 );
687 style = GetWindowLongW( info.hwndList, GWL_STYLE );
688 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
689 ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
690 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
691
692 DestroyWindow(combo);
693 }
694
695 START_TEST(combo)
696 {
697 hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
698 ShowWindow(hMainWnd, SW_SHOW);
699
700 test_setfont(CBS_DROPDOWN);
701 test_setfont(CBS_DROPDOWNLIST);
702 test_setitemheight(CBS_DROPDOWN);
703 test_setitemheight(CBS_DROPDOWNLIST);
704 test_CBN_SELCHANGE();
705 test_WM_LBUTTONDOWN();
706 test_changesize(CBS_DROPDOWN);
707 test_changesize(CBS_DROPDOWNLIST);
708 test_editselection();
709 test_editselection_focus(CBS_SIMPLE);
710 test_editselection_focus(CBS_DROPDOWN);
711 test_listbox_styles(CBS_SIMPLE);
712 test_listbox_styles(CBS_DROPDOWN);
713 test_listbox_styles(CBS_DROPDOWNLIST);
714
715 DestroyWindow(hMainWnd);
716 }