wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / comctl32 / tests / combo.c
blob63470a50ff712aec99d94b730951f9208966bd42
1 /* Unit test suite for ComboBox and ComboBoxEx32 controls.
3 * Copyright 2005 Jason Edmeades
4 * Copyright 2007 Mikolaj Zalewski
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <limits.h>
22 #include <stdio.h>
23 #include <windows.h>
24 #include <commctrl.h>
26 #include "wine/test.h"
27 #include "v6util.h"
28 #include "msg.h"
30 #define EDITBOX_SEQ_INDEX 0
31 #define NUM_MSG_SEQUENCES 1
33 #define EDITBOX_ID 0
34 #define COMBO_ID 1995
36 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
38 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
39 r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \
40 wine_dbgstr_rect(&r), _left, _top, _right, _bottom);
43 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
45 static HWND hComboExParentWnd, hMainWnd;
46 static HINSTANCE hMainHinst;
47 static const char ComboExTestClass[] = "ComboExTestClass";
49 static HBRUSH brush_red;
51 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
53 #define MAX_CHARS 100
54 static char *textBuffer = NULL;
56 static BOOL received_end_edit = FALSE;
58 static void get_combobox_info(HWND hwnd, COMBOBOXINFO *info)
60 BOOL ret;
62 info->cbSize = sizeof(*info);
63 ret = GetComboBoxInfo(hwnd, info);
64 ok(ret, "Failed to get combobox info structure, error %d\n", GetLastError());
67 static HWND createComboEx(DWORD style) {
68 return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300,
69 hComboExParentWnd, NULL, hMainHinst, NULL);
72 static LONG addItem(HWND cbex, int idx, const char *text) {
73 COMBOBOXEXITEMA cbexItem;
74 memset(&cbexItem, 0x00, sizeof(cbexItem));
75 cbexItem.mask = CBEIF_TEXT;
76 cbexItem.iItem = idx;
77 cbexItem.pszText = (char*)text;
78 cbexItem.cchTextMax = 0;
79 return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem);
82 static LONG setItem(HWND cbex, int idx, const char *text) {
83 COMBOBOXEXITEMA cbexItem;
84 memset(&cbexItem, 0x00, sizeof(cbexItem));
85 cbexItem.mask = CBEIF_TEXT;
86 cbexItem.iItem = idx;
87 cbexItem.pszText = (char*)text;
88 cbexItem.cchTextMax = 0;
89 return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem);
92 static LONG delItem(HWND cbex, int idx) {
93 return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0);
96 static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) {
97 memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA));
98 cbItem->mask = CBEIF_TEXT;
99 cbItem->pszText = textBuffer;
100 cbItem->iItem = idx;
101 cbItem->cchTextMax = 100;
102 return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem);
105 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
107 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
108 static LONG defwndproc_counter = 0;
109 struct message msg = { 0 };
110 LRESULT ret;
112 msg.message = message;
113 msg.flags = sent|wparam|lparam;
114 if (defwndproc_counter) msg.flags |= defwinproc;
115 msg.wParam = wParam;
116 msg.lParam = lParam;
117 msg.id = EDITBOX_ID;
119 if (message != WM_PAINT &&
120 message != WM_ERASEBKGND &&
121 message != WM_NCPAINT &&
122 message != WM_NCHITTEST &&
123 message != WM_GETTEXT &&
124 message != WM_GETICON &&
125 message != WM_DEVICECHANGE)
127 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
130 defwndproc_counter++;
131 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
132 defwndproc_counter--;
133 return ret;
136 static HWND subclass_editbox(HWND hwndComboEx)
138 WNDPROC oldproc;
139 HWND hwnd;
141 hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0);
142 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
143 (LONG_PTR)editbox_subclass_proc);
144 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
146 return hwnd;
149 static void test_comboex(void)
151 HWND myHwnd = 0;
152 LONG res;
153 COMBOBOXEXITEMA cbexItem;
154 static const char *first_item = "First Item",
155 *second_item = "Second Item",
156 *third_item = "Third Item",
157 *middle_item = "Between First and Second Items",
158 *replacement_item = "Between First and Second Items",
159 *out_of_range_item = "Out of Range Item";
161 /* Allocate space for result */
162 textBuffer = heap_alloc(MAX_CHARS);
164 /* Basic comboboxex test */
165 myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
167 /* Add items onto the end of the combobox */
168 res = addItem(myHwnd, -1, first_item);
169 ok(res == 0, "Adding simple item failed (%d)\n", res);
170 res = addItem(myHwnd, -1, second_item);
171 ok(res == 1, "Adding simple item failed (%d)\n", res);
172 res = addItem(myHwnd, 2, third_item);
173 ok(res == 2, "Adding simple item failed (%d)\n", res);
174 res = addItem(myHwnd, 1, middle_item);
175 ok(res == 1, "Inserting simple item failed (%d)\n", res);
177 /* Add an item completely out of range */
178 res = addItem(myHwnd, 99, out_of_range_item);
179 ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
180 res = addItem(myHwnd, 5, out_of_range_item);
181 ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
182 /* Removed: Causes traps on Windows XP
183 res = addItem(myHwnd, -2, "Out Of Range Item");
184 ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
187 /* Get an item completely out of range */
188 res = getItem(myHwnd, 99, &cbexItem);
189 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
190 res = getItem(myHwnd, 4, &cbexItem);
191 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
192 res = getItem(myHwnd, -2, &cbexItem);
193 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
195 /* Get an item in range */
196 res = getItem(myHwnd, 0, &cbexItem);
197 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
198 ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
200 res = getItem(myHwnd, 1, &cbexItem);
201 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
202 ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
204 res = getItem(myHwnd, 2, &cbexItem);
205 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
206 ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
208 res = getItem(myHwnd, 3, &cbexItem);
209 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
210 ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
212 /* Set an item completely out of range */
213 res = setItem(myHwnd, 99, replacement_item);
214 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
215 res = setItem(myHwnd, 4, replacement_item);
216 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
217 res = setItem(myHwnd, -2, replacement_item);
218 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
220 /* Set an item in range */
221 res = setItem(myHwnd, 0, replacement_item);
222 ok(res != 0, "Setting first item failed (%d)\n", res);
223 res = setItem(myHwnd, 3, replacement_item);
224 ok(res != 0, "Setting last item failed (%d)\n", res);
226 /* Remove items completely out of range (4 items in control at this point) */
227 res = delItem(myHwnd, -1);
228 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
229 res = delItem(myHwnd, 4);
230 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
232 /* Remove items in range (4 items in control at this point) */
233 res = delItem(myHwnd, 3);
234 ok(res == 3, "Deleting using out of range index failed (%d)\n", res);
235 res = delItem(myHwnd, 0);
236 ok(res == 2, "Deleting using out of range index failed (%d)\n", res);
237 res = delItem(myHwnd, 0);
238 ok(res == 1, "Deleting using out of range index failed (%d)\n", res);
239 res = delItem(myHwnd, 0);
240 ok(res == 0, "Deleting using out of range index failed (%d)\n", res);
242 /* Remove from an empty box */
243 res = delItem(myHwnd, 0);
244 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
247 /* Cleanup */
248 heap_free(textBuffer);
249 DestroyWindow(myHwnd);
252 static void test_comboex_WM_LBUTTONDOWN(void)
254 HWND hComboEx, hCombo, hEdit, hList;
255 COMBOBOXINFO cbInfo;
256 UINT x, y, item_height;
257 LRESULT result;
258 UINT i;
259 int idx;
260 RECT rect;
261 WCHAR buffer[3];
262 static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
264 hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL,
265 WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150,
266 hComboExParentWnd, NULL, hMainHinst, NULL);
268 for (i = 0; i < ARRAY_SIZE(choices); i++)
270 COMBOBOXEXITEMW cbexItem;
271 wsprintfW(buffer, L"%2d", choices[i]);
273 memset(&cbexItem, 0x00, sizeof(cbexItem));
274 cbexItem.mask = CBEIF_TEXT;
275 cbexItem.iItem = i;
276 cbexItem.pszText = buffer;
277 cbexItem.cchTextMax = 0;
278 ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0,
279 "Failed to add item %d\n", i);
282 hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
283 hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
285 get_combobox_info(hCombo, &cbInfo);
286 hList = cbInfo.hwndList;
288 ok(GetFocus() == hComboExParentWnd,
289 "Focus not on Main Window, instead on %p\n", GetFocus());
291 /* Click on the button to drop down the list */
292 x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
293 y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
294 result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
295 ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
296 GetLastError());
297 ok(GetFocus() == hCombo ||
298 broken(GetFocus() != hCombo), /* win98 */
299 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
300 GetFocus());
301 ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
302 "The dropdown list should have appeared after clicking the button.\n");
303 idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0);
304 ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx);
306 result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
307 ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
308 GetLastError());
309 ok(GetFocus() == hCombo ||
310 broken(GetFocus() != hCombo), /* win98 */
311 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
312 GetFocus());
314 /* Click on the 5th item in the list */
315 item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0);
316 ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
317 x = rect.left + (rect.right-rect.left)/2;
318 y = item_height/2 + item_height*4;
319 result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
320 ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
321 GetLastError());
322 ok(GetFocus() == hCombo ||
323 broken(GetFocus() != hCombo), /* win98 */
324 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
325 GetFocus());
327 result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
328 ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
329 GetLastError());
330 ok(GetFocus() == hCombo ||
331 broken(GetFocus() != hCombo), /* win98 */
332 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
333 GetFocus());
334 ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0),
335 "The dropdown list should still be visible.\n");
337 result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
338 ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
339 GetLastError());
340 todo_wine ok(GetFocus() == hEdit ||
341 broken(GetFocus() == hCombo), /* win98 */
342 "Focus not on ComboBoxEx's Edit Control, instead on %p\n",
343 GetFocus());
345 result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
346 ok(!result ||
347 broken(result != 0), /* win98 */
348 "The dropdown list should have been rolled up.\n");
349 idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0);
350 ok(idx == 4 ||
351 broken(idx == -1), /* win98 */
352 "Current Selection: expected %d, got %d\n", 4, idx);
353 ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n");
355 SetFocus( hComboExParentWnd );
356 ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() );
357 SetFocus( hComboEx );
358 ok( GetFocus() == hEdit, "got %p\n", GetFocus() );
360 DestroyWindow(hComboEx);
363 static void test_comboex_CB_GETLBTEXT(void)
365 HWND hCombo;
366 CHAR buff[1];
367 COMBOBOXEXITEMA item;
368 LRESULT ret;
370 hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
372 /* set text to null */
373 addItem(hCombo, 0, NULL);
375 buff[0] = 'a';
376 item.mask = CBEIF_TEXT;
377 item.iItem = 0;
378 item.pszText = buff;
379 item.cchTextMax = 1;
380 ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item);
381 ok(ret != 0, "CBEM_GETITEM failed\n");
382 ok(buff[0] == 0, "\n");
384 ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
385 ok(ret == 0, "Expected zero length\n");
387 ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0);
388 ok(ret == 0, "Expected zero length\n");
390 buff[0] = 'a';
391 ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff);
392 ok(ret == 0, "Expected zero length\n");
393 ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff);
395 DestroyWindow(hCombo);
398 static void test_comboex_WM_WINDOWPOSCHANGING(void)
400 HWND hCombo;
401 WINDOWPOS wp;
402 RECT rect;
403 int combo_height;
404 int ret;
406 hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
407 ok(hCombo != NULL, "createComboEx failed\n");
408 ret = GetWindowRect(hCombo, &rect);
409 ok(ret, "GetWindowRect failed\n");
410 combo_height = rect.bottom - rect.top;
411 ok(combo_height > 0, "wrong combo height\n");
413 /* Test height > combo_height */
414 wp.x = rect.left;
415 wp.y = rect.top;
416 wp.cx = (rect.right - rect.left);
417 wp.cy = combo_height * 2;
418 wp.flags = 0;
419 wp.hwnd = hCombo;
420 wp.hwndInsertAfter = NULL;
422 ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
423 ok(ret == 0, "expected 0, got %x\n", ret);
424 ok(wp.cy == combo_height,
425 "Expected height %d, got %d\n", combo_height, wp.cy);
427 /* Test height < combo_height */
428 wp.x = rect.left;
429 wp.y = rect.top;
430 wp.cx = (rect.right - rect.left);
431 wp.cy = combo_height / 2;
432 wp.flags = 0;
433 wp.hwnd = hCombo;
434 wp.hwndInsertAfter = NULL;
436 ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
437 ok(ret == 0, "expected 0, got %x\n", ret);
438 ok(wp.cy == combo_height,
439 "Expected height %d, got %d\n", combo_height, wp.cy);
441 ret = DestroyWindow(hCombo);
442 ok(ret, "DestroyWindow failed\n");
445 static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
447 NMHDR *hdr = (NMHDR*)lParam;
448 switch(hdr->code){
449 case CBEN_ENDEDITA:
451 NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr;
452 if(edit_info->iWhy==CBENF_DROPDOWN){
453 received_end_edit = TRUE;
455 break;
457 case CBEN_ENDEDITW:
459 NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr;
460 if(edit_info->iWhy==CBENF_DROPDOWN){
461 received_end_edit = TRUE;
463 break;
466 return 0;
469 static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
471 switch(msg) {
473 case WM_DESTROY:
474 PostQuitMessage(0);
475 break;
476 case WM_NOTIFY:
477 return ComboExTestOnNotify(hWnd,msg,wParam,lParam);
478 default:
479 return DefWindowProcA(hWnd, msg, wParam, lParam);
482 return 0L;
485 static void init_functions(void)
487 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
489 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
490 #define X2(f, ord) p##f = (void*)GetProcAddress(hComCtl32, (const char *)ord);
491 X2(SetWindowSubclass, 410);
492 #undef X
493 #undef X2
496 static BOOL init(void)
498 WNDCLASSA wc;
500 wc.style = CS_HREDRAW | CS_VREDRAW;
501 wc.cbClsExtra = 0;
502 wc.cbWndExtra = 0;
503 wc.hInstance = GetModuleHandleA(NULL);
504 wc.hIcon = NULL;
505 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
506 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
507 wc.lpszMenuName = NULL;
508 wc.lpszClassName = ComboExTestClass;
509 wc.lpfnWndProc = ComboExTestWndProc;
510 RegisterClassA(&wc);
512 brush_red = CreateSolidBrush(RGB(255, 0, 0));
514 hMainWnd = CreateWindowA(WC_STATICA, "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
515 ShowWindow(hMainWnd, SW_SHOW);
517 hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
518 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
519 ok(hComboExParentWnd != NULL, "failed to create parent window\n");
521 hMainHinst = GetModuleHandleA(NULL);
523 return hComboExParentWnd != NULL;
526 static void cleanup(void)
528 MSG msg;
530 PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0);
531 while (GetMessageA(&msg,0,0,0)) {
532 TranslateMessage(&msg);
533 DispatchMessageA(&msg);
536 DestroyWindow(hComboExParentWnd);
537 UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
539 DestroyWindow(hMainWnd);
540 DeleteObject(brush_red);
543 static void test_comboex_subclass(void)
545 HWND hComboEx, hCombo, hEdit;
547 hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
549 hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
550 ok(hCombo != NULL, "Failed to get internal combo\n");
551 hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
552 ok(hEdit != NULL, "Failed to get internal edit\n");
554 if (pSetWindowSubclass)
556 ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
557 ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
560 DestroyWindow(hComboEx);
563 static const struct message test_setitem_edit_seq[] = {
564 { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID },
565 { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID },
566 { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID },
567 { 0 }
570 static void test_comboex_get_set_item(void)
572 char textA[] = "test";
573 HWND hComboEx;
574 COMBOBOXEXITEMA item;
575 BOOL ret;
577 hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
579 subclass_editbox(hComboEx);
581 flush_sequences(sequences, NUM_MSG_SEQUENCES);
583 memset(&item, 0, sizeof(item));
584 item.mask = CBEIF_TEXT;
585 item.pszText = textA;
586 item.iItem = -1;
587 ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
588 expect(TRUE, ret);
590 ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE);
592 /* get/set lParam */
593 item.mask = CBEIF_LPARAM;
594 item.iItem = -1;
595 item.lParam = 0xdeadbeef;
596 ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
597 expect(TRUE, ret);
598 ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam);
600 item.lParam = 0x1abe11ed;
601 ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
602 expect(TRUE, ret);
604 item.lParam = 0;
605 ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
606 expect(TRUE, ret);
607 ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam);
609 DestroyWindow(hComboEx);
612 static HWND create_combobox(DWORD style)
614 return CreateWindowA(WC_COMBOBOXA, "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
617 static int get_font_height(HFONT hFont)
619 TEXTMETRICA tm;
620 HFONT hFontOld;
621 HDC hDC;
623 hDC = CreateCompatibleDC(NULL);
624 hFontOld = SelectObject(hDC, hFont);
625 GetTextMetricsA(hDC, &tm);
626 SelectObject(hDC, hFontOld);
627 DeleteDC(hDC);
629 return tm.tmHeight;
632 static void test_combo_setitemheight(DWORD style)
634 HWND hCombo = create_combobox(style);
635 int i, font_height, height;
636 HFONT hFont;
637 RECT r;
639 GetClientRect(hCombo, &r);
640 expect_rect(r, 0, 0, 100, get_font_height(GetStockObject(SYSTEM_FONT)) + 8);
641 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
642 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
643 todo_wine expect_rect(r, 5, 5, 105, 105);
645 for (i = 1; i < 30; i++)
647 SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, i);
648 GetClientRect(hCombo, &r);
649 ok((r.bottom - r.top) == (i + 6), "Unexpected client rect height.\n");
652 DestroyWindow(hCombo);
654 /* Set item height below text height, force resize. */
655 hCombo = create_combobox(style);
657 hFont = (HFONT)SendMessageA(hCombo, WM_GETFONT, 0, 0);
658 font_height = get_font_height(hFont);
659 SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, font_height / 2);
660 height = SendMessageA(hCombo, CB_GETITEMHEIGHT, -1, 0);
661 todo_wine
662 ok(height == font_height / 2, "Unexpected item height %d, expected %d.\n", height, font_height / 2);
664 SetWindowPos(hCombo, NULL, 10, 10, 150, 5 * font_height, SWP_SHOWWINDOW);
665 height = SendMessageA(hCombo, CB_GETITEMHEIGHT, -1, 0);
666 ok(height > font_height, "Unexpected item height %d, font height %d.\n", height, font_height);
668 DestroyWindow(hCombo);
671 static void test_combo_setfont(DWORD style)
673 HFONT hFont1, hFont2;
674 HWND hCombo;
675 RECT r;
676 int i;
678 hCombo = create_combobox(style);
679 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");
680 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");
682 GetClientRect(hCombo, &r);
683 expect_rect(r, 0, 0, 100, get_font_height(GetStockObject(SYSTEM_FONT)) + 8);
684 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
685 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
686 todo_wine expect_rect(r, 5, 5, 105, 105);
688 /* The size of the dropped control is initially equal to the size
689 of the window when it was created. The size of the calculated
690 dropped area changes only by how much the selection area
691 changes, not by how much the list area changes. */
692 if (get_font_height(hFont1) == 10 && get_font_height(hFont2) == 8)
694 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
695 GetClientRect(hCombo, &r);
696 expect_rect(r, 0, 0, 100, 18);
697 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
698 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
699 todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1)));
701 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE);
702 GetClientRect(hCombo, &r);
703 expect_rect(r, 0, 0, 100, 16);
704 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
705 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
706 todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont2)));
708 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
709 GetClientRect(hCombo, &r);
710 expect_rect(r, 0, 0, 100, 18);
711 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
712 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
713 todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1)));
715 else
717 ok(0, "Expected Marlett font heights 10/8, got %d/%d\n",
718 get_font_height(hFont1), get_font_height(hFont2));
721 for (i = 1; i < 30; i++)
723 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");
724 int height = get_font_height(hFont);
726 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE);
727 GetClientRect(hCombo, &r);
728 ok((r.bottom - r.top) == (height + 8), "Unexpected client rect height.\n");
729 SendMessageA(hCombo, WM_SETFONT, 0, FALSE);
730 DeleteObject(hFont);
733 DestroyWindow(hCombo);
734 DeleteObject(hFont1);
735 DeleteObject(hFont2);
738 static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
739 static LPCSTR expected_edit_text;
740 static LPCSTR expected_list_text;
741 static BOOL selchange_fired;
742 static HWND lparam_for_WM_CTLCOLOR;
744 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
746 switch (msg)
748 case WM_COMMAND:
749 switch (wparam)
751 case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE):
753 HWND hCombo = (HWND)lparam;
754 char list[20], edit[20];
755 int idx;
757 memset(list, 0, sizeof(list));
758 memset(edit, 0, sizeof(edit));
760 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
761 SendMessageA(hCombo, CB_GETLBTEXT, idx, (LPARAM)list);
762 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
764 ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n",
765 edit, expected_edit_text);
766 ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n",
767 list, expected_list_text);
769 selchange_fired = TRUE;
771 break;
773 break;
774 case WM_CTLCOLOR:
775 case WM_CTLCOLORMSGBOX:
776 case WM_CTLCOLOREDIT:
777 case WM_CTLCOLORLISTBOX:
778 case WM_CTLCOLORBTN:
779 case WM_CTLCOLORDLG:
780 case WM_CTLCOLORSCROLLBAR:
781 case WM_CTLCOLORSTATIC:
782 if (lparam_for_WM_CTLCOLOR)
784 ok(lparam_for_WM_CTLCOLOR == (HWND)lparam, "Expected %p, got %p\n", lparam_for_WM_CTLCOLOR, (HWND)lparam);
785 return (LRESULT) brush_red;
787 break;
790 return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam);
793 static void test_selection(DWORD style, const char * const text[], const int *edit, const int *list)
795 HWND hCombo;
796 INT idx;
798 hCombo = create_combobox(style);
800 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]);
801 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]);
802 SendMessageA(hCombo, CB_SETCURSEL, -1, 0);
804 old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
806 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0);
807 ok(idx == -1, "expected selection -1, got %d\n", idx);
809 /* keyboard navigation */
811 expected_list_text = text[list[0]];
812 expected_edit_text = text[edit[0]];
813 selchange_fired = FALSE;
814 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
815 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
817 expected_list_text = text[list[1]];
818 expected_edit_text = text[edit[1]];
819 selchange_fired = FALSE;
820 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0);
821 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
823 expected_list_text = text[list[2]];
824 expected_edit_text = text[edit[2]];
825 selchange_fired = FALSE;
826 SendMessageA(hCombo, WM_KEYDOWN, VK_UP, 0);
827 ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
829 /* programmatic navigation */
831 expected_list_text = text[list[3]];
832 expected_edit_text = text[edit[3]];
833 selchange_fired = FALSE;
834 SendMessageA(hCombo, CB_SETCURSEL, list[3], 0);
835 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
837 expected_list_text = text[list[4]];
838 expected_edit_text = text[edit[4]];
839 selchange_fired = FALSE;
840 SendMessageA(hCombo, CB_SETCURSEL, list[4], 0);
841 ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
843 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
844 DestroyWindow(hCombo);
847 static void test_combo_CBN_SELCHANGE(void)
849 static const char * const text[] = { "alpha", "beta", "" };
850 static const int sel_1[] = { 2, 0, 1, 0, 1 };
851 static const int sel_2[] = { 0, 1, 0, 0, 1 };
853 test_selection(CBS_SIMPLE, text, sel_1, sel_2);
854 test_selection(CBS_DROPDOWN, text, sel_1, sel_2);
855 test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
858 static void test_combo_changesize(DWORD style)
860 INT ddheight, clheight, ddwidth, clwidth;
861 HWND hCombo;
862 RECT rc;
864 hCombo = create_combobox(style);
866 /* get initial measurements */
867 GetClientRect( hCombo, &rc);
868 clheight = rc.bottom - rc.top;
869 clwidth = rc.right - rc.left;
870 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
871 ddheight = rc.bottom - rc.top;
872 ddwidth = rc.right - rc.left;
873 /* use MoveWindow to move & resize the combo */
874 /* first make it slightly smaller */
875 MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE);
876 GetClientRect( hCombo, &rc);
877 ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n",
878 rc.right - rc.left, clwidth - 2);
879 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
880 rc.bottom - rc.top, clheight);
881 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
882 ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n",
883 rc.right - rc.left, clwidth - 2);
884 ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n",
885 rc.bottom - rc.top, ddheight);
886 ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n",
887 rc.right - rc.left, ddwidth - 2);
888 /* new cx, cy is slightly bigger than the initial values */
889 MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE);
890 GetClientRect( hCombo, &rc);
891 ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n",
892 rc.right - rc.left, clwidth + 2);
893 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
894 rc.bottom - rc.top, clheight);
895 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
896 ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n",
897 rc.right - rc.left, clwidth + 2);
898 todo_wine {
899 ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n",
900 rc.bottom - rc.top, clheight + 2);
903 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0);
904 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
905 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
906 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
908 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
909 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
910 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
911 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
913 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0);
914 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
915 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
916 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
918 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0);
919 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
920 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
921 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
923 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
924 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
925 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
926 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
928 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0);
929 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
930 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
931 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
933 DestroyWindow(hCombo);
936 static void test_combo_editselection(void)
938 COMBOBOXINFO cbInfo;
939 INT start, end;
940 char edit[20];
941 HWND hCombo;
942 HWND hEdit;
943 DWORD len;
945 /* Build a combo */
946 hCombo = create_combobox(CBS_SIMPLE);
948 get_combobox_info(hCombo, &cbInfo);
949 hEdit = cbInfo.hwndItem;
951 /* Initially combo selection is empty*/
952 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
953 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
954 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
956 /* Set some text, and press a key to replace it */
957 edit[0] = 0x00;
958 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1");
959 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
960 ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit);
962 /* Now what is the selection - still empty */
963 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
964 ok(start==0, "Unexpected start position for selection %d\n", start);
965 ok(end==0, "Unexpected end position for selection %d\n", end);
966 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
967 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
968 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
970 /* Give it focus, and it gets selected */
971 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
972 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
973 ok(start==0, "Unexpected start position for selection %d\n", start);
974 ok(end==6, "Unexpected end position for selection %d\n", end);
975 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
976 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
977 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
979 /* Now emulate a key press */
980 edit[0] = 0x00;
981 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
982 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
983 ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit);
985 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
986 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
987 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
989 /* Now what happens when it gets more focus a second time - it doesn't reselect */
990 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
991 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
992 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
993 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
994 DestroyWindow(hCombo);
996 /* Start again - Build a combo */
997 hCombo = create_combobox(CBS_SIMPLE);
998 get_combobox_info(hCombo, &cbInfo);
999 hEdit = cbInfo.hwndItem;
1001 /* Set some text and give focus so it gets selected */
1002 edit[0] = 0x00;
1003 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2");
1004 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
1005 ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit);
1007 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
1009 /* Now what is the selection */
1010 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
1011 ok(start==0, "Unexpected start position for selection %d\n", start);
1012 ok(end==6, "Unexpected end position for selection %d\n", end);
1013 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0);
1014 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
1015 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
1017 /* Now change the selection to the apparently invalid start -1, end -1 and
1018 show it means no selection (ie start -1) but cursor at end */
1019 SendMessageA(hCombo, CB_SETEDITSEL, 0, -1);
1020 edit[0] = 0x00;
1021 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001);
1022 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
1023 ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit);
1024 DestroyWindow(hCombo);
1027 static WNDPROC edit_window_proc;
1028 static long setsel_start = 1, setsel_end = 1;
1029 static HWND hCBN_SetFocus, hCBN_KillFocus;
1031 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1033 if (msg == EM_SETSEL)
1035 setsel_start = wParam;
1036 setsel_end = lParam;
1038 return CallWindowProcA(edit_window_proc, hwnd, msg, wParam, lParam);
1041 static LRESULT CALLBACK test_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1043 switch (msg)
1045 case WM_COMMAND:
1046 switch (HIWORD(wParam))
1048 case CBN_SETFOCUS:
1049 hCBN_SetFocus = (HWND)lParam;
1050 break;
1051 case CBN_KILLFOCUS:
1052 hCBN_KillFocus = (HWND)lParam;
1053 break;
1055 break;
1056 case WM_NEXTDLGCTL:
1057 SetFocus((HWND)wParam);
1058 break;
1060 return CallWindowProcA(old_parent_proc, hwnd, msg, wParam, lParam);
1063 static void test_combo_editselection_focus(DWORD style)
1065 static const char wine_test[] = "Wine Test";
1066 HWND hCombo, hEdit, hButton;
1067 char buffer[16] = {0};
1068 COMBOBOXINFO cbInfo;
1069 DWORD len;
1071 hCombo = create_combobox(style);
1072 get_combobox_info(hCombo, &cbInfo);
1073 hEdit = cbInfo.hwndItem;
1075 hButton = CreateWindowA(WC_BUTTONA, "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,
1076 5, 50, 100, 20, hMainWnd, NULL,
1077 (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL);
1079 old_parent_proc = (WNDPROC)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)test_window_proc);
1080 edit_window_proc = (WNDPROC)SetWindowLongPtrA(hEdit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
1082 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
1083 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
1084 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
1085 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
1086 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
1088 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
1089 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
1090 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
1091 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
1092 ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
1094 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)wine_test);
1095 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hCombo, TRUE);
1096 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
1097 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
1098 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus);
1099 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n");
1100 SendMessageA(hCombo, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
1101 ok(!strcmp(buffer, wine_test), "Unexpected text in edit control; got '%s'\n", buffer);
1103 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE);
1104 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start);
1105 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end);
1106 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus);
1107 ok(GetFocus() == hButton, "hButton should have keyboard focus\n");
1108 len = SendMessageA(hCombo, CB_GETEDITSEL, 0, 0);
1109 ok(len == 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len), HIWORD(len));
1111 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
1112 DestroyWindow(hButton);
1113 DestroyWindow(hCombo);
1116 static void test_combo_listbox_styles(DWORD cb_style)
1118 DWORD style, exstyle, expect_style, expect_exstyle;
1119 COMBOBOXINFO info;
1120 HWND combo;
1122 expect_style = WS_CHILD|WS_CLIPSIBLINGS|LBS_COMBOBOX|LBS_HASSTRINGS|LBS_NOTIFY;
1123 if (cb_style == CBS_SIMPLE)
1125 expect_style |= WS_VISIBLE;
1126 expect_exstyle = WS_EX_CLIENTEDGE;
1128 else
1130 expect_style |= WS_BORDER;
1131 expect_exstyle = WS_EX_TOOLWINDOW;
1134 combo = create_combobox(cb_style);
1135 get_combobox_info(combo, &info);
1137 style = GetWindowLongW( info.hwndList, GWL_STYLE );
1138 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
1139 ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
1140 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
1142 if (cb_style != CBS_SIMPLE)
1143 expect_exstyle |= WS_EX_TOPMOST;
1145 SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 );
1146 style = GetWindowLongW( info.hwndList, GWL_STYLE );
1147 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
1148 ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style);
1149 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
1151 SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 );
1152 style = GetWindowLongW( info.hwndList, GWL_STYLE );
1153 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE );
1154 ok(style == expect_style, "%08x: got %08x\n", cb_style, style);
1155 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle);
1157 DestroyWindow(combo);
1160 static void test_combo_WS_VSCROLL(void)
1162 HWND hCombo, hList;
1163 COMBOBOXINFO info;
1164 DWORD style;
1165 int i;
1167 hCombo = create_combobox(CBS_DROPDOWNLIST);
1169 get_combobox_info(hCombo, &info);
1170 hList = info.hwndList;
1172 for (i = 0; i < 3; i++)
1174 char buffer[2];
1175 sprintf(buffer, "%d", i);
1176 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer);
1179 style = GetWindowLongA(info.hwndList, GWL_STYLE);
1180 SetWindowLongA(hList, GWL_STYLE, style | WS_VSCROLL);
1182 SendMessageA(hCombo, CB_SHOWDROPDOWN, TRUE, 0);
1183 SendMessageA(hCombo, CB_SHOWDROPDOWN, FALSE, 0);
1185 style = GetWindowLongA(hList, GWL_STYLE);
1186 ok((style & WS_VSCROLL) != 0, "Style does not include WS_VSCROLL\n");
1188 DestroyWindow(hCombo);
1191 static void test_combo_dropdown_size(DWORD style)
1193 static const char wine_test[] = "Wine Test";
1194 HWND hCombo, hList;
1195 COMBOBOXINFO cbInfo;
1196 int i, test, ret;
1198 static const struct list_size_info
1200 int num_items;
1201 int height_combo;
1202 int limit;
1203 } info_height[] = {
1204 {33, 50, -1},
1205 {35, 100, 40},
1206 {15, 50, 3},
1209 for (test = 0; test < ARRAY_SIZE(info_height); test++)
1211 const struct list_size_info *info_test = &info_height[test];
1212 int height_item; /* Height of a list item */
1213 int height_list; /* Height of the list we got */
1214 int expected_height_list;
1215 RECT rect_list_client;
1216 int min_visible_expected;
1218 hCombo = CreateWindowA(WC_COMBOBOXA, "Combo", CBS_DROPDOWN | WS_VISIBLE | WS_CHILD | style, 5, 5, 100,
1219 info_test->height_combo, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
1221 min_visible_expected = SendMessageA(hCombo, CB_GETMINVISIBLE, 0, 0);
1222 ok(min_visible_expected == 30, "Unexpected number of items %d.\n", min_visible_expected);
1224 cbInfo.cbSize = sizeof(COMBOBOXINFO);
1225 ret = SendMessageA(hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbInfo);
1226 ok(ret, "Failed to get combo info, %d\n", ret);
1228 hList = cbInfo.hwndList;
1229 for (i = 0; i < info_test->num_items; i++)
1231 ret = SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM) wine_test);
1232 ok(ret == i, "Failed to add string %d, returned %d.\n", i, ret);
1235 if (info_test->limit != -1)
1237 int min_visible_actual;
1238 min_visible_expected = info_test->limit;
1240 ret = SendMessageA(hCombo, CB_SETMINVISIBLE, min_visible_expected, 0);
1241 ok(ret, "Failed to set visible limit.\n");
1242 min_visible_actual = SendMessageA(hCombo, CB_GETMINVISIBLE, 0, 0);
1243 ok(min_visible_expected == min_visible_actual, "test %d: unexpected number of items %d.\n",
1244 test, min_visible_actual);
1247 ret = SendMessageA(hCombo, CB_SHOWDROPDOWN, TRUE,0);
1248 ok(ret, "Failed to show dropdown.\n");
1249 ret = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
1250 ok(ret, "Unexpected dropped state.\n");
1252 GetClientRect(hList, &rect_list_client);
1253 height_list = rect_list_client.bottom - rect_list_client.top;
1254 height_item = (int)SendMessageA(hList, LB_GETITEMHEIGHT, 0, 0);
1256 if (style & CBS_NOINTEGRALHEIGHT)
1258 RECT rect_list_complete;
1259 int list_height_nonclient;
1260 int list_height_calculated;
1261 int edit_padding_size = cbInfo.rcItem.top; /* edit client rect top is the padding it has to its parent
1262 We assume it's the same on the bottom */
1264 GetWindowRect(hList, &rect_list_complete);
1266 list_height_nonclient = (rect_list_complete.bottom - rect_list_complete.top)
1267 - (rect_list_client.bottom - rect_list_client.top);
1269 /* Calculate the expected client size of the listbox popup from the size of the combobox. */
1270 list_height_calculated = info_test->height_combo /* Take height we created combobox with */
1271 - (cbInfo.rcItem.bottom - cbInfo.rcItem.top) /* Subtract size of edit control */
1272 - list_height_nonclient /* Subtract list nonclient area */
1273 - edit_padding_size * 2; /* subtract space around the edit control */
1275 expected_height_list = min(list_height_calculated, height_item * info_test->num_items);
1276 if (expected_height_list < 0)
1277 expected_height_list = 0;
1279 ok(expected_height_list == height_list, "Test %d, expected list height to be %d, got %d\n",
1280 test, expected_height_list, height_list);
1282 else
1284 expected_height_list = min(info_test->num_items, min_visible_expected) * height_item;
1286 ok(expected_height_list == height_list, "Test %d, expected list height to be %d, got %d\n",
1287 test, expected_height_list, height_list);
1290 DestroyWindow(hCombo);
1294 static void test_combo_ctlcolor(void)
1296 static const int messages[] =
1298 WM_CTLCOLOR,
1299 WM_CTLCOLORMSGBOX,
1300 WM_CTLCOLOREDIT,
1301 WM_CTLCOLORLISTBOX,
1302 WM_CTLCOLORBTN,
1303 WM_CTLCOLORDLG,
1304 WM_CTLCOLORSCROLLBAR,
1305 WM_CTLCOLORSTATIC,
1308 HBRUSH brush, global_brush;
1309 COMBOBOXINFO info;
1310 unsigned int i;
1311 HWND combo;
1313 combo = create_combobox(CBS_DROPDOWN);
1314 ok(!!combo, "Failed to create combo window.\n");
1316 old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
1318 get_combobox_info(combo, &info);
1320 lparam_for_WM_CTLCOLOR = info.hwndItem;
1322 /* Parent returns valid brush handle. */
1323 for (i = 0; i < ARRAY_SIZE(messages); ++i)
1325 brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem);
1326 ok(brush == brush_red, "%u: unexpected brush %p, expected got %p.\n", i, brush, brush_red);
1329 /* Parent returns NULL brush. */
1330 global_brush = brush_red;
1331 brush_red = NULL;
1333 for (i = 0; i < ARRAY_SIZE(messages); ++i)
1335 brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem);
1336 ok(!brush, "%u: unexpected brush %p.\n", i, brush);
1339 brush_red = global_brush;
1341 lparam_for_WM_CTLCOLOR = 0;
1343 /* Parent does default processing. */
1344 for (i = 0; i < ARRAY_SIZE(messages); ++i)
1346 brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem);
1347 ok(!!brush && brush != brush_red, "%u: unexpected brush %p.\n", i, brush);
1350 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
1351 DestroyWindow(combo);
1353 /* Combo without a parent. */
1354 combo = CreateWindowA(WC_COMBOBOXA, "Combo", CBS_DROPDOWN, 5, 5, 100, 100, NULL, NULL, NULL, 0);
1355 ok(!!combo, "Failed to create combo window.\n");
1357 get_combobox_info(combo, &info);
1359 for (i = 0; i < ARRAY_SIZE(messages); ++i)
1361 brush = (HBRUSH)SendMessageA(combo, messages[i], 0, (LPARAM)info.hwndItem);
1362 ok(!brush, "%u: unexpected brush %p.\n", i, brush);
1365 DestroyWindow(combo);
1368 START_TEST(combo)
1370 ULONG_PTR ctx_cookie;
1371 HANDLE hCtx;
1373 init_functions();
1375 if (!init())
1376 return;
1378 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1380 /* ComboBoxEx32 tests. */
1381 test_comboex();
1382 test_comboex_WM_LBUTTONDOWN();
1383 test_comboex_CB_GETLBTEXT();
1384 test_comboex_WM_WINDOWPOSCHANGING();
1385 test_comboex_subclass();
1386 test_comboex_get_set_item();
1388 if (!load_v6_module(&ctx_cookie, &hCtx))
1390 cleanup();
1391 return;
1394 /* ComboBox control tests. */
1395 test_combo_WS_VSCROLL();
1396 test_combo_setfont(CBS_DROPDOWN);
1397 test_combo_setfont(CBS_DROPDOWNLIST);
1398 test_combo_setitemheight(CBS_DROPDOWN);
1399 test_combo_setitemheight(CBS_DROPDOWNLIST);
1400 test_combo_CBN_SELCHANGE();
1401 test_combo_changesize(CBS_DROPDOWN);
1402 test_combo_changesize(CBS_DROPDOWNLIST);
1403 test_combo_editselection();
1404 test_combo_editselection_focus(CBS_SIMPLE);
1405 test_combo_editselection_focus(CBS_DROPDOWN);
1406 test_combo_listbox_styles(CBS_SIMPLE);
1407 test_combo_listbox_styles(CBS_DROPDOWN);
1408 test_combo_listbox_styles(CBS_DROPDOWNLIST);
1409 test_combo_dropdown_size(0);
1410 test_combo_dropdown_size(CBS_NOINTEGRALHEIGHT);
1411 test_combo_ctlcolor();
1413 cleanup();
1414 unload_v6_module(ctx_cookie, hCtx);