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
26 #include "wine/test.h"
30 #define EDITBOX_SEQ_INDEX 0
31 #define NUM_MSG_SEQUENCES 1
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 BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
52 static char *textBuffer
= NULL
;
54 static BOOL received_end_edit
= FALSE
;
56 static void get_combobox_info(HWND hwnd
, COMBOBOXINFO
*info
)
60 info
->cbSize
= sizeof(*info
);
61 ret
= GetComboBoxInfo(hwnd
, info
);
62 ok(ret
, "Failed to get combobox info structure, error %d\n", GetLastError());
65 static HWND
createComboEx(DWORD style
) {
66 return CreateWindowExA(0, WC_COMBOBOXEXA
, NULL
, style
, 0, 0, 300, 300,
67 hComboExParentWnd
, NULL
, hMainHinst
, NULL
);
70 static LONG
addItem(HWND cbex
, int idx
, const char *text
) {
71 COMBOBOXEXITEMA cbexItem
;
72 memset(&cbexItem
, 0x00, sizeof(cbexItem
));
73 cbexItem
.mask
= CBEIF_TEXT
;
75 cbexItem
.pszText
= (char*)text
;
76 cbexItem
.cchTextMax
= 0;
77 return SendMessageA(cbex
, CBEM_INSERTITEMA
, 0, (LPARAM
)&cbexItem
);
80 static LONG
setItem(HWND cbex
, int idx
, const char *text
) {
81 COMBOBOXEXITEMA cbexItem
;
82 memset(&cbexItem
, 0x00, sizeof(cbexItem
));
83 cbexItem
.mask
= CBEIF_TEXT
;
85 cbexItem
.pszText
= (char*)text
;
86 cbexItem
.cchTextMax
= 0;
87 return SendMessageA(cbex
, CBEM_SETITEMA
, 0, (LPARAM
)&cbexItem
);
90 static LONG
delItem(HWND cbex
, int idx
) {
91 return SendMessageA(cbex
, CBEM_DELETEITEM
, idx
, 0);
94 static LONG
getItem(HWND cbex
, int idx
, COMBOBOXEXITEMA
*cbItem
) {
95 memset(cbItem
, 0x00, sizeof(COMBOBOXEXITEMA
));
96 cbItem
->mask
= CBEIF_TEXT
;
97 cbItem
->pszText
= textBuffer
;
99 cbItem
->cchTextMax
= 100;
100 return SendMessageA(cbex
, CBEM_GETITEMA
, 0, (LPARAM
)cbItem
);
103 static LRESULT WINAPI
editbox_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
105 WNDPROC oldproc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
106 static LONG defwndproc_counter
= 0;
107 struct message msg
= { 0 };
110 msg
.message
= message
;
111 msg
.flags
= sent
|wparam
|lparam
;
112 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
117 if (message
!= WM_PAINT
&&
118 message
!= WM_ERASEBKGND
&&
119 message
!= WM_NCPAINT
&&
120 message
!= WM_NCHITTEST
&&
121 message
!= WM_GETTEXT
&&
122 message
!= WM_GETICON
&&
123 message
!= WM_DEVICECHANGE
)
125 add_message(sequences
, EDITBOX_SEQ_INDEX
, &msg
);
128 defwndproc_counter
++;
129 ret
= CallWindowProcA(oldproc
, hwnd
, message
, wParam
, lParam
);
130 defwndproc_counter
--;
134 static HWND
subclass_editbox(HWND hwndComboEx
)
139 hwnd
= (HWND
)SendMessageA(hwndComboEx
, CBEM_GETEDITCONTROL
, 0, 0);
140 oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
141 (LONG_PTR
)editbox_subclass_proc
);
142 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)oldproc
);
147 static void test_comboex(void)
151 COMBOBOXEXITEMA cbexItem
;
152 static const char *first_item
= "First Item",
153 *second_item
= "Second Item",
154 *third_item
= "Third Item",
155 *middle_item
= "Between First and Second Items",
156 *replacement_item
= "Between First and Second Items",
157 *out_of_range_item
= "Out of Range Item";
159 /* Allocate space for result */
160 textBuffer
= heap_alloc(MAX_CHARS
);
162 /* Basic comboboxex test */
163 myHwnd
= createComboEx(WS_BORDER
| WS_VISIBLE
| WS_CHILD
| CBS_DROPDOWN
);
165 /* Add items onto the end of the combobox */
166 res
= addItem(myHwnd
, -1, first_item
);
167 ok(res
== 0, "Adding simple item failed (%d)\n", res
);
168 res
= addItem(myHwnd
, -1, second_item
);
169 ok(res
== 1, "Adding simple item failed (%d)\n", res
);
170 res
= addItem(myHwnd
, 2, third_item
);
171 ok(res
== 2, "Adding simple item failed (%d)\n", res
);
172 res
= addItem(myHwnd
, 1, middle_item
);
173 ok(res
== 1, "Inserting simple item failed (%d)\n", res
);
175 /* Add an item completely out of range */
176 res
= addItem(myHwnd
, 99, out_of_range_item
);
177 ok(res
== -1, "Adding using out of range index worked unexpectedly (%d)\n", res
);
178 res
= addItem(myHwnd
, 5, out_of_range_item
);
179 ok(res
== -1, "Adding using out of range index worked unexpectedly (%d)\n", res
);
180 /* Removed: Causes traps on Windows XP
181 res = addItem(myHwnd, -2, "Out Of Range Item");
182 ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
185 /* Get an item completely out of range */
186 res
= getItem(myHwnd
, 99, &cbexItem
);
187 ok(res
== 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res
, cbexItem
.pszText
);
188 res
= getItem(myHwnd
, 4, &cbexItem
);
189 ok(res
== 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res
, cbexItem
.pszText
);
190 res
= getItem(myHwnd
, -2, &cbexItem
);
191 ok(res
== 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res
, cbexItem
.pszText
);
193 /* Get an item in range */
194 res
= getItem(myHwnd
, 0, &cbexItem
);
195 ok(res
!= 0, "Getting item using valid index failed unexpectedly (%d)\n", res
);
196 ok(strcmp(first_item
, cbexItem
.pszText
) == 0, "Getting item returned wrong string (%s)\n", cbexItem
.pszText
);
198 res
= getItem(myHwnd
, 1, &cbexItem
);
199 ok(res
!= 0, "Getting item using valid index failed unexpectedly (%d)\n", res
);
200 ok(strcmp(middle_item
, cbexItem
.pszText
) == 0, "Getting item returned wrong string (%s)\n", cbexItem
.pszText
);
202 res
= getItem(myHwnd
, 2, &cbexItem
);
203 ok(res
!= 0, "Getting item using valid index failed unexpectedly (%d)\n", res
);
204 ok(strcmp(second_item
, cbexItem
.pszText
) == 0, "Getting item returned wrong string (%s)\n", cbexItem
.pszText
);
206 res
= getItem(myHwnd
, 3, &cbexItem
);
207 ok(res
!= 0, "Getting item using valid index failed unexpectedly (%d)\n", res
);
208 ok(strcmp(third_item
, cbexItem
.pszText
) == 0, "Getting item returned wrong string (%s)\n", cbexItem
.pszText
);
210 /* Set an item completely out of range */
211 res
= setItem(myHwnd
, 99, replacement_item
);
212 ok(res
== 0, "Setting item using out of range index worked unexpectedly (%d)\n", res
);
213 res
= setItem(myHwnd
, 4, replacement_item
);
214 ok(res
== 0, "Setting item using out of range index worked unexpectedly (%d)\n", res
);
215 res
= setItem(myHwnd
, -2, replacement_item
);
216 ok(res
== 0, "Setting item using out of range index worked unexpectedly (%d)\n", res
);
218 /* Set an item in range */
219 res
= setItem(myHwnd
, 0, replacement_item
);
220 ok(res
!= 0, "Setting first item failed (%d)\n", res
);
221 res
= setItem(myHwnd
, 3, replacement_item
);
222 ok(res
!= 0, "Setting last item failed (%d)\n", res
);
224 /* Remove items completely out of range (4 items in control at this point) */
225 res
= delItem(myHwnd
, -1);
226 ok(res
== CB_ERR
, "Deleting using out of range index worked unexpectedly (%d)\n", res
);
227 res
= delItem(myHwnd
, 4);
228 ok(res
== CB_ERR
, "Deleting using out of range index worked unexpectedly (%d)\n", res
);
230 /* Remove items in range (4 items in control at this point) */
231 res
= delItem(myHwnd
, 3);
232 ok(res
== 3, "Deleting using out of range index failed (%d)\n", res
);
233 res
= delItem(myHwnd
, 0);
234 ok(res
== 2, "Deleting using out of range index failed (%d)\n", res
);
235 res
= delItem(myHwnd
, 0);
236 ok(res
== 1, "Deleting using out of range index failed (%d)\n", res
);
237 res
= delItem(myHwnd
, 0);
238 ok(res
== 0, "Deleting using out of range index failed (%d)\n", res
);
240 /* Remove from an empty box */
241 res
= delItem(myHwnd
, 0);
242 ok(res
== CB_ERR
, "Deleting using out of range index worked unexpectedly (%d)\n", res
);
246 heap_free(textBuffer
);
247 DestroyWindow(myHwnd
);
250 static void test_comboex_WM_LBUTTONDOWN(void)
252 HWND hComboEx
, hCombo
, hEdit
, hList
;
254 UINT x
, y
, item_height
;
260 static const UINT choices
[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
261 static const WCHAR stringFormat
[] = {'%','2','d','\0'};
263 hComboEx
= CreateWindowExA(0, WC_COMBOBOXEXA
, NULL
,
264 WS_VISIBLE
|WS_CHILD
|CBS_DROPDOWN
, 0, 0, 200, 150,
265 hComboExParentWnd
, NULL
, hMainHinst
, NULL
);
267 for (i
= 0; i
< sizeof(choices
)/sizeof(UINT
); i
++){
268 COMBOBOXEXITEMW cbexItem
;
269 wsprintfW(buffer
, stringFormat
, choices
[i
]);
271 memset(&cbexItem
, 0x00, sizeof(cbexItem
));
272 cbexItem
.mask
= CBEIF_TEXT
;
274 cbexItem
.pszText
= buffer
;
275 cbexItem
.cchTextMax
= 0;
276 ok(SendMessageW(hComboEx
, CBEM_INSERTITEMW
, 0, (LPARAM
)&cbexItem
) >= 0,
277 "Failed to add item %d\n", i
);
280 hCombo
= (HWND
)SendMessageA(hComboEx
, CBEM_GETCOMBOCONTROL
, 0, 0);
281 hEdit
= (HWND
)SendMessageA(hComboEx
, CBEM_GETEDITCONTROL
, 0, 0);
283 get_combobox_info(hCombo
, &cbInfo
);
284 hList
= cbInfo
.hwndList
;
286 ok(GetFocus() == hComboExParentWnd
,
287 "Focus not on Main Window, instead on %p\n", GetFocus());
289 /* Click on the button to drop down the list */
290 x
= cbInfo
.rcButton
.left
+ (cbInfo
.rcButton
.right
-cbInfo
.rcButton
.left
)/2;
291 y
= cbInfo
.rcButton
.top
+ (cbInfo
.rcButton
.bottom
-cbInfo
.rcButton
.top
)/2;
292 result
= SendMessageA(hCombo
, WM_LBUTTONDOWN
, 0, MAKELPARAM(x
, y
));
293 ok(result
, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
295 ok(GetFocus() == hCombo
||
296 broken(GetFocus() != hCombo
), /* win98 */
297 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
299 ok(SendMessageA(hComboEx
, CB_GETDROPPEDSTATE
, 0, 0),
300 "The dropdown list should have appeared after clicking the button.\n");
301 idx
= SendMessageA(hCombo
, CB_GETTOPINDEX
, 0, 0);
302 ok(idx
== 0, "For TopIndex expected %d, got %d\n", 0, idx
);
304 result
= SendMessageA(hCombo
, WM_LBUTTONUP
, 0, MAKELPARAM(x
, y
));
305 ok(result
, "WM_LBUTTONUP was not processed. LastError=%d\n",
307 ok(GetFocus() == hCombo
||
308 broken(GetFocus() != hCombo
), /* win98 */
309 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
312 /* Click on the 5th item in the list */
313 item_height
= SendMessageA(hCombo
, CB_GETITEMHEIGHT
, 0, 0);
314 ok(GetClientRect(hList
, &rect
), "Failed to get list's client rect.\n");
315 x
= rect
.left
+ (rect
.right
-rect
.left
)/2;
316 y
= item_height
/2 + item_height
*4;
317 result
= SendMessageA(hList
, WM_MOUSEMOVE
, 0, MAKELPARAM(x
, y
));
318 ok(!result
, "WM_MOUSEMOVE was not processed. LastError=%d\n",
320 ok(GetFocus() == hCombo
||
321 broken(GetFocus() != hCombo
), /* win98 */
322 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
325 result
= SendMessageA(hList
, WM_LBUTTONDOWN
, 0, MAKELPARAM(x
, y
));
326 ok(!result
, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
328 ok(GetFocus() == hCombo
||
329 broken(GetFocus() != hCombo
), /* win98 */
330 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n",
332 ok(SendMessageA(hComboEx
, CB_GETDROPPEDSTATE
, 0, 0),
333 "The dropdown list should still be visible.\n");
335 result
= SendMessageA(hList
, WM_LBUTTONUP
, 0, MAKELPARAM(x
, y
));
336 ok(!result
, "WM_LBUTTONUP was not processed. LastError=%d\n",
338 todo_wine
ok(GetFocus() == hEdit
||
339 broken(GetFocus() == hCombo
), /* win98 */
340 "Focus not on ComboBoxEx's Edit Control, instead on %p\n",
343 result
= SendMessageA(hCombo
, CB_GETDROPPEDSTATE
, 0, 0);
345 broken(result
!= 0), /* win98 */
346 "The dropdown list should have been rolled up.\n");
347 idx
= SendMessageA(hComboEx
, CB_GETCURSEL
, 0, 0);
349 broken(idx
== -1), /* win98 */
350 "Current Selection: expected %d, got %d\n", 4, idx
);
351 ok(received_end_edit
, "Expected to receive a CBEN_ENDEDIT message\n");
353 SetFocus( hComboExParentWnd
);
354 ok( GetFocus() == hComboExParentWnd
, "got %p\n", GetFocus() );
355 SetFocus( hComboEx
);
356 ok( GetFocus() == hEdit
, "got %p\n", GetFocus() );
358 DestroyWindow(hComboEx
);
361 static void test_comboex_CB_GETLBTEXT(void)
365 COMBOBOXEXITEMA item
;
368 hCombo
= createComboEx(WS_BORDER
| WS_VISIBLE
| WS_CHILD
| CBS_DROPDOWN
);
370 /* set text to null */
371 addItem(hCombo
, 0, NULL
);
374 item
.mask
= CBEIF_TEXT
;
378 ret
= SendMessageA(hCombo
, CBEM_GETITEMA
, 0, (LPARAM
)&item
);
379 ok(ret
!= 0, "CBEM_GETITEM failed\n");
380 ok(buff
[0] == 0, "\n");
382 ret
= SendMessageA(hCombo
, CB_GETLBTEXTLEN
, 0, 0);
383 ok(ret
== 0, "Expected zero length\n");
385 ret
= SendMessageA(hCombo
, CB_GETLBTEXTLEN
, 0, 0);
386 ok(ret
== 0, "Expected zero length\n");
389 ret
= SendMessageA(hCombo
, CB_GETLBTEXT
, 0, (LPARAM
)buff
);
390 ok(ret
== 0, "Expected zero length\n");
391 ok(buff
[0] == 0, "Expected null terminator as a string, got %s\n", buff
);
393 DestroyWindow(hCombo
);
396 static void test_comboex_WM_WINDOWPOSCHANGING(void)
404 hCombo
= createComboEx(WS_BORDER
| WS_VISIBLE
| WS_CHILD
| CBS_DROPDOWN
);
405 ok(hCombo
!= NULL
, "createComboEx failed\n");
406 ret
= GetWindowRect(hCombo
, &rect
);
407 ok(ret
, "GetWindowRect failed\n");
408 combo_height
= rect
.bottom
- rect
.top
;
409 ok(combo_height
> 0, "wrong combo height\n");
411 /* Test height > combo_height */
414 wp
.cx
= (rect
.right
- rect
.left
);
415 wp
.cy
= combo_height
* 2;
418 wp
.hwndInsertAfter
= NULL
;
420 ret
= SendMessageA(hCombo
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&wp
);
421 ok(ret
== 0, "expected 0, got %x\n", ret
);
422 ok(wp
.cy
== combo_height
,
423 "Expected height %d, got %d\n", combo_height
, wp
.cy
);
425 /* Test height < combo_height */
428 wp
.cx
= (rect
.right
- rect
.left
);
429 wp
.cy
= combo_height
/ 2;
432 wp
.hwndInsertAfter
= NULL
;
434 ret
= SendMessageA(hCombo
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&wp
);
435 ok(ret
== 0, "expected 0, got %x\n", ret
);
436 ok(wp
.cy
== combo_height
,
437 "Expected height %d, got %d\n", combo_height
, wp
.cy
);
439 ret
= DestroyWindow(hCombo
);
440 ok(ret
, "DestroyWindow failed\n");
443 static LRESULT
ComboExTestOnNotify(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
445 NMHDR
*hdr
= (NMHDR
*)lParam
;
449 NMCBEENDEDITA
*edit_info
= (NMCBEENDEDITA
*)hdr
;
450 if(edit_info
->iWhy
==CBENF_DROPDOWN
){
451 received_end_edit
= TRUE
;
457 NMCBEENDEDITW
*edit_info
= (NMCBEENDEDITW
*)hdr
;
458 if(edit_info
->iWhy
==CBENF_DROPDOWN
){
459 received_end_edit
= TRUE
;
467 static LRESULT CALLBACK
ComboExTestWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
475 return ComboExTestOnNotify(hWnd
,msg
,wParam
,lParam
);
477 return DefWindowProcA(hWnd
, msg
, wParam
, lParam
);
483 static void init_functions(void)
485 HMODULE hComCtl32
= LoadLibraryA("comctl32.dll");
487 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
488 #define X2(f, ord) p##f = (void*)GetProcAddress(hComCtl32, (const char *)ord);
489 X2(SetWindowSubclass
, 410);
494 static BOOL
init(void)
498 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
501 wc
.hInstance
= GetModuleHandleA(NULL
);
503 wc
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
504 wc
.hbrBackground
= GetSysColorBrush(COLOR_WINDOW
);
505 wc
.lpszMenuName
= NULL
;
506 wc
.lpszClassName
= ComboExTestClass
;
507 wc
.lpfnWndProc
= ComboExTestWndProc
;
510 hMainWnd
= CreateWindowA(WC_STATICA
, "Test", WS_OVERLAPPEDWINDOW
, 10, 10, 300, 300, NULL
, NULL
, NULL
, 0);
511 ShowWindow(hMainWnd
, SW_SHOW
);
513 hComboExParentWnd
= CreateWindowExA(0, ComboExTestClass
, "ComboEx test", WS_OVERLAPPEDWINDOW
|WS_VISIBLE
,
514 CW_USEDEFAULT
, CW_USEDEFAULT
, 680, 260, NULL
, NULL
, GetModuleHandleA(NULL
), 0);
515 ok(hComboExParentWnd
!= NULL
, "failed to create parent window\n");
517 hMainHinst
= GetModuleHandleA(NULL
);
519 return hComboExParentWnd
!= NULL
;
522 static void cleanup(void)
526 PostMessageA(hComboExParentWnd
, WM_CLOSE
, 0, 0);
527 while (GetMessageA(&msg
,0,0,0)) {
528 TranslateMessage(&msg
);
529 DispatchMessageA(&msg
);
532 DestroyWindow(hComboExParentWnd
);
533 UnregisterClassA(ComboExTestClass
, GetModuleHandleA(NULL
));
535 DestroyWindow(hMainWnd
);
538 static void test_comboex_subclass(void)
540 HWND hComboEx
, hCombo
, hEdit
;
542 hComboEx
= createComboEx(WS_BORDER
| WS_VISIBLE
| WS_CHILD
| CBS_DROPDOWN
);
544 hCombo
= (HWND
)SendMessageA(hComboEx
, CBEM_GETCOMBOCONTROL
, 0, 0);
545 ok(hCombo
!= NULL
, "Failed to get internal combo\n");
546 hEdit
= (HWND
)SendMessageA(hComboEx
, CBEM_GETEDITCONTROL
, 0, 0);
547 ok(hEdit
!= NULL
, "Failed to get internal edit\n");
549 if (pSetWindowSubclass
)
551 ok(GetPropA(hCombo
, "CC32SubclassInfo") != NULL
, "Expected CC32SubclassInfo property\n");
552 ok(GetPropA(hEdit
, "CC32SubclassInfo") != NULL
, "Expected CC32SubclassInfo property\n");
555 DestroyWindow(hComboEx
);
558 static const struct message test_setitem_edit_seq
[] = {
559 { WM_SETTEXT
, sent
|id
, 0, 0, EDITBOX_ID
},
560 { EM_SETSEL
, sent
|id
|wparam
|lparam
, 0, 0, EDITBOX_ID
},
561 { EM_SETSEL
, sent
|id
|wparam
|lparam
, 0, -1, EDITBOX_ID
},
565 static void test_comboex_get_set_item(void)
567 char textA
[] = "test";
569 COMBOBOXEXITEMA item
;
572 hComboEx
= createComboEx(WS_BORDER
| WS_VISIBLE
| WS_CHILD
| CBS_DROPDOWN
);
574 subclass_editbox(hComboEx
);
576 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
578 memset(&item
, 0, sizeof(item
));
579 item
.mask
= CBEIF_TEXT
;
580 item
.pszText
= textA
;
582 ret
= SendMessageA(hComboEx
, CBEM_SETITEMA
, 0, (LPARAM
)&item
);
585 ok_sequence(sequences
, EDITBOX_SEQ_INDEX
, test_setitem_edit_seq
, "set item data for edit", FALSE
);
588 item
.mask
= CBEIF_LPARAM
;
590 item
.lParam
= 0xdeadbeef;
591 ret
= SendMessageA(hComboEx
, CBEM_GETITEMA
, 0, (LPARAM
)&item
);
593 ok(item
.lParam
== 0, "Expected zero, got %lx\n", item
.lParam
);
595 item
.lParam
= 0x1abe11ed;
596 ret
= SendMessageA(hComboEx
, CBEM_SETITEMA
, 0, (LPARAM
)&item
);
600 ret
= SendMessageA(hComboEx
, CBEM_GETITEMA
, 0, (LPARAM
)&item
);
602 ok(item
.lParam
== 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item
.lParam
);
604 DestroyWindow(hComboEx
);
607 static HWND
create_combobox(DWORD style
)
609 return CreateWindowA(WC_COMBOBOXA
, "Combo", WS_VISIBLE
|WS_CHILD
|style
, 5, 5, 100, 100, hMainWnd
, (HMENU
)COMBO_ID
, NULL
, 0);
612 static int font_height(HFONT hFont
)
618 hDC
= CreateCompatibleDC(NULL
);
619 hFontOld
= SelectObject(hDC
, hFont
);
620 GetTextMetricsA(hDC
, &tm
);
621 SelectObject(hDC
, hFontOld
);
627 static void test_combo_setitemheight(DWORD style
)
629 HWND hCombo
= create_combobox(style
);
633 GetClientRect(hCombo
, &r
);
634 expect_rect(r
, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT
)) + 8);
635 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&r
);
636 MapWindowPoints(HWND_DESKTOP
, hMainWnd
, (LPPOINT
)&r
, 2);
637 todo_wine
expect_rect(r
, 5, 5, 105, 105);
639 for (i
= 1; i
< 30; i
++)
641 SendMessageA(hCombo
, CB_SETITEMHEIGHT
, -1, i
);
642 GetClientRect(hCombo
, &r
);
643 ok((r
.bottom
- r
.top
) == (i
+ 6), "Unexpected client rect height.\n");
646 DestroyWindow(hCombo
);
649 static void test_combo_setfont(DWORD style
)
651 HFONT hFont1
, hFont2
;
656 hCombo
= create_combobox(style
);
657 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");
658 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");
660 GetClientRect(hCombo
, &r
);
661 expect_rect(r
, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT
)) + 8);
662 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&r
);
663 MapWindowPoints(HWND_DESKTOP
, hMainWnd
, (LPPOINT
)&r
, 2);
664 todo_wine
expect_rect(r
, 5, 5, 105, 105);
666 /* The size of the dropped control is initially equal to the size
667 of the window when it was created. The size of the calculated
668 dropped area changes only by how much the selection area
669 changes, not by how much the list area changes. */
670 if (font_height(hFont1
) == 10 && font_height(hFont2
) == 8)
672 SendMessageA(hCombo
, WM_SETFONT
, (WPARAM
)hFont1
, FALSE
);
673 GetClientRect(hCombo
, &r
);
674 expect_rect(r
, 0, 0, 100, 18);
675 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&r
);
676 MapWindowPoints(HWND_DESKTOP
, hMainWnd
, (LPPOINT
)&r
, 2);
677 todo_wine
expect_rect(r
, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT
)) - font_height(hFont1
)));
679 SendMessageA(hCombo
, WM_SETFONT
, (WPARAM
)hFont2
, FALSE
);
680 GetClientRect(hCombo
, &r
);
681 expect_rect(r
, 0, 0, 100, 16);
682 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&r
);
683 MapWindowPoints(HWND_DESKTOP
, hMainWnd
, (LPPOINT
)&r
, 2);
684 todo_wine
expect_rect(r
, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT
)) - font_height(hFont2
)));
686 SendMessageA(hCombo
, WM_SETFONT
, (WPARAM
)hFont1
, FALSE
);
687 GetClientRect(hCombo
, &r
);
688 expect_rect(r
, 0, 0, 100, 18);
689 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&r
);
690 MapWindowPoints(HWND_DESKTOP
, hMainWnd
, (LPPOINT
)&r
, 2);
691 todo_wine
expect_rect(r
, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT
)) - font_height(hFont1
)));
695 ok(0, "Expected Marlett font heights 10/8, got %d/%d\n",
696 font_height(hFont1
), font_height(hFont2
));
699 for (i
= 1; i
< 30; i
++)
701 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");
702 int height
= font_height(hFont
);
704 SendMessageA(hCombo
, WM_SETFONT
, (WPARAM
)hFont
, FALSE
);
705 GetClientRect(hCombo
, &r
);
706 ok((r
.bottom
- r
.top
) == (height
+ 8), "Unexpected client rect height.\n");
707 SendMessageA(hCombo
, WM_SETFONT
, 0, FALSE
);
711 DestroyWindow(hCombo
);
712 DeleteObject(hFont1
);
713 DeleteObject(hFont2
);
716 static LRESULT (CALLBACK
*old_parent_proc
)(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
);
717 static LPCSTR expected_edit_text
;
718 static LPCSTR expected_list_text
;
719 static BOOL selchange_fired
;
721 static LRESULT CALLBACK
parent_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
728 case MAKEWPARAM(COMBO_ID
, CBN_SELCHANGE
):
730 HWND hCombo
= (HWND
)lparam
;
731 char list
[20], edit
[20];
734 memset(list
, 0, sizeof(list
));
735 memset(edit
, 0, sizeof(edit
));
737 idx
= SendMessageA(hCombo
, CB_GETCURSEL
, 0, 0);
738 SendMessageA(hCombo
, CB_GETLBTEXT
, idx
, (LPARAM
)list
);
739 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(edit
), (LPARAM
)edit
);
741 ok(!strcmp(edit
, expected_edit_text
), "edit: got %s, expected %s\n",
742 edit
, expected_edit_text
);
743 ok(!strcmp(list
, expected_list_text
), "list: got %s, expected %s\n",
744 list
, expected_list_text
);
746 selchange_fired
= TRUE
;
753 return CallWindowProcA(old_parent_proc
, hwnd
, msg
, wparam
, lparam
);
756 static void test_selection(DWORD style
, const char * const text
[], const int *edit
, const int *list
)
761 hCombo
= create_combobox(style
);
763 SendMessageA(hCombo
, CB_ADDSTRING
, 0, (LPARAM
)text
[0]);
764 SendMessageA(hCombo
, CB_ADDSTRING
, 0, (LPARAM
)text
[1]);
765 SendMessageA(hCombo
, CB_SETCURSEL
, -1, 0);
767 old_parent_proc
= (void *)SetWindowLongPtrA(hMainWnd
, GWLP_WNDPROC
, (ULONG_PTR
)parent_wnd_proc
);
769 idx
= SendMessageA(hCombo
, CB_GETCURSEL
, 0, 0);
770 ok(idx
== -1, "expected selection -1, got %d\n", idx
);
772 /* keyboard navigation */
774 expected_list_text
= text
[list
[0]];
775 expected_edit_text
= text
[edit
[0]];
776 selchange_fired
= FALSE
;
777 SendMessageA(hCombo
, WM_KEYDOWN
, VK_DOWN
, 0);
778 ok(selchange_fired
, "CBN_SELCHANGE not sent!\n");
780 expected_list_text
= text
[list
[1]];
781 expected_edit_text
= text
[edit
[1]];
782 selchange_fired
= FALSE
;
783 SendMessageA(hCombo
, WM_KEYDOWN
, VK_DOWN
, 0);
784 ok(selchange_fired
, "CBN_SELCHANGE not sent!\n");
786 expected_list_text
= text
[list
[2]];
787 expected_edit_text
= text
[edit
[2]];
788 selchange_fired
= FALSE
;
789 SendMessageA(hCombo
, WM_KEYDOWN
, VK_UP
, 0);
790 ok(selchange_fired
, "CBN_SELCHANGE not sent!\n");
792 /* programmatic navigation */
794 expected_list_text
= text
[list
[3]];
795 expected_edit_text
= text
[edit
[3]];
796 selchange_fired
= FALSE
;
797 SendMessageA(hCombo
, CB_SETCURSEL
, list
[3], 0);
798 ok(!selchange_fired
, "CBN_SELCHANGE sent!\n");
800 expected_list_text
= text
[list
[4]];
801 expected_edit_text
= text
[edit
[4]];
802 selchange_fired
= FALSE
;
803 SendMessageA(hCombo
, CB_SETCURSEL
, list
[4], 0);
804 ok(!selchange_fired
, "CBN_SELCHANGE sent!\n");
806 SetWindowLongPtrA(hMainWnd
, GWLP_WNDPROC
, (ULONG_PTR
)old_parent_proc
);
807 DestroyWindow(hCombo
);
810 static void test_combo_CBN_SELCHANGE(void)
812 static const char * const text
[] = { "alpha", "beta", "" };
813 static const int sel_1
[] = { 2, 0, 1, 0, 1 };
814 static const int sel_2
[] = { 0, 1, 0, 0, 1 };
816 test_selection(CBS_SIMPLE
, text
, sel_1
, sel_2
);
817 test_selection(CBS_DROPDOWN
, text
, sel_1
, sel_2
);
818 test_selection(CBS_DROPDOWNLIST
, text
, sel_2
, sel_2
);
821 static void test_combo_changesize(DWORD style
)
823 INT ddheight
, clheight
, ddwidth
, clwidth
;
827 hCombo
= create_combobox(style
);
829 /* get initial measurements */
830 GetClientRect( hCombo
, &rc
);
831 clheight
= rc
.bottom
- rc
.top
;
832 clwidth
= rc
.right
- rc
.left
;
833 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&rc
);
834 ddheight
= rc
.bottom
- rc
.top
;
835 ddwidth
= rc
.right
- rc
.left
;
836 /* use MoveWindow to move & resize the combo */
837 /* first make it slightly smaller */
838 MoveWindow( hCombo
, 10, 10, clwidth
- 2, clheight
- 2, TRUE
);
839 GetClientRect( hCombo
, &rc
);
840 ok( rc
.right
- rc
.left
== clwidth
- 2, "clientrect width is %d vs %d\n",
841 rc
.right
- rc
.left
, clwidth
- 2);
842 ok( rc
.bottom
- rc
.top
== clheight
, "clientrect height is %d vs %d\n",
843 rc
.bottom
- rc
.top
, clheight
);
844 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&rc
);
845 ok( rc
.right
- rc
.left
== clwidth
- 2, "drop-down rect width is %d vs %d\n",
846 rc
.right
- rc
.left
, clwidth
- 2);
847 ok( rc
.bottom
- rc
.top
== ddheight
, "drop-down rect height is %d vs %d\n",
848 rc
.bottom
- rc
.top
, ddheight
);
849 ok( rc
.right
- rc
.left
== ddwidth
-2, "drop-down rect width is %d vs %d\n",
850 rc
.right
- rc
.left
, ddwidth
- 2);
851 /* new cx, cy is slightly bigger than the initial values */
852 MoveWindow( hCombo
, 10, 10, clwidth
+ 2, clheight
+ 2, TRUE
);
853 GetClientRect( hCombo
, &rc
);
854 ok( rc
.right
- rc
.left
== clwidth
+ 2, "clientrect width is %d vs %d\n",
855 rc
.right
- rc
.left
, clwidth
+ 2);
856 ok( rc
.bottom
- rc
.top
== clheight
, "clientrect height is %d vs %d\n",
857 rc
.bottom
- rc
.top
, clheight
);
858 SendMessageA(hCombo
, CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
)&rc
);
859 ok( rc
.right
- rc
.left
== clwidth
+ 2, "drop-down rect width is %d vs %d\n",
860 rc
.right
- rc
.left
, clwidth
+ 2);
862 ok( rc
.bottom
- rc
.top
== clheight
+ 2, "drop-down rect height is %d vs %d\n",
863 rc
.bottom
- rc
.top
, clheight
+ 2);
866 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, -1, 0);
867 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
868 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
869 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
871 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, 0, 0);
872 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
873 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
874 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
876 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, clwidth
- 1, 0);
877 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
878 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
879 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
881 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, clwidth
<< 1, 0);
882 ok( ddwidth
== (clwidth
<< 1), "drop-width is %d vs %d\n", ddwidth
, clwidth
<< 1);
883 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
884 ok( ddwidth
== (clwidth
<< 1), "drop-width is %d vs %d\n", ddwidth
, clwidth
<< 1);
886 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, 0, 0);
887 ok( ddwidth
== (clwidth
<< 1), "drop-width is %d vs %d\n", ddwidth
, clwidth
<< 1);
888 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
889 ok( ddwidth
== (clwidth
<< 1), "drop-width is %d vs %d\n", ddwidth
, clwidth
<< 1);
891 ddwidth
= SendMessageA(hCombo
, CB_SETDROPPEDWIDTH
, 1, 0);
892 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
893 ddwidth
= SendMessageA(hCombo
, CB_GETDROPPEDWIDTH
, 0, 0);
894 ok( ddwidth
== clwidth
+ 2, "drop-width is %d vs %d\n", ddwidth
, clwidth
+ 2);
896 DestroyWindow(hCombo
);
899 static void test_combo_editselection(void)
909 hCombo
= create_combobox(CBS_SIMPLE
);
911 get_combobox_info(hCombo
, &cbInfo
);
912 hEdit
= cbInfo
.hwndItem
;
914 /* Initially combo selection is empty*/
915 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
916 ok(LOWORD(len
)==0, "Unexpected start position for selection %d\n", LOWORD(len
));
917 ok(HIWORD(len
)==0, "Unexpected end position for selection %d\n", HIWORD(len
));
919 /* Set some text, and press a key to replace it */
921 SendMessageA(hCombo
, WM_SETTEXT
, 0, (LPARAM
)"Jason1");
922 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(edit
), (LPARAM
)edit
);
923 ok(strcmp(edit
, "Jason1")==0, "Unexpected text retrieved %s\n", edit
);
925 /* Now what is the selection - still empty */
926 SendMessageA(hCombo
, CB_GETEDITSEL
, (WPARAM
)&start
, (WPARAM
)&end
);
927 ok(start
==0, "Unexpected start position for selection %d\n", start
);
928 ok(end
==0, "Unexpected end position for selection %d\n", end
);
929 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
930 ok(LOWORD(len
)==0, "Unexpected start position for selection %d\n", LOWORD(len
));
931 ok(HIWORD(len
)==0, "Unexpected end position for selection %d\n", HIWORD(len
));
933 /* Give it focus, and it gets selected */
934 SendMessageA(hCombo
, WM_SETFOCUS
, 0, (LPARAM
)hEdit
);
935 SendMessageA(hCombo
, CB_GETEDITSEL
, (WPARAM
)&start
, (WPARAM
)&end
);
936 ok(start
==0, "Unexpected start position for selection %d\n", start
);
937 ok(end
==6, "Unexpected end position for selection %d\n", end
);
938 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
939 ok(LOWORD(len
)==0, "Unexpected start position for selection %d\n", LOWORD(len
));
940 ok(HIWORD(len
)==6, "Unexpected end position for selection %d\n", HIWORD(len
));
942 /* Now emulate a key press */
944 SendMessageA(hCombo
, WM_CHAR
, 'A', 0x1c0001);
945 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(edit
), (LPARAM
)edit
);
946 ok(strcmp(edit
, "A")==0, "Unexpected text retrieved %s\n", edit
);
948 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
949 ok(LOWORD(len
)==1, "Unexpected start position for selection %d\n", LOWORD(len
));
950 ok(HIWORD(len
)==1, "Unexpected end position for selection %d\n", HIWORD(len
));
952 /* Now what happens when it gets more focus a second time - it doesn't reselect */
953 SendMessageA(hCombo
, WM_SETFOCUS
, 0, (LPARAM
)hEdit
);
954 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
955 ok(LOWORD(len
)==1, "Unexpected start position for selection %d\n", LOWORD(len
));
956 ok(HIWORD(len
)==1, "Unexpected end position for selection %d\n", HIWORD(len
));
957 DestroyWindow(hCombo
);
959 /* Start again - Build a combo */
960 hCombo
= create_combobox(CBS_SIMPLE
);
961 get_combobox_info(hCombo
, &cbInfo
);
962 hEdit
= cbInfo
.hwndItem
;
964 /* Set some text and give focus so it gets selected */
966 SendMessageA(hCombo
, WM_SETTEXT
, 0, (LPARAM
)"Jason2");
967 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(edit
), (LPARAM
)edit
);
968 ok(strcmp(edit
, "Jason2")==0, "Unexpected text retrieved %s\n", edit
);
970 SendMessageA(hCombo
, WM_SETFOCUS
, 0, (LPARAM
)hEdit
);
972 /* Now what is the selection */
973 SendMessageA(hCombo
, CB_GETEDITSEL
, (WPARAM
)&start
, (WPARAM
)&end
);
974 ok(start
==0, "Unexpected start position for selection %d\n", start
);
975 ok(end
==6, "Unexpected end position for selection %d\n", end
);
976 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0,0);
977 ok(LOWORD(len
)==0, "Unexpected start position for selection %d\n", LOWORD(len
));
978 ok(HIWORD(len
)==6, "Unexpected end position for selection %d\n", HIWORD(len
));
980 /* Now change the selection to the apparently invalid start -1, end -1 and
981 show it means no selection (ie start -1) but cursor at end */
982 SendMessageA(hCombo
, CB_SETEDITSEL
, 0, -1);
984 SendMessageA(hCombo
, WM_CHAR
, 'A', 0x1c0001);
985 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(edit
), (LPARAM
)edit
);
986 ok(strcmp(edit
, "Jason2A")==0, "Unexpected text retrieved %s\n", edit
);
987 DestroyWindow(hCombo
);
990 static WNDPROC edit_window_proc
;
991 static long setsel_start
= 1, setsel_end
= 1;
992 static HWND hCBN_SetFocus
, hCBN_KillFocus
;
994 static LRESULT CALLBACK
combobox_subclass_proc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
996 if (msg
== EM_SETSEL
)
998 setsel_start
= wParam
;
1001 return CallWindowProcA(edit_window_proc
, hwnd
, msg
, wParam
, lParam
);
1004 static LRESULT CALLBACK
test_window_proc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1009 switch (HIWORD(wParam
))
1012 hCBN_SetFocus
= (HWND
)lParam
;
1015 hCBN_KillFocus
= (HWND
)lParam
;
1020 SetFocus((HWND
)wParam
);
1023 return CallWindowProcA(old_parent_proc
, hwnd
, msg
, wParam
, lParam
);
1026 static void test_combo_editselection_focus(DWORD style
)
1028 static const char wine_test
[] = "Wine Test";
1029 HWND hCombo
, hEdit
, hButton
;
1030 char buffer
[16] = {0};
1031 COMBOBOXINFO cbInfo
;
1034 hCombo
= create_combobox(style
);
1035 get_combobox_info(hCombo
, &cbInfo
);
1036 hEdit
= cbInfo
.hwndItem
;
1038 hButton
= CreateWindowA(WC_BUTTONA
, "OK", WS_VISIBLE
|WS_CHILD
|BS_DEFPUSHBUTTON
,
1039 5, 50, 100, 20, hMainWnd
, NULL
,
1040 (HINSTANCE
)GetWindowLongPtrA(hMainWnd
, GWLP_HINSTANCE
), NULL
);
1042 old_parent_proc
= (WNDPROC
)SetWindowLongPtrA(hMainWnd
, GWLP_WNDPROC
, (ULONG_PTR
)test_window_proc
);
1043 edit_window_proc
= (WNDPROC
)SetWindowLongPtrA(hEdit
, GWLP_WNDPROC
, (ULONG_PTR
)combobox_subclass_proc
);
1045 SendMessageA(hCombo
, WM_SETFOCUS
, 0, (LPARAM
)hEdit
);
1046 ok(setsel_start
== 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start
);
1047 todo_wine
ok(setsel_end
== INT_MAX
, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end
);
1048 ok(hCBN_SetFocus
== hCombo
, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus
);
1049 ok(GetFocus() == hEdit
, "hEdit should have keyboard focus\n");
1051 SendMessageA(hMainWnd
, WM_NEXTDLGCTL
, (WPARAM
)hButton
, TRUE
);
1052 ok(setsel_start
== 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start
);
1053 todo_wine
ok(setsel_end
== 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end
);
1054 ok(hCBN_KillFocus
== hCombo
, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus
);
1055 ok(GetFocus() == hButton
, "hButton should have keyboard focus\n");
1057 SendMessageA(hCombo
, WM_SETTEXT
, 0, (LPARAM
)wine_test
);
1058 SendMessageA(hMainWnd
, WM_NEXTDLGCTL
, (WPARAM
)hCombo
, TRUE
);
1059 ok(setsel_start
== 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start
);
1060 todo_wine
ok(setsel_end
== INT_MAX
, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end
);
1061 ok(hCBN_SetFocus
== hCombo
, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus
);
1062 ok(GetFocus() == hEdit
, "hEdit should have keyboard focus\n");
1063 SendMessageA(hCombo
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1064 ok(!strcmp(buffer
, wine_test
), "Unexpected text in edit control; got '%s'\n", buffer
);
1066 SendMessageA(hMainWnd
, WM_NEXTDLGCTL
, (WPARAM
)hButton
, TRUE
);
1067 ok(setsel_start
== 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start
);
1068 todo_wine
ok(setsel_end
== 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end
);
1069 ok(hCBN_KillFocus
== hCombo
, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus
);
1070 ok(GetFocus() == hButton
, "hButton should have keyboard focus\n");
1071 len
= SendMessageA(hCombo
, CB_GETEDITSEL
, 0, 0);
1072 ok(len
== 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len
), HIWORD(len
));
1074 SetWindowLongPtrA(hMainWnd
, GWLP_WNDPROC
, (ULONG_PTR
)old_parent_proc
);
1075 DestroyWindow(hButton
);
1076 DestroyWindow(hCombo
);
1079 static void test_combo_listbox_styles(DWORD cb_style
)
1081 DWORD style
, exstyle
, expect_style
, expect_exstyle
;
1085 expect_style
= WS_CHILD
|WS_CLIPSIBLINGS
|LBS_COMBOBOX
|LBS_HASSTRINGS
|LBS_NOTIFY
;
1086 if (cb_style
== CBS_SIMPLE
)
1088 expect_style
|= WS_VISIBLE
;
1089 expect_exstyle
= WS_EX_CLIENTEDGE
;
1093 expect_style
|= WS_BORDER
;
1094 expect_exstyle
= WS_EX_TOOLWINDOW
;
1097 combo
= create_combobox(cb_style
);
1098 get_combobox_info(combo
, &info
);
1100 style
= GetWindowLongW( info
.hwndList
, GWL_STYLE
);
1101 exstyle
= GetWindowLongW( info
.hwndList
, GWL_EXSTYLE
);
1102 ok(style
== expect_style
, "%08x: got %08x\n", cb_style
, style
);
1103 ok(exstyle
== expect_exstyle
, "%08x: got %08x\n", cb_style
, exstyle
);
1105 if (cb_style
!= CBS_SIMPLE
)
1106 expect_exstyle
|= WS_EX_TOPMOST
;
1108 SendMessageW(combo
, CB_SHOWDROPDOWN
, TRUE
, 0 );
1109 style
= GetWindowLongW( info
.hwndList
, GWL_STYLE
);
1110 exstyle
= GetWindowLongW( info
.hwndList
, GWL_EXSTYLE
);
1111 ok(style
== (expect_style
| WS_VISIBLE
), "%08x: got %08x\n", cb_style
, style
);
1112 ok(exstyle
== expect_exstyle
, "%08x: got %08x\n", cb_style
, exstyle
);
1114 SendMessageW(combo
, CB_SHOWDROPDOWN
, FALSE
, 0 );
1115 style
= GetWindowLongW( info
.hwndList
, GWL_STYLE
);
1116 exstyle
= GetWindowLongW( info
.hwndList
, GWL_EXSTYLE
);
1117 ok(style
== expect_style
, "%08x: got %08x\n", cb_style
, style
);
1118 ok(exstyle
== expect_exstyle
, "%08x: got %08x\n", cb_style
, exstyle
);
1120 DestroyWindow(combo
);
1123 static void test_combo_WS_VSCROLL(void)
1130 hCombo
= create_combobox(CBS_DROPDOWNLIST
);
1132 get_combobox_info(hCombo
, &info
);
1133 hList
= info
.hwndList
;
1135 for (i
= 0; i
< 3; i
++)
1138 sprintf(buffer
, "%d", i
);
1139 SendMessageA(hCombo
, CB_ADDSTRING
, 0, (LPARAM
)buffer
);
1142 style
= GetWindowLongA(info
.hwndList
, GWL_STYLE
);
1143 SetWindowLongA(hList
, GWL_STYLE
, style
| WS_VSCROLL
);
1145 SendMessageA(hCombo
, CB_SHOWDROPDOWN
, TRUE
, 0);
1146 SendMessageA(hCombo
, CB_SHOWDROPDOWN
, FALSE
, 0);
1148 style
= GetWindowLongA(hList
, GWL_STYLE
);
1149 ok((style
& WS_VSCROLL
) != 0, "Style does not include WS_VSCROLL\n");
1151 DestroyWindow(hCombo
);
1154 static void test_combo_dropdown_size(DWORD style
)
1156 static const char wine_test
[] = "Wine Test";
1158 COMBOBOXINFO cbInfo
;
1161 static const struct list_size_info
1172 for (test
= 0; test
< sizeof(info_height
) / sizeof(info_height
[0]); test
++)
1174 const struct list_size_info
*info_test
= &info_height
[test
];
1175 int height_item
; /* Height of a list item */
1176 int height_list
; /* Height of the list we got */
1177 int expected_height_list
;
1178 RECT rect_list_client
;
1179 int min_visible_expected
;
1181 hCombo
= CreateWindowA(WC_COMBOBOXA
, "Combo", CBS_DROPDOWN
| WS_VISIBLE
| WS_CHILD
| style
, 5, 5, 100,
1182 info_test
->height_combo
, hMainWnd
, (HMENU
)COMBO_ID
, NULL
, 0);
1184 min_visible_expected
= SendMessageA(hCombo
, CB_GETMINVISIBLE
, 0, 0);
1186 ok(min_visible_expected
== 30, "Unexpected number of items %d.\n", min_visible_expected
);
1188 cbInfo
.cbSize
= sizeof(COMBOBOXINFO
);
1189 ret
= SendMessageA(hCombo
, CB_GETCOMBOBOXINFO
, 0, (LPARAM
)&cbInfo
);
1190 ok(ret
, "Failed to get combo info, %d\n", ret
);
1192 hList
= cbInfo
.hwndList
;
1193 for (i
= 0; i
< info_test
->num_items
; i
++)
1195 ret
= SendMessageA(hCombo
, CB_ADDSTRING
, 0, (LPARAM
) wine_test
);
1196 ok(ret
== i
, "Failed to add string %d, returned %d.\n", i
, ret
);
1199 if (info_test
->limit
!= -1)
1201 int min_visible_actual
;
1202 min_visible_expected
= info_test
->limit
;
1204 ret
= SendMessageA(hCombo
, CB_SETMINVISIBLE
, min_visible_expected
, 0);
1206 ok(ret
, "Failed to set visible limit.\n");
1207 min_visible_actual
= SendMessageA(hCombo
, CB_GETMINVISIBLE
, 0, 0);
1209 ok(min_visible_expected
== min_visible_actual
, "test %d: unexpected number of items %d.\n",
1210 test
, min_visible_actual
);
1213 ret
= SendMessageA(hCombo
, CB_SHOWDROPDOWN
, TRUE
,0);
1214 ok(ret
, "Failed to show dropdown.\n");
1215 ret
= SendMessageA(hCombo
, CB_GETDROPPEDSTATE
, 0, 0);
1216 ok(ret
, "Unexpected dropped state.\n");
1218 GetClientRect(hList
, &rect_list_client
);
1219 height_list
= rect_list_client
.bottom
- rect_list_client
.top
;
1220 height_item
= (int)SendMessageA(hList
, LB_GETITEMHEIGHT
, 0, 0);
1222 if (style
& CBS_NOINTEGRALHEIGHT
)
1224 RECT rect_list_complete
;
1225 int list_height_nonclient
;
1226 int list_height_calculated
;
1227 int edit_padding_size
= cbInfo
.rcItem
.top
; /* edit client rect top is the padding it has to its parent
1228 We assume it's the same on the bottom */
1230 GetWindowRect(hList
, &rect_list_complete
);
1232 list_height_nonclient
= (rect_list_complete
.bottom
- rect_list_complete
.top
)
1233 - (rect_list_client
.bottom
- rect_list_client
.top
);
1235 /* Calculate the expected client size of the listbox popup from the size of the combobox. */
1236 list_height_calculated
= info_test
->height_combo
/* Take height we created combobox with */
1237 - (cbInfo
.rcItem
.bottom
- cbInfo
.rcItem
.top
) /* Subtract size of edit control */
1238 - list_height_nonclient
/* Subtract list nonclient area */
1239 - edit_padding_size
* 2; /* subtract space around the edit control */
1241 expected_height_list
= min(list_height_calculated
, height_item
* info_test
->num_items
);
1242 if (expected_height_list
< 0)
1243 expected_height_list
= 0;
1246 ok(expected_height_list
== height_list
, "Test %d, expected list height to be %d, got %d\n",
1247 test
, expected_height_list
, height_list
);
1251 expected_height_list
= min(info_test
->num_items
, min_visible_expected
) * height_item
;
1254 ok(expected_height_list
== height_list
, "Test %d, expected list height to be %d, got %d\n",
1255 test
, expected_height_list
, height_list
);
1258 DestroyWindow(hCombo
);
1264 ULONG_PTR ctx_cookie
;
1272 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1274 /* ComboBoxEx32 tests. */
1276 test_comboex_WM_LBUTTONDOWN();
1277 test_comboex_CB_GETLBTEXT();
1278 test_comboex_WM_WINDOWPOSCHANGING();
1279 test_comboex_subclass();
1280 test_comboex_get_set_item();
1282 if (!load_v6_module(&ctx_cookie
, &hCtx
))
1288 /* ComboBox control tests. */
1289 test_combo_WS_VSCROLL();
1290 test_combo_setfont(CBS_DROPDOWN
);
1291 test_combo_setfont(CBS_DROPDOWNLIST
);
1292 test_combo_setitemheight(CBS_DROPDOWN
);
1293 test_combo_setitemheight(CBS_DROPDOWNLIST
);
1294 test_combo_CBN_SELCHANGE();
1295 test_combo_changesize(CBS_DROPDOWN
);
1296 test_combo_changesize(CBS_DROPDOWNLIST
);
1297 test_combo_editselection();
1298 test_combo_editselection_focus(CBS_SIMPLE
);
1299 test_combo_editselection_focus(CBS_DROPDOWN
);
1300 test_combo_listbox_styles(CBS_SIMPLE
);
1301 test_combo_listbox_styles(CBS_DROPDOWN
);
1302 test_combo_listbox_styles(CBS_DROPDOWNLIST
);
1303 test_combo_dropdown_size(0);
1304 test_combo_dropdown_size(CBS_NOINTEGRALHEIGHT
);
1307 unload_v6_module(ctx_cookie
, hCtx
);