user32: IsDialogMessage should allow control ids other than IDOK when processing...
[wine] / dlls / user32 / tests / combo.c
1 /* Unit test suite for combo boxes.
2  *
3  * Copyright 2007 Mikolaj Zalewski
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdarg.h>
21 #include <stdio.h>
22
23 #define STRICT
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26
27 #include "wine/test.h"
28
29 #define COMBO_ID 1995
30
31 static HWND hMainWnd;
32
33 #define expect_eq(expr, value, type, fmt); { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); }
34 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
35     r.bottom == _bottom && r.right == _right, "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", \
36     r.left, r.top, r.right, r.bottom, _left, _top, _right, _bottom);
37
38 static HWND build_combo(DWORD style)
39 {
40     return CreateWindow("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|style, 5, 5, 100, 100, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
41 }
42
43 static int font_height(HFONT hFont)
44 {
45     TEXTMETRIC tm;
46     HFONT hFontOld;
47     HDC hDC;
48
49     hDC = CreateCompatibleDC(NULL);
50     hFontOld = SelectObject(hDC, hFont);
51     GetTextMetrics(hDC, &tm);
52     SelectObject(hDC, hFontOld);
53     DeleteDC(hDC);
54
55     return tm.tmHeight;
56 }
57
58 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
59 {
60     return 0;
61 }
62
63 static int is_font_installed(const char *name)
64 {
65     HDC hdc = GetDC(NULL);
66     BOOL ret = !EnumFontFamilies(hdc, name, is_font_installed_proc, 0);
67     ReleaseDC(NULL, hdc);
68     return ret;
69 }
70
71 static void test_setitemheight(DWORD style)
72 {
73     HWND hCombo = build_combo(style);
74     RECT r;
75     int i;
76
77     trace("Style %x\n", style);
78     GetClientRect(hCombo, &r);
79     expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
80     SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
81     MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
82     todo_wine expect_rect(r, 5, 5, 105, 105);
83
84     for (i = 1; i < 30; i++)
85     {
86         SendMessage(hCombo, CB_SETITEMHEIGHT, -1, i);
87         GetClientRect(hCombo, &r);
88         expect_eq(r.bottom - r.top, i + 6, int, "%d");
89     }
90
91     DestroyWindow(hCombo);
92 }
93
94 static void test_setfont(DWORD style)
95 {
96     HWND hCombo;
97     HFONT hFont1, hFont2;
98     RECT r;
99     int i;
100
101     if (!is_font_installed("Marlett"))
102     {
103         skip("Marlett font not available\n");
104         return;
105     }
106
107     trace("Style %x\n", style);
108
109     hCombo = build_combo(style);
110     hFont1 = CreateFont(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
111     hFont2 = CreateFont(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
112
113     GetClientRect(hCombo, &r);
114     expect_rect(r, 0, 0, 100, font_height(GetStockObject(SYSTEM_FONT)) + 8);
115     SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
116     MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
117     todo_wine expect_rect(r, 5, 5, 105, 105);
118
119     /* The size of the dropped control is initially equal to the size
120        of the window when it was created.  The size of the calculated
121        dropped area changes only by how much the selection area
122        changes, not by how much the list area changes.  */
123     if (font_height(hFont1) == 10 && font_height(hFont2) == 8)
124     {
125         SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
126         GetClientRect(hCombo, &r);
127         expect_rect(r, 0, 0, 100, 18);
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(hFont1)));
131
132         SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE);
133         GetClientRect(hCombo, &r);
134         expect_rect(r, 0, 0, 100, 16);
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(hFont2)));
138
139         SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE);
140         GetClientRect(hCombo, &r);
141         expect_rect(r, 0, 0, 100, 18);
142         SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r);
143         MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
144         todo_wine expect_rect(r, 5, 5, 105, 105 - (font_height(GetStockObject(SYSTEM_FONT)) - font_height(hFont1)));
145     }
146     else
147     {
148         ok(0, "Expected Marlett font heights 10/8, got %d/%d\n",
149            font_height(hFont1), font_height(hFont2));
150     }
151
152     for (i = 1; i < 30; i++)
153     {
154         HFONT hFont = CreateFont(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett");
155         int height = font_height(hFont);
156
157         SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE);
158         GetClientRect(hCombo, &r);
159         expect_eq(r.bottom - r.top, height + 8, int, "%d");
160         SendMessage(hCombo, WM_SETFONT, 0, FALSE);
161         DeleteObject(hFont);
162     }
163
164     DestroyWindow(hCombo);
165     DeleteObject(hFont1);
166     DeleteObject(hFont2);
167 }
168
169 static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
170 static LPCSTR expected_edit_text;
171 static LPCSTR expected_list_text;
172 static BOOL selchange_fired;
173
174 static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
175 {
176     switch (msg)
177     {
178     case WM_COMMAND:
179         switch (wparam)
180         {
181             case MAKEWPARAM(COMBO_ID, CBN_SELCHANGE):
182             {
183                 HWND hCombo = (HWND)lparam;
184                 int idx;
185                 char list[20], edit[20];
186
187                 memset(list, 0, sizeof(list));
188                 memset(edit, 0, sizeof(edit));
189
190                 idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
191                 SendMessage(hCombo, CB_GETLBTEXT, idx, (LPARAM)list);
192                 SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
193
194                 ok(!strcmp(edit, expected_edit_text), "edit: got %s, expected %s\n",
195                    edit, expected_edit_text);
196                 ok(!strcmp(list, expected_list_text), "list: got %s, expected %s\n",
197                    list, expected_list_text);
198
199                 selchange_fired = TRUE;
200             }
201             break;
202         }
203         break;
204     }
205
206     return CallWindowProc(old_parent_proc, hwnd, msg, wparam, lparam);
207 }
208
209 static void test_selection(DWORD style, const char * const text[],
210                            const int *edit, const int *list)
211 {
212     INT idx;
213     HWND hCombo;
214
215     hCombo = build_combo(style);
216
217     SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)text[0]);
218     SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)text[1]);
219     SendMessage(hCombo, CB_SETCURSEL, -1, 0);
220
221     old_parent_proc = (void *)SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)parent_wnd_proc);
222
223     idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
224     ok(idx == -1, "expected selection -1, got %d\n", idx);
225
226     /* keyboard navigation */
227
228     expected_list_text = text[list[0]];
229     expected_edit_text = text[edit[0]];
230     selchange_fired = FALSE;
231     SendMessage(hCombo, WM_KEYDOWN, VK_DOWN, 0);
232     ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
233
234     expected_list_text = text[list[1]];
235     expected_edit_text = text[edit[1]];
236     selchange_fired = FALSE;
237     SendMessage(hCombo, WM_KEYDOWN, VK_DOWN, 0);
238     ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
239
240     expected_list_text = text[list[2]];
241     expected_edit_text = text[edit[2]];
242     selchange_fired = FALSE;
243     SendMessage(hCombo, WM_KEYDOWN, VK_UP, 0);
244     ok(selchange_fired, "CBN_SELCHANGE not sent!\n");
245
246     /* programmatic navigation */
247
248     expected_list_text = text[list[3]];
249     expected_edit_text = text[edit[3]];
250     selchange_fired = FALSE;
251     SendMessage(hCombo, CB_SETCURSEL, list[3], 0);
252     ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
253
254     expected_list_text = text[list[4]];
255     expected_edit_text = text[edit[4]];
256     selchange_fired = FALSE;
257     SendMessage(hCombo, CB_SETCURSEL, list[4], 0);
258     ok(!selchange_fired, "CBN_SELCHANGE sent!\n");
259
260     SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, (ULONG_PTR)old_parent_proc);
261     DestroyWindow(hCombo);
262 }
263
264 static void test_CBN_SELCHANGE(void)
265 {
266     static const char * const text[] = { "alpha", "beta", "" };
267     static const int sel_1[] = { 2, 0, 1, 0, 1 };
268     static const int sel_2[] = { 0, 1, 0, 0, 1 };
269
270     test_selection(CBS_SIMPLE, text, sel_1, sel_2);
271     test_selection(CBS_DROPDOWN, text, sel_1, sel_2);
272     test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
273 }
274
275 static void test_WM_LBUTTONDOWN(void)
276 {
277     HWND hCombo, hEdit, hList;
278     COMBOBOXINFO cbInfo;
279     UINT x, y, item_height;
280     LRESULT result;
281     int i, idx;
282     RECT rect;
283     CHAR buffer[3];
284     static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
285     static const CHAR stringFormat[] = "%2d";
286     BOOL ret;
287     BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
288
289     pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
290     if (!pGetComboBoxInfo){
291         win_skip("GetComboBoxInfo is not available\n");
292         return;
293     }
294
295     hCombo = CreateWindow("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|CBS_DROPDOWN,
296             0, 0, 200, 150, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
297
298     for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
299         sprintf(buffer, stringFormat, choices[i]);
300         result = SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer);
301         ok(result == i,
302            "Failed to add item %d\n", i);
303     }
304
305     cbInfo.cbSize = sizeof(COMBOBOXINFO);
306     SetLastError(0xdeadbeef);
307     ret = pGetComboBoxInfo(hCombo, &cbInfo);
308     ok(ret, "Failed to get combobox info structure. LastError=%d\n",
309        GetLastError());
310     hEdit = cbInfo.hwndItem;
311     hList = cbInfo.hwndList;
312
313     trace("hMainWnd=%p, hCombo=%p, hList=%p, hEdit=%p\n", hMainWnd, hCombo, hList, hEdit);
314     ok(GetFocus() == hMainWnd, "Focus not on Main Window, instead on %p\n", GetFocus());
315
316     /* Click on the button to drop down the list */
317     x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
318     y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
319     result = SendMessage(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
320     ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
321        GetLastError());
322     ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
323        "The dropdown list should have appeared after clicking the button.\n");
324
325     ok(GetFocus() == hEdit,
326        "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
327     result = SendMessage(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
328     ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
329        GetLastError());
330     ok(GetFocus() == hEdit,
331        "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
332
333     /* Click on the 5th item in the list */
334     item_height = SendMessage(hCombo, CB_GETITEMHEIGHT, 0, 0);
335     ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
336     x = rect.left + (rect.right-rect.left)/2;
337     y = item_height/2 + item_height*4;
338     result = SendMessage(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
339     ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
340        GetLastError());
341     ok(GetFocus() == hEdit,
342        "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
343
344     result = SendMessage(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
345     ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
346        GetLastError());
347     ok(GetFocus() == hEdit,
348        "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
349     ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
350        "The dropdown list should still be visible.\n");
351
352     result = SendMessage(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
353     ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
354        GetLastError());
355     ok(GetFocus() == hEdit,
356        "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus());
357     ok(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
358        "The dropdown list should have been rolled up.\n");
359     idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
360     ok(idx, "Current Selection: expected %d, got %d\n", 4, idx);
361
362     DestroyWindow(hCombo);
363 }
364
365 static void test_changesize( DWORD style)
366 {
367     HWND hCombo = build_combo(style);
368     RECT rc;
369     INT ddheight, clheight, ddwidth, clwidth;
370     /* get initial measurements */
371     GetClientRect( hCombo, &rc);
372     clheight = rc.bottom - rc.top;
373     clwidth = rc.right - rc.left;
374     SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
375     ddheight = rc.bottom - rc.top;
376     ddwidth = rc.right - rc.left;
377     /* use MoveWindow to move & resize the combo */
378     /* first make it slightly smaller */
379     MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE);
380     GetClientRect( hCombo, &rc);
381     ok( rc.right - rc.left == clwidth - 2, "clientrect witdh is %d vs %d\n",
382             rc.right - rc.left, clwidth - 2);
383     ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
384                 rc.bottom - rc.top, clheight);
385     SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
386     ok( rc.right - rc.left == clwidth - 2, "drop-down rect witdh is %d vs %d\n",
387             rc.right - rc.left, clwidth - 2);
388     ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n",
389             rc.bottom - rc.top, ddheight);
390     ok( rc.right - rc.left == ddwidth -2, "drop-down rect width is %d vs %d\n",
391             rc.right - rc.left, ddwidth - 2);
392     /* new cx, cy is slightly bigger than the initial values */
393     MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE);
394     GetClientRect( hCombo, &rc);
395     ok( rc.right - rc.left == clwidth + 2, "clientrect witdh is %d vs %d\n",
396             rc.right - rc.left, clwidth + 2);
397     ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n",
398             rc.bottom - rc.top, clheight);
399     SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc);
400     ok( rc.right - rc.left == clwidth + 2, "drop-down rect witdh is %d vs %d\n",
401             rc.right - rc.left, clwidth + 2);
402     todo_wine {
403         ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n",
404                 rc.bottom - rc.top, clheight + 2);
405     }
406
407     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, -1, 0);
408     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
409     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
410     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
411
412     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
413     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
414     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
415     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
416
417     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth - 1, 0);
418     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
419     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
420     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
421
422     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, clwidth << 1, 0);
423     ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
424     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
425     ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
426
427     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 0, 0);
428     ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
429     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
430     ok( ddwidth == (clwidth << 1), "drop-width is %d vs %d\n", ddwidth, clwidth << 1);
431
432     ddwidth = SendMessageA(hCombo, CB_SETDROPPEDWIDTH, 1, 0);
433     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
434     ddwidth = SendMessageA(hCombo, CB_GETDROPPEDWIDTH, 0, 0);
435     ok( ddwidth == clwidth + 2, "drop-width is %d vs %d\n", ddwidth, clwidth + 2);
436
437     DestroyWindow(hCombo);
438 }
439
440 static void test_editselection(void)
441 {
442     HWND hCombo;
443     INT start,end;
444     HWND hEdit;
445     COMBOBOXINFO cbInfo;
446     BOOL ret;
447     DWORD len;
448     BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
449     char edit[20];
450
451     pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
452     if (!pGetComboBoxInfo){
453         win_skip("GetComboBoxInfo is not available\n");
454         return;
455     }
456
457     /* Build a combo */
458     hCombo = build_combo(CBS_SIMPLE);
459     cbInfo.cbSize = sizeof(COMBOBOXINFO);
460     SetLastError(0xdeadbeef);
461     ret = pGetComboBoxInfo(hCombo, &cbInfo);
462     ok(ret, "Failed to get combobox info structure. LastError=%d\n",
463        GetLastError());
464     hEdit = cbInfo.hwndItem;
465
466     /* Initially combo selection is empty*/
467     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
468     ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
469     ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
470
471     /* Set some text, and press a key to replace it */
472     edit[0] = 0x00;
473     SendMessage(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason1");
474     SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
475     ok(strcmp(edit, "Jason1")==0, "Unexpected text retrieved %s\n", edit);
476
477     /* Now what is the selection - still empty */
478     SendMessage(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
479     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
480     ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
481     ok(HIWORD(len)==0, "Unexpected end position for selection %d\n", HIWORD(len));
482
483     /* Give it focus, and it gets selected */
484     SendMessage(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
485     SendMessage(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
486     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
487     ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
488     ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
489
490     /* Now emulate a key press */
491     edit[0] = 0x00;
492     SendMessage(hCombo, WM_CHAR, 'A', 0x1c0001);
493     SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
494     ok(strcmp(edit, "A")==0, "Unexpected text retrieved %s\n", edit);
495
496     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
497     ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
498     ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
499
500     /* Now what happens when it gets more focus a second time - it doesn't reselect */
501     SendMessage(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
502     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
503     ok(LOWORD(len)==1, "Unexpected start position for selection %d\n", LOWORD(len));
504     ok(HIWORD(len)==1, "Unexpected end position for selection %d\n", HIWORD(len));
505     DestroyWindow(hCombo);
506
507     /* Start again - Build a combo */
508     hCombo = build_combo(CBS_SIMPLE);
509     cbInfo.cbSize = sizeof(COMBOBOXINFO);
510     SetLastError(0xdeadbeef);
511     ret = pGetComboBoxInfo(hCombo, &cbInfo);
512     ok(ret, "Failed to get combobox info structure. LastError=%d\n",
513        GetLastError());
514     hEdit = cbInfo.hwndItem;
515
516     /* Set some text and give focus so it gets selected */
517     edit[0] = 0x00;
518     SendMessage(hCombo, WM_SETTEXT, 0, (LPARAM)"Jason2");
519     SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
520     ok(strcmp(edit, "Jason2")==0, "Unexpected text retrieved %s\n", edit);
521
522     SendMessage(hCombo, WM_SETFOCUS, 0, (LPARAM)hEdit);
523
524     /* Now what is the selection */
525     SendMessage(hCombo, CB_GETEDITSEL, (WPARAM)&start, (WPARAM)&end);
526     len = SendMessage(hCombo, CB_GETEDITSEL, 0,0);
527     ok(LOWORD(len)==0, "Unexpected start position for selection %d\n", LOWORD(len));
528     ok(HIWORD(len)==6, "Unexpected end position for selection %d\n", HIWORD(len));
529
530     /* Now change the selection to the apparently invalid start -1, end -1 and
531        show it means no selection (ie start -1) but cursor at end              */
532     SendMessage(hCombo, CB_SETEDITSEL, 0, -1);
533     edit[0] = 0x00;
534     SendMessage(hCombo, WM_CHAR, 'A', 0x1c0001);
535     SendMessage(hCombo, WM_GETTEXT, sizeof(edit), (LPARAM)edit);
536     ok(strcmp(edit, "Jason2A")==0, "Unexpected text retrieved %s\n", edit);
537     DestroyWindow(hCombo);
538 }
539
540 START_TEST(combo)
541 {
542     hMainWnd = CreateWindow("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
543     ShowWindow(hMainWnd, SW_SHOW);
544
545     test_setfont(CBS_DROPDOWN);
546     test_setfont(CBS_DROPDOWNLIST);
547     test_setitemheight(CBS_DROPDOWN);
548     test_setitemheight(CBS_DROPDOWNLIST);
549     test_CBN_SELCHANGE();
550     test_WM_LBUTTONDOWN();
551     test_changesize(CBS_DROPDOWN);
552     test_changesize(CBS_DROPDOWNLIST);
553     test_editselection();
554
555     DestroyWindow(hMainWnd);
556 }