1 /* Unit test suite for ComboBox and ComboBoxEx32 controls. 2 * 3 * Copyright 2005 Jason Edmeades 4 * Copyright 2007 Mikolaj Zalewski 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include "precomp.h" 22 23 #define EDITBOX_SEQ_INDEX 0 24 #define NUM_MSG_SEQUENCES 1 25 26 #define EDITBOX_ID 0 27 #define COMBO_ID 1995 28 29 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) 30 31 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \ 32 r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \ 33 wine_dbgstr_rect(&r), _left, _top, _right, _bottom); 34 35 36 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 37 38 static HWND hComboExParentWnd, hMainWnd; 39 static HINSTANCE hMainHinst; 40 static const char ComboExTestClass[] = "ComboExTestClass"; 41 42 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); 43 44 #define MAX_CHARS 100 45 static char *textBuffer = NULL; 46 47 static BOOL received_end_edit = FALSE; 48 49 static void get_combobox_info(HWND hwnd, COMBOBOXINFO *info) 50 { 51 BOOL ret; 52 53 info->cbSize = sizeof(*info); 54 ret = GetComboBoxInfo(hwnd, info); 55 ok(ret, "Failed to get combobox info structure, error %d\n", GetLastError()); 56 } 57 58 static HWND createComboEx(DWORD style) { 59 return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300, 60 hComboExParentWnd, NULL, hMainHinst, NULL); 61 } 62 63 static LONG addItem(HWND cbex, int idx, const char *text) { 64 COMBOBOXEXITEMA cbexItem; 65 memset(&cbexItem, 0x00, sizeof(cbexItem)); 66 cbexItem.mask = CBEIF_TEXT; 67 cbexItem.iItem = idx; 68 cbexItem.pszText = (char*)text; 69 cbexItem.cchTextMax = 0; 70 return SendMessageA(cbex, CBEM_INSERTITEMA, 0, (LPARAM)&cbexItem); 71 } 72 73 static LONG setItem(HWND cbex, int idx, const char *text) { 74 COMBOBOXEXITEMA cbexItem; 75 memset(&cbexItem, 0x00, sizeof(cbexItem)); 76 cbexItem.mask = CBEIF_TEXT; 77 cbexItem.iItem = idx; 78 cbexItem.pszText = (char*)text; 79 cbexItem.cchTextMax = 0; 80 return SendMessageA(cbex, CBEM_SETITEMA, 0, (LPARAM)&cbexItem); 81 } 82 83 static LONG delItem(HWND cbex, int idx) { 84 return SendMessageA(cbex, CBEM_DELETEITEM, idx, 0); 85 } 86 87 static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEMA *cbItem) { 88 memset(cbItem, 0x00, sizeof(COMBOBOXEXITEMA)); 89 cbItem->mask = CBEIF_TEXT; 90 cbItem->pszText = textBuffer; 91 cbItem->iItem = idx; 92 cbItem->cchTextMax = 100; 93 return SendMessageA(cbex, CBEM_GETITEMA, 0, (LPARAM)cbItem); 94 } 95 96 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 97 { 98 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); 99 static LONG defwndproc_counter = 0; 100 struct message msg = { 0 }; 101 LRESULT ret; 102 103 msg.message = message; 104 msg.flags = sent|wparam|lparam; 105 if (defwndproc_counter) msg.flags |= defwinproc; 106 msg.wParam = wParam; 107 msg.lParam = lParam; 108 msg.id = EDITBOX_ID; 109 110 if (message != WM_PAINT && 111 message != WM_ERASEBKGND && 112 message != WM_NCPAINT && 113 message != WM_NCHITTEST && 114 message != WM_GETTEXT && 115 message != WM_GETICON && 116 message != WM_DEVICECHANGE) 117 { 118 add_message(sequences, EDITBOX_SEQ_INDEX, &msg); 119 } 120 121 defwndproc_counter++; 122 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); 123 defwndproc_counter--; 124 return ret; 125 } 126 127 static HWND subclass_editbox(HWND hwndComboEx) 128 { 129 WNDPROC oldproc; 130 HWND hwnd; 131 132 hwnd = (HWND)SendMessageA(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0); 133 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, 134 (LONG_PTR)editbox_subclass_proc); 135 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); 136 137 return hwnd; 138 } 139 140 static void test_comboex(void) 141 { 142 HWND myHwnd = 0; 143 LONG res; 144 COMBOBOXEXITEMA cbexItem; 145 static const char *first_item = "First Item", 146 *second_item = "Second Item", 147 *third_item = "Third Item", 148 *middle_item = "Between First and Second Items", 149 *replacement_item = "Between First and Second Items", 150 *out_of_range_item = "Out of Range Item"; 151 152 /* Allocate space for result */ 153 textBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_CHARS); 154 155 /* Basic comboboxex test */ 156 myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); 157 158 /* Add items onto the end of the combobox */ 159 res = addItem(myHwnd, -1, first_item); 160 ok(res == 0, "Adding simple item failed (%d)\n", res); 161 res = addItem(myHwnd, -1, second_item); 162 ok(res == 1, "Adding simple item failed (%d)\n", res); 163 res = addItem(myHwnd, 2, third_item); 164 ok(res == 2, "Adding simple item failed (%d)\n", res); 165 res = addItem(myHwnd, 1, middle_item); 166 ok(res == 1, "Inserting simple item failed (%d)\n", res); 167 168 /* Add an item completely out of range */ 169 res = addItem(myHwnd, 99, out_of_range_item); 170 ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res); 171 res = addItem(myHwnd, 5, out_of_range_item); 172 ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res); 173 /* Removed: Causes traps on Windows XP 174 res = addItem(myHwnd, -2, "Out Of Range Item"); 175 ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res); 176 */ 177 178 /* Get an item completely out of range */ 179 res = getItem(myHwnd, 99, &cbexItem); 180 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); 181 res = getItem(myHwnd, 4, &cbexItem); 182 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); 183 res = getItem(myHwnd, -2, &cbexItem); 184 ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText); 185 186 /* Get an item in range */ 187 res = getItem(myHwnd, 0, &cbexItem); 188 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); 189 ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); 190 191 res = getItem(myHwnd, 1, &cbexItem); 192 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); 193 ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); 194 195 res = getItem(myHwnd, 2, &cbexItem); 196 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); 197 ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); 198 199 res = getItem(myHwnd, 3, &cbexItem); 200 ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res); 201 ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText); 202 203 /* Set an item completely out of range */ 204 res = setItem(myHwnd, 99, replacement_item); 205 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); 206 res = setItem(myHwnd, 4, replacement_item); 207 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); 208 res = setItem(myHwnd, -2, replacement_item); 209 ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res); 210 211 /* Set an item in range */ 212 res = setItem(myHwnd, 0, replacement_item); 213 ok(res != 0, "Setting first item failed (%d)\n", res); 214 res = setItem(myHwnd, 3, replacement_item); 215 ok(res != 0, "Setting last item failed (%d)\n", res); 216 217 /* Remove items completely out of range (4 items in control at this point) */ 218 res = delItem(myHwnd, -1); 219 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); 220 res = delItem(myHwnd, 4); 221 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); 222 223 /* Remove items in range (4 items in control at this point) */ 224 res = delItem(myHwnd, 3); 225 ok(res == 3, "Deleting using out of range index failed (%d)\n", res); 226 res = delItem(myHwnd, 0); 227 ok(res == 2, "Deleting using out of range index failed (%d)\n", res); 228 res = delItem(myHwnd, 0); 229 ok(res == 1, "Deleting using out of range index failed (%d)\n", res); 230 res = delItem(myHwnd, 0); 231 ok(res == 0, "Deleting using out of range index failed (%d)\n", res); 232 233 /* Remove from an empty box */ 234 res = delItem(myHwnd, 0); 235 ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res); 236 237 238 /* Cleanup */ 239 HeapFree(GetProcessHeap(), 0, textBuffer); 240 DestroyWindow(myHwnd); 241 } 242 243 static void test_comboex_WM_LBUTTONDOWN(void) 244 { 245 HWND hComboEx, hCombo, hEdit, hList; 246 COMBOBOXINFO cbInfo; 247 UINT x, y, item_height; 248 LRESULT result; 249 UINT i; 250 int idx; 251 RECT rect; 252 WCHAR buffer[3]; 253 static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; 254 static const WCHAR stringFormat[] = {'%','2','d','\0'}; 255 256 hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL, 257 WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150, 258 hComboExParentWnd, NULL, hMainHinst, NULL); 259 260 for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){ 261 COMBOBOXEXITEMW cbexItem; 262 wsprintfW(buffer, stringFormat, choices[i]); 263 264 memset(&cbexItem, 0x00, sizeof(cbexItem)); 265 cbexItem.mask = CBEIF_TEXT; 266 cbexItem.iItem = i; 267 cbexItem.pszText = buffer; 268 cbexItem.cchTextMax = 0; 269 ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0, 270 "Failed to add item %d\n", i); 271 } 272 273 hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); 274 hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); 275 276 get_combobox_info(hCombo, &cbInfo); 277 hList = cbInfo.hwndList; 278 279 ok(GetFocus() == hComboExParentWnd, 280 "Focus not on Main Window, instead on %p\n", GetFocus()); 281 282 /* Click on the button to drop down the list */ 283 x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; 284 y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; 285 result = SendMessageA(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); 286 ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", 287 GetLastError()); 288 ok(GetFocus() == hCombo || 289 broken(GetFocus() != hCombo), /* win98 */ 290 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", 291 GetFocus()); 292 ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), 293 "The dropdown list should have appeared after clicking the button.\n"); 294 idx = SendMessageA(hCombo, CB_GETTOPINDEX, 0, 0); 295 ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx); 296 297 result = SendMessageA(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); 298 ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", 299 GetLastError()); 300 ok(GetFocus() == hCombo || 301 broken(GetFocus() != hCombo), /* win98 */ 302 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", 303 GetFocus()); 304 305 /* Click on the 5th item in the list */ 306 item_height = SendMessageA(hCombo, CB_GETITEMHEIGHT, 0, 0); 307 ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n"); 308 x = rect.left + (rect.right-rect.left)/2; 309 y = item_height/2 + item_height*4; 310 result = SendMessageA(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); 311 ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", 312 GetLastError()); 313 ok(GetFocus() == hCombo || 314 broken(GetFocus() != hCombo), /* win98 */ 315 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", 316 GetFocus()); 317 318 result = SendMessageA(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); 319 ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", 320 GetLastError()); 321 ok(GetFocus() == hCombo || 322 broken(GetFocus() != hCombo), /* win98 */ 323 "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", 324 GetFocus()); 325 ok(SendMessageA(hComboEx, CB_GETDROPPEDSTATE, 0, 0), 326 "The dropdown list should still be visible.\n"); 327 328 result = SendMessageA(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); 329 ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", 330 GetLastError()); 331 todo_wine ok(GetFocus() == hEdit || 332 broken(GetFocus() == hCombo), /* win98 */ 333 "Focus not on ComboBoxEx's Edit Control, instead on %p\n", 334 GetFocus()); 335 336 result = SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0); 337 ok(!result || 338 broken(result != 0), /* win98 */ 339 "The dropdown list should have been rolled up.\n"); 340 idx = SendMessageA(hComboEx, CB_GETCURSEL, 0, 0); 341 ok(idx == 4 || 342 broken(idx == -1), /* win98 */ 343 "Current Selection: expected %d, got %d\n", 4, idx); 344 ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n"); 345 346 SetFocus( hComboExParentWnd ); 347 ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() ); 348 SetFocus( hComboEx ); 349 ok( GetFocus() == hEdit, "got %p\n", GetFocus() ); 350 351 DestroyWindow(hComboEx); 352 } 353 354 static void test_comboex_CB_GETLBTEXT(void) 355 { 356 HWND hCombo; 357 CHAR buff[1]; 358 COMBOBOXEXITEMA item; 359 LRESULT ret; 360 361 hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); 362 363 /* set text to null */ 364 addItem(hCombo, 0, NULL); 365 366 buff[0] = 'a'; 367 item.mask = CBEIF_TEXT; 368 item.iItem = 0; 369 item.pszText = buff; 370 item.cchTextMax = 1; 371 ret = SendMessageA(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item); 372 ok(ret != 0, "CBEM_GETITEM failed\n"); 373 ok(buff[0] == 0, "\n"); 374 375 ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); 376 ok(ret == 0, "Expected zero length\n"); 377 378 ret = SendMessageA(hCombo, CB_GETLBTEXTLEN, 0, 0); 379 ok(ret == 0, "Expected zero length\n"); 380 381 buff[0] = 'a'; 382 ret = SendMessageA(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff); 383 ok(ret == 0, "Expected zero length\n"); 384 ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff); 385 386 DestroyWindow(hCombo); 387 } 388 389 static void test_comboex_WM_WINDOWPOSCHANGING(void) 390 { 391 HWND hCombo; 392 WINDOWPOS wp; 393 RECT rect; 394 int combo_height; 395 int ret; 396 397 hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); 398 ok(hCombo != NULL, "createComboEx failed\n"); 399 ret = GetWindowRect(hCombo, &rect); 400 ok(ret, "GetWindowRect failed\n"); 401 combo_height = rect.bottom - rect.top; 402 ok(combo_height > 0, "wrong combo height\n"); 403 404 /* Test height > combo_height */ 405 wp.x = rect.left; 406 wp.y = rect.top; 407 wp.cx = (rect.right - rect.left); 408 wp.cy = combo_height * 2; 409 wp.flags = 0; 410 wp.hwnd = hCombo; 411 wp.hwndInsertAfter = NULL; 412 413 ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); 414 ok(ret == 0, "expected 0, got %x\n", ret); 415 ok(wp.cy == combo_height, 416 "Expected height %d, got %d\n", combo_height, wp.cy); 417 418 /* Test height < combo_height */ 419 wp.x = rect.left; 420 wp.y = rect.top; 421 wp.cx = (rect.right - rect.left); 422 wp.cy = combo_height / 2; 423 wp.flags = 0; 424 wp.hwnd = hCombo; 425 wp.hwndInsertAfter = NULL; 426 427 ret = SendMessageA(hCombo, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp); 428 ok(ret == 0, "expected 0, got %x\n", ret); 429 ok(wp.cy == combo_height, 430 "Expected height %d, got %d\n", combo_height, wp.cy); 431 432 ret = DestroyWindow(hCombo); 433 ok(ret, "DestroyWindow failed\n"); 434 } 435 436 static LRESULT ComboExTestOnNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 437 { 438 NMHDR *hdr = (NMHDR*)lParam; 439 switch(hdr->code){ 440 case CBEN_ENDEDITA: 441 { 442 NMCBEENDEDITA *edit_info = (NMCBEENDEDITA*)hdr; 443 if(edit_info->iWhy==CBENF_DROPDOWN){ 444 received_end_edit = TRUE; 445 } 446 break; 447 } 448 case CBEN_ENDEDITW: 449 { 450 NMCBEENDEDITW *edit_info = (NMCBEENDEDITW*)hdr; 451 if(edit_info->iWhy==CBENF_DROPDOWN){ 452 received_end_edit = TRUE; 453 } 454 break; 455 } 456 } 457 return 0; 458 } 459 460 static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 461 { 462 switch(msg) { 463 464 case WM_DESTROY: 465 PostQuitMessage(0); 466 break; 467 case WM_NOTIFY: 468 return ComboExTestOnNotify(hWnd,msg,wParam,lParam); 469 default: 470 return DefWindowProcA(hWnd, msg, wParam, lParam); 471 } 472 473 return 0L; 474 } 475 476 static BOOL init(void) 477 { 478 HMODULE hComctl32; 479 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); 480 WNDCLASSA wc; 481 INITCOMMONCONTROLSEX iccex; 482 483 hComctl32 = GetModuleHandleA("comctl32.dll"); 484 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); 485 if (!pInitCommonControlsEx) 486 { 487 win_skip("InitCommonControlsEx() is missing. Skipping the tests\n"); 488 return FALSE; 489 } 490 iccex.dwSize = sizeof(iccex); 491 iccex.dwICC = ICC_USEREX_CLASSES; 492 pInitCommonControlsEx(&iccex); 493 494 pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410); 495 496 wc.style = CS_HREDRAW | CS_VREDRAW; 497 wc.cbClsExtra = 0; 498 wc.cbWndExtra = 0; 499 wc.hInstance = GetModuleHandleA(NULL); 500 wc.hIcon = NULL; 501 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); 502 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); 503 wc.lpszMenuName = NULL; 504 wc.lpszClassName = ComboExTestClass; 505 wc.lpfnWndProc = ComboExTestWndProc; 506 RegisterClassA(&wc); 507 508 hMainWnd = CreateWindowA("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); 509 ShowWindow(hMainWnd, SW_SHOW); 510 511 hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE, 512 CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); 513 ok(hComboExParentWnd != NULL, "failed to create parent window\n"); 514 515 hMainHinst = GetModuleHandleA(NULL); 516 517 return hComboExParentWnd != NULL; 518 } 519 520 static void cleanup(void) 521 { 522 MSG msg; 523 524 PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0); 525 while (GetMessageA(&msg,0,0,0)) { 526 TranslateMessage(&msg); 527 DispatchMessageA(&msg); 528 } 529 530 DestroyWindow(hComboExParentWnd); 531 UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); 532 533 DestroyWindow(hMainWnd); 534 } 535 536 static void test_comboex_subclass(void) 537 { 538 HWND hComboEx, hCombo, hEdit; 539 540 hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); 541 542 hCombo = (HWND)SendMessageA(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); 543 ok(hCombo != NULL, "Failed to get internal combo\n"); 544 hEdit = (HWND)SendMessageA(hComboEx, CBEM_GETEDITCONTROL, 0, 0); 545 ok(hEdit != NULL, "Failed to get internal edit\n"); 546 547 if (pSetWindowSubclass) 548 { 549 ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); 550 ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n"); 551 } 552 553 DestroyWindow(hComboEx); 554 } 555 556 static const struct message test_setitem_edit_seq[] = { 557 { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID }, 558 { EM_SETSEL, sent|id|wparam|lparam, 0, 0, EDITBOX_ID }, 559 { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID }, 560 { 0 } 561 }; 562 563 static void test_comboex_get_set_item(void) 564 { 565 char textA[] = "test"; 566 HWND hComboEx; 567 COMBOBOXEXITEMA item; 568 BOOL ret; 569 570 hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN); 571 572 subclass_editbox(hComboEx); 573 574 flush_sequences(sequences, NUM_MSG_SEQUENCES); 575 576 memset(&item, 0, sizeof(item)); 577 item.mask = CBEIF_TEXT; 578 item.pszText = textA; 579 item.iItem = -1; 580 ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); 581 expect(TRUE, ret); 582 583 ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE); 584 585 /* get/set lParam */ 586 item.mask = CBEIF_LPARAM; 587 item.iItem = -1; 588 item.lParam = 0xdeadbeef; 589 ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); 590 expect(TRUE, ret); 591 ok(item.lParam == 0, "Expected zero, got %lx\n", item.lParam); 592 593 item.lParam = 0x1abe11ed; 594 ret = SendMessageA(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item); 595 expect(TRUE, ret); 596 597 item.lParam = 0; 598 ret = SendMessageA(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item); 599 expect(TRUE, ret); 600 ok(item.lParam == 0x1abe11ed, "Expected 0x1abe11ed, got %lx\n", item.lParam); 601 602 DestroyWindow(hComboEx); 603 } 604 605 static HWND create_combobox(DWORD style) 606 { 607 return CreateWindowA("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0); 608 } 609 610 static int font_height(HFONT hFont) 611 { 612 TEXTMETRICA tm; 613 HFONT hFontOld; 614 HDC hDC; 615 616 hDC = CreateCompatibleDC(NULL); 617 hFontOld = SelectObject(hDC, hFont); 618 GetTextMetricsA(hDC, &tm); 619 SelectObject(hDC, hFontOld); 620 DeleteDC(hDC); 621 622 return tm.tmHeight; 623 } 624 625 static void test_combo_setitemheight(DWORD style) 626 { 627 HWND hCombo = create_combobox(style); 628 RECT r; 629 int i; 630 631 GetClientRect(hCombo, &r); 632 expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); 633 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); 634 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); 635 todo_wine expect_rect(r, 5, 5, 105, 105); 636 637 for (i = 1; i < 30; i++) 638 { 639 SendMessageA(hCombo, CB_SETITEMHEIGHT, -1, i); 640 GetClientRect(hCombo, &r); 641 ok((r.bottom - r.top) == (i + 6), "Unexpected client rect height.\n"); 642 } 643 644 DestroyWindow(hCombo); 645 } 646 647 static void test_combo_setfont(DWORD style) 648 { 649 HFONT hFont1, hFont2; 650 HWND hCombo; 651 RECT r; 652 int i; 653 654 hCombo = create_combobox(style); 655 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"); 656 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"); 657 658 GetClientRect(hCombo, &r); 659 expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8); 660 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); 661 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); 662 todo_wine expect_rect(r, 5, 5, 105, 105); 663 664 /* The size of the dropped control is initially equal to the size 665 of the window when it was created. The size of the calculated 666 dropped area changes only by how much the selection area 667 changes, not by how much the list area changes. */ 668 if (font_height(hFont1) == 10 && font_height(hFont2) == 8) 669 { 670 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); 671 GetClientRect(hCombo, &r); 672 expect_rect(r, 0, 0, 100, 18); 673 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); 674 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); 675 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); 676 677 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE); 678 GetClientRect(hCombo, &r); 679 expect_rect(r, 0, 0, 100, 16); 680 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); 681 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); 682 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont2))); 683 684 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); 685 GetClientRect(hCombo, &r); 686 expect_rect(r, 0, 0, 100, 18); 687 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); 688 MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); 689 todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1))); 690 } 691 else 692 { 693 ok(0, "Expected Marlett font heights 10/8, got %d/%d\n", 694 font_height(hFont1), font_height(hFont2)); 695 } 696 697 for (i = 1; i < 30; i++) 698 { 699 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"); 700 int height = font_height(hFont); 701 702 SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE); 703 GetClientRect(hCombo, &r); 704 ok((r.bottom - r.top) == (height + 8), "Unexpected client rect height.\n"); 705 SendMessageA(hCombo, WM_SETFONT, 0, FALSE); 706 DeleteObject(hFont); 707 } 708 709 DestroyWindow(hCombo); 710 DeleteObject(hFont1); 711 DeleteObject(hFont2); 712 } 713 714 static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); 715 static LPCSTR expected_edit_text; 716 static LPCSTR expected_list_text; 717 static BOOL selchange_fired; 718 719 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 720 { 721 switch (msg) 722 { 723 case WM_COMMAND: 724 switch (wparam) 725 { 726 case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE): 727 { 728 HWND hCombo = (HWND)lparam; 729 char list[20], edit[20]; 730 int idx; 731 732 memset(list, 0, sizeof(list)); 733 memset(edit, 0, sizeof(edit)); 734 735 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0); 736 SendMessageA(hCombo, CB_GETLBTEXT, idx, (LPARAM)list); 737 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); 738 739 ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n", 740 edit, expected_edit_text); 741 ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n", 742 list, expected_list_text); 743 744 selchange_fired = TRUE; 745 } 746 break; 747 } 748 break; 749 } 750 751 return CallWindowProcA(old_parent_proc, hwnd, msg, wparam, lparam); 752 } 753 754 static void test_selection(DWORD style, const char * const text[], const int *edit, const int *list) 755 { 756 HWND hCombo; 757 INT idx; 758 759 hCombo = create_combobox(style); 760 761 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]); 762 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]); 763 SendMessageA(hCombo, CB_SETCURSEL, -1, 0); 764 765 old_parent_proc = (void *)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc); 766 767 idx = SendMessageA(hCombo, CB_GETCURSEL, 0, 0); 768 ok(idx == -1, "expected selection -1, got %d\n", idx); 769 770 /* keyboard navigation */ 771 772 expected_list_text = text[list[0]]; 773 expected_edit_text = text[edit[0]]; 774 selchange_fired = FALSE; 775 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0); 776 ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); 777 778 expected_list_text = text[list[1]]; 779 expected_edit_text = text[edit[1]]; 780 selchange_fired = FALSE; 781 SendMessageA(hCombo, WM_KEYDOWN, VK_DOWN, 0); 782 ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); 783 784 expected_list_text = text[list[2]]; 785 expected_edit_text = text[edit[2]]; 786 selchange_fired = FALSE; 787 SendMessageA(hCombo, WM_KEYDOWN, VK_UP, 0); 788 ok(selchange_fired, "CBN_SELCHANGE not sent!\n"); 789 790 /* programmatic navigation */ 791 792 expected_list_text = text[list[3]]; 793 expected_edit_text = text[edit[3]]; 794 selchange_fired = FALSE; 795 SendMessageA(hCombo, CB_SETCURSEL, list[3], 0); 796 ok(!selchange_fired, "CBN_SELCHANGE sent!\n"); 797 798 expected_list_text = text[list[4]]; 799 expected_edit_text = text[edit[4]]; 800 selchange_fired = FALSE; 801 SendMessageA(hCombo, CB_SETCURSEL, list[4], 0); 802 ok(!selchange_fired, "CBN_SELCHANGE sent!\n"); 803 804 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc); 805 DestroyWindow(hCombo); 806 } 807 808 static void test_combo_CBN_SELCHANGE(void) 809 { 810 static const char * const text[] = { "alpha", "beta", "" }; 811 static const int sel_1[] = { 2, 0, 1, 0, 1 }; 812 static const int sel_2[] = { 0, 1, 0, 0, 1 }; 813 814 test_selection(CBS_SIMPLE, text, sel_1, sel_2); 815 test_selection(CBS_DROPDOWN, text, sel_1, sel_2); 816 test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2); 817 } 818 819 static void test_combo_changesize(DWORD style) 820 { 821 INT ddheight, clheight, ddwidth, clwidth; 822 HWND hCombo; 823 RECT rc; 824 825 hCombo = create_combobox(style); 826 827 /* get initial measurements */ 828 GetClientRect( hCombo, &rc); 829 clheight = rc.bottom - rc.top; 830 clwidth = rc.right - rc.left; 831 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); 832 ddheight = rc.bottom - rc.top; 833 ddwidth = rc.right - rc.left; 834 /* use MoveWindow to move & resize the combo */ 835 /* first make it slightly smaller */ 836 MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE); 837 GetClientRect( hCombo, &rc); 838 ok( rc.right - rc.left == clwidth - 2, "clientrect width is %d vs %d\n", 839 rc.right - rc.left, clwidth - 2); 840 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", 841 rc.bottom - rc.top, clheight); 842 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); 843 ok( rc.right - rc.left == clwidth - 2, "drop-down rect width is %d vs %d\n", 844 rc.right - rc.left, clwidth - 2); 845 ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n", 846 rc.bottom - rc.top, ddheight); 847 ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n", 848 rc.right - rc.left, ddwidth - 2); 849 /* new cx, cy is slightly bigger than the initial values */ 850 MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE); 851 GetClientRect( hCombo, &rc); 852 ok( rc.right - rc.left == clwidth + 2, "clientrect width is %d vs %d\n", 853 rc.right - rc.left, clwidth + 2); 854 ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", 855 rc.bottom - rc.top, clheight); 856 SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); 857 ok( rc.right - rc.left == clwidth + 2, "drop-down rect width is %d vs %d\n", 858 rc.right - rc.left, clwidth + 2); 859 todo_wine { 860 ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n", 861 rc.bottom - rc.top, clheight + 2); 862 } 863 864 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0); 865 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 866 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 867 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 868 869 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0); 870 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 871 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 872 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 873 874 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0); 875 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 876 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 877 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 878 879 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0); 880 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); 881 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 882 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); 883 884 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0); 885 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); 886 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 887 ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1); 888 889 ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0); 890 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 891 ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0); 892 ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2); 893 894 DestroyWindow(hCombo); 895 } 896 897 static void test_combo_editselection(void) 898 { 899 COMBOBOXINFO cbInfo; 900 INT start, end; 901 char edit[20]; 902 HWND hCombo; 903 HWND hEdit; 904 DWORD len; 905 906 /* Build a combo */ 907 hCombo = create_combobox(CBS_SIMPLE); 908 909 get_combobox_info(hCombo, &cbInfo); 910 hEdit = cbInfo.hwndItem; 911 912 /* Initially combo selection is empty*/ 913 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 914 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); 915 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); 916 917 /* Set some text, and press a key to replace it */ 918 edit[0] = 0x00; 919 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1"); 920 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); 921 ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit); 922 923 /* Now what is the selection - still empty */ 924 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); 925 ok(start==0, "Unexpected start position for selection %d\n", start); 926 ok(end==0, "Unexpected end position for selection %d\n", end); 927 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 928 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); 929 ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len)); 930 931 /* Give it focus, and it gets selected */ 932 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); 933 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); 934 ok(start==0, "Unexpected start position for selection %d\n", start); 935 ok(end==6, "Unexpected end position for selection %d\n", end); 936 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 937 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); 938 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len)); 939 940 /* Now emulate a key press */ 941 edit[0] = 0x00; 942 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001); 943 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); 944 ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit); 945 946 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 947 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len)); 948 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len)); 949 950 /* Now what happens when it gets more focus a second time - it doesn't reselect */ 951 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); 952 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 953 ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len)); 954 ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len)); 955 DestroyWindow(hCombo); 956 957 /* Start again - Build a combo */ 958 hCombo = create_combobox(CBS_SIMPLE); 959 get_combobox_info(hCombo, &cbInfo); 960 hEdit = cbInfo.hwndItem; 961 962 /* Set some text and give focus so it gets selected */ 963 edit[0] = 0x00; 964 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2"); 965 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); 966 ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit); 967 968 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); 969 970 /* Now what is the selection */ 971 SendMessageA(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end); 972 ok(start==0, "Unexpected start position for selection %d\n", start); 973 ok(end==6, "Unexpected end position for selection %d\n", end); 974 len = SendMessageA(hCombo, CB_GETEDITSEL, 0,0); 975 ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len)); 976 ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len)); 977 978 /* Now change the selection to the apparently invalid start -1, end -1 and 979 show it means no selection (ie start -1) but cursor at end */ 980 SendMessageA(hCombo, CB_SETEDITSEL, 0, -1); 981 edit[0] = 0x00; 982 SendMessageA(hCombo, WM_CHAR, 'A', 0x1c0001); 983 SendMessageA(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit); 984 ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit); 985 DestroyWindow(hCombo); 986 } 987 988 static WNDPROC edit_window_proc; 989 static long setsel_start = 1, setsel_end = 1; 990 static HWND hCBN_SetFocus, hCBN_KillFocus; 991 992 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 993 { 994 if (msg == EM_SETSEL) 995 { 996 setsel_start = wParam; 997 setsel_end = lParam; 998 } 999 return CallWindowProcA(edit_window_proc, hwnd, msg, wParam, lParam); 1000 } 1001 1002 static LRESULT CALLBACK test_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 1003 { 1004 switch (msg) 1005 { 1006 case WM_COMMAND: 1007 switch (HIWORD(wParam)) 1008 { 1009 case CBN_SETFOCUS: 1010 hCBN_SetFocus = (HWND)lParam; 1011 break; 1012 case CBN_KILLFOCUS: 1013 hCBN_KillFocus = (HWND)lParam; 1014 break; 1015 } 1016 break; 1017 case WM_NEXTDLGCTL: 1018 SetFocus((HWND)wParam); 1019 break; 1020 } 1021 return CallWindowProcA(old_parent_proc, hwnd, msg, wParam, lParam); 1022 } 1023 1024 static void test_combo_editselection_focus(DWORD style) 1025 { 1026 static const char wine_test[] = "Wine Test"; 1027 HWND hCombo, hEdit, hButton; 1028 char buffer[16] = {0}; 1029 COMBOBOXINFO cbInfo; 1030 DWORD len; 1031 1032 hCombo = create_combobox(style); 1033 get_combobox_info(hCombo, &cbInfo); 1034 hEdit = cbInfo.hwndItem; 1035 1036 hButton = CreateWindowA("Button", "OK", WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 1037 5, 50, 100, 20, hMainWnd, NULL, 1038 (HINSTANCE)GetWindowLongPtrA(hMainWnd, GWLP_HINSTANCE), NULL); 1039 1040 old_parent_proc = (WNDPROC)SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)test_window_proc); 1041 edit_window_proc = (WNDPROC)SetWindowLongPtrA(hEdit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc); 1042 1043 SendMessageA(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit); 1044 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); 1045 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); 1046 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus); 1047 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n"); 1048 1049 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE); 1050 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); 1051 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); 1052 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus); 1053 ok(GetFocus() == hButton, "hButton should have keyboard focus\n"); 1054 1055 SendMessageA(hCombo, WM_SETTEXT, 0, (LPARAM)wine_test); 1056 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hCombo, TRUE); 1057 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); 1058 todo_wine ok(setsel_end == INT_MAX, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); 1059 ok(hCBN_SetFocus == hCombo, "Wrong handle set by CBN_SETFOCUS; got %p\n", hCBN_SetFocus); 1060 ok(GetFocus() == hEdit, "hEdit should have keyboard focus\n"); 1061 SendMessageA(hCombo, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); 1062 ok(!strcmp(buffer, wine_test), "Unexpected text in edit control; got '%s'\n", buffer); 1063 1064 SendMessageA(hMainWnd, WM_NEXTDLGCTL, (WPARAM)hButton, TRUE); 1065 ok(setsel_start == 0, "Unexpected EM_SETSEL start value; got %ld\n", setsel_start); 1066 todo_wine ok(setsel_end == 0, "Unexpected EM_SETSEL end value; got %ld\n", setsel_end); 1067 ok(hCBN_KillFocus == hCombo, "Wrong handle set by CBN_KILLFOCUS; got %p\n", hCBN_KillFocus); 1068 ok(GetFocus() == hButton, "hButton should have keyboard focus\n"); 1069 len = SendMessageA(hCombo, CB_GETEDITSEL, 0, 0); 1070 ok(len == 0, "Unexpected text selection; start: %u, end: %u\n", LOWORD(len), HIWORD(len)); 1071 1072 SetWindowLongPtrA(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc); 1073 DestroyWindow(hButton); 1074 DestroyWindow(hCombo); 1075 } 1076 1077 static void test_combo_listbox_styles(DWORD cb_style) 1078 { 1079 DWORD style, exstyle, expect_style, expect_exstyle; 1080 COMBOBOXINFO info; 1081 HWND combo; 1082 1083 expect_style = WS_CHILD|WS_CLIPSIBLINGS|LBS_COMBOBOX|LBS_HASSTRINGS|LBS_NOTIFY; 1084 if (cb_style == CBS_SIMPLE) 1085 { 1086 expect_style |= WS_VISIBLE; 1087 expect_exstyle = WS_EX_CLIENTEDGE; 1088 } 1089 else 1090 { 1091 expect_style |= WS_BORDER; 1092 expect_exstyle = WS_EX_TOOLWINDOW; 1093 } 1094 1095 combo = create_combobox(cb_style); 1096 get_combobox_info(combo, &info); 1097 1098 style = GetWindowLongW( info.hwndList, GWL_STYLE ); 1099 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); 1100 ok(style == expect_style, "%08x: got %08x\n", cb_style, style); 1101 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); 1102 1103 if (cb_style != CBS_SIMPLE) 1104 expect_exstyle |= WS_EX_TOPMOST; 1105 1106 SendMessageW(combo, CB_SHOWDROPDOWN, TRUE, 0 ); 1107 style = GetWindowLongW( info.hwndList, GWL_STYLE ); 1108 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); 1109 ok(style == (expect_style | WS_VISIBLE), "%08x: got %08x\n", cb_style, style); 1110 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); 1111 1112 SendMessageW(combo, CB_SHOWDROPDOWN, FALSE, 0 ); 1113 style = GetWindowLongW( info.hwndList, GWL_STYLE ); 1114 exstyle = GetWindowLongW( info.hwndList, GWL_EXSTYLE ); 1115 ok(style == expect_style, "%08x: got %08x\n", cb_style, style); 1116 ok(exstyle == expect_exstyle, "%08x: got %08x\n", cb_style, exstyle); 1117 1118 DestroyWindow(combo); 1119 } 1120 1121 static void test_combo_WS_VSCROLL(void) 1122 { 1123 HWND hCombo, hList; 1124 COMBOBOXINFO info; 1125 DWORD style; 1126 int i; 1127 1128 hCombo = create_combobox(CBS_DROPDOWNLIST); 1129 1130 get_combobox_info(hCombo, &info); 1131 hList = info.hwndList; 1132 1133 for (i = 0; i < 3; i++) 1134 { 1135 char buffer[2]; 1136 sprintf(buffer, "%d", i); 1137 SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer); 1138 } 1139 1140 style = GetWindowLongA(info.hwndList, GWL_STYLE); 1141 SetWindowLongA(hList, GWL_STYLE, style | WS_VSCROLL); 1142 1143 SendMessageA(hCombo, CB_SHOWDROPDOWN, TRUE, 0); 1144 SendMessageA(hCombo, CB_SHOWDROPDOWN, FALSE, 0); 1145 1146 style = GetWindowLongA(hList, GWL_STYLE); 1147 ok((style & WS_VSCROLL) != 0, "Style does not include WS_VSCROLL\n"); 1148 1149 DestroyWindow(hCombo); 1150 } 1151 1152 START_TEST(combo) 1153 { 1154 ULONG_PTR ctx_cookie; 1155 HANDLE hCtx; 1156 1157 if (!init()) 1158 return; 1159 1160 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 1161 1162 /* ComboBoxEx32 tests. */ 1163 test_comboex(); 1164 test_comboex_WM_LBUTTONDOWN(); 1165 test_comboex_CB_GETLBTEXT(); 1166 test_comboex_WM_WINDOWPOSCHANGING(); 1167 test_comboex_subclass(); 1168 test_comboex_get_set_item(); 1169 1170 if (!load_v6_module(&ctx_cookie, &hCtx)) 1171 { 1172 cleanup(); 1173 return; 1174 } 1175 1176 /* ComboBox control tests. */ 1177 test_combo_WS_VSCROLL(); 1178 test_combo_setfont(CBS_DROPDOWN); 1179 test_combo_setfont(CBS_DROPDOWNLIST); 1180 test_combo_setitemheight(CBS_DROPDOWN); 1181 test_combo_setitemheight(CBS_DROPDOWNLIST); 1182 test_combo_CBN_SELCHANGE(); 1183 test_combo_changesize(CBS_DROPDOWN); 1184 test_combo_changesize(CBS_DROPDOWNLIST); 1185 test_combo_editselection(); 1186 test_combo_editselection_focus(CBS_SIMPLE); 1187 test_combo_editselection_focus(CBS_DROPDOWN); 1188 test_combo_listbox_styles(CBS_SIMPLE); 1189 test_combo_listbox_styles(CBS_DROPDOWN); 1190 test_combo_listbox_styles(CBS_DROPDOWNLIST); 1191 1192 cleanup(); 1193 unload_v6_module(ctx_cookie, hCtx); 1194 } 1195