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