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