comctl32/tests: Accept touchscreen-related messages in button tests.
[wine.git] / dlls / comctl32 / tests / button.c
blob9977ce17e905c50031687c2bcbeab2f8884ebe58
1 /* Unit test suite for Button control.
3 * Copyright 1999 Ove Kaaven
4 * Copyright 2003 Dimitrie O. Paun
5 * Copyright 2004, 2005 Dmitry Timoshkov
6 * Copyright 2014 Nikolay Sivov for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <windows.h>
24 #include <commctrl.h>
26 #include "wine/test.h"
27 #include "v6util.h"
28 #include "msg.h"
30 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
32 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
33 static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
34 static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
36 /****************** button message test *************************/
37 #define ID_BUTTON 0x000e
39 #define COMBINED_SEQ_INDEX 0
40 #define NUM_MSG_SEQUENCES 1
42 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
44 struct wndclass_redirect_data
46 ULONG size;
47 DWORD res;
48 ULONG name_len;
49 ULONG name_offset;
50 ULONG module_len;
51 ULONG module_offset;
54 /* returned pointer is valid as long as activation context is alive */
55 static WCHAR* get_versioned_classname(const WCHAR *name)
57 BOOL (WINAPI *pFindActCtxSectionStringW)(DWORD,const GUID *,ULONG,LPCWSTR,PACTCTX_SECTION_KEYED_DATA);
58 struct wndclass_redirect_data *wnddata;
59 ACTCTX_SECTION_KEYED_DATA data;
60 BOOL ret;
62 pFindActCtxSectionStringW = (void*)GetProcAddress(GetModuleHandleA("kernel32"), "FindActCtxSectionStringW");
64 memset(&data, 0, sizeof(data));
65 data.cbSize = sizeof(data);
67 ret = pFindActCtxSectionStringW(0, NULL,
68 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
69 name, &data);
70 ok(ret, "got %d, error %u\n", ret, GetLastError());
71 wnddata = (struct wndclass_redirect_data*)data.lpData;
72 return (WCHAR*)((BYTE*)wnddata + wnddata->name_offset);
75 static void init_functions(void)
77 HMODULE hmod = GetModuleHandleA("comctl32.dll");
78 ok(hmod != NULL, "got %p\n", hmod);
80 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
81 MAKEFUNC_ORD(SetWindowSubclass, 410);
82 MAKEFUNC_ORD(RemoveWindowSubclass, 412);
83 MAKEFUNC_ORD(DefSubclassProc, 413);
84 #undef MAKEFUNC_ORD
87 /* try to make sure pending X events have been processed before continuing */
88 static void flush_events(void)
90 MSG msg;
91 int diff = 200;
92 int min_timeout = 100;
93 DWORD time = GetTickCount() + diff;
95 while (diff > 0)
97 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
98 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
99 diff = time - GetTickCount();
103 static BOOL ignore_message( UINT message )
105 /* these are always ignored */
106 return (message >= 0xc000 ||
107 message == WM_GETICON ||
108 message == WM_GETOBJECT ||
109 message == WM_TIMECHANGE ||
110 message == WM_DISPLAYCHANGE ||
111 message == WM_DEVICECHANGE ||
112 message == WM_DWMNCRENDERINGCHANGED ||
113 message == WM_GETTEXTLENGTH ||
114 message == WM_GETTEXT);
117 static LRESULT CALLBACK button_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR ref_data)
119 static LONG defwndproc_counter = 0;
120 LRESULT ret;
121 struct message msg;
123 if (ignore_message( message )) return pDefSubclassProc(hwnd, message, wParam, lParam);
125 switch (message)
127 case WM_SYNCPAINT:
128 break;
129 case BM_SETSTATE:
130 if (GetCapture())
131 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
132 /* fall through */
133 default:
134 msg.message = message;
135 msg.flags = sent|wparam|lparam;
136 if (defwndproc_counter) msg.flags |= defwinproc;
137 msg.wParam = wParam;
138 msg.lParam = lParam;
139 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
142 if (message == WM_NCDESTROY)
143 pRemoveWindowSubclass(hwnd, button_subclass_proc, 0);
145 defwndproc_counter++;
146 ret = pDefSubclassProc(hwnd, message, wParam, lParam);
147 defwndproc_counter--;
149 return ret;
152 static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
154 static LONG defwndproc_counter = 0;
155 static LONG beginpaint_counter = 0;
156 LRESULT ret;
157 struct message msg;
159 if (ignore_message( message )) return 0;
161 if (message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
162 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
163 message == WM_ENABLE || message == WM_ENTERIDLE ||
164 message == WM_DRAWITEM || message == WM_COMMAND ||
165 message == WM_IME_SETCONTEXT)
167 switch (message)
169 /* ignore */
170 case WM_NCHITTEST:
171 return HTCLIENT;
172 case WM_SETCURSOR:
173 case WM_MOUSEMOVE:
174 case WM_NCMOUSEMOVE:
175 return 0;
178 msg.message = message;
179 msg.flags = sent|parent|wparam|lparam;
180 if (defwndproc_counter) msg.flags |= defwinproc;
181 if (beginpaint_counter) msg.flags |= beginpaint;
182 msg.wParam = wParam;
183 msg.lParam = lParam;
184 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
187 if (message == WM_PAINT)
189 PAINTSTRUCT ps;
190 beginpaint_counter++;
191 BeginPaint( hwnd, &ps );
192 beginpaint_counter--;
193 EndPaint( hwnd, &ps );
194 return 0;
197 defwndproc_counter++;
198 ret = DefWindowProcA(hwnd, message, wParam, lParam);
199 defwndproc_counter--;
201 return ret;
204 static const struct message setfocus_seq[] =
206 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
207 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
208 { BM_GETSTATE, sent|optional }, /* when touchscreen is present */
209 { WM_SETFOCUS, sent|wparam },
210 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
211 { WM_APP, sent|wparam|lparam },
212 { WM_PAINT, sent },
213 { 0 }
216 static const struct message killfocus_seq[] =
218 { WM_KILLFOCUS, sent|wparam, 0 },
219 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
220 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
221 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
222 { WM_APP, sent|wparam|lparam, 0, 0 },
223 { WM_PAINT, sent },
224 { 0 }
227 static const struct message setfocus_static_seq[] =
229 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
230 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
231 { BM_GETSTATE, sent|optional }, /* when touchscreen is present */
232 { WM_SETFOCUS, sent|wparam, 0 },
233 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
234 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
235 { WM_APP, sent|wparam|lparam, 0, 0 },
236 { WM_PAINT, sent },
237 { 0 }
240 static const struct message setfocus_groupbox_seq[] =
242 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
243 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
244 { BM_GETSTATE, sent|optional }, /* when touchscreen is present */
245 { WM_SETFOCUS, sent|wparam, 0 },
246 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
247 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
248 { WM_APP, sent|wparam|lparam, 0, 0 },
249 { WM_PAINT, sent },
250 { 0 }
253 static const struct message killfocus_static_seq[] =
255 { WM_KILLFOCUS, sent|wparam, 0 },
256 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
257 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
258 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
259 { WM_APP, sent|wparam|lparam, 0, 0 },
260 { WM_PAINT, sent },
261 { 0 }
264 static const struct message setfocus_ownerdraw_seq[] =
266 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
267 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
268 { BM_GETSTATE, sent|optional }, /* when touchscreen is present */
269 { WM_SETFOCUS, sent|wparam, 0 },
270 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
271 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
272 { WM_APP, sent|wparam|lparam, 0, 0 },
273 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
274 { 0 }
277 static const struct message killfocus_ownerdraw_seq[] =
279 { WM_KILLFOCUS, sent|wparam, 0 },
280 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
281 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
282 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
283 { WM_APP, sent|wparam|lparam, 0, 0 },
284 { WM_PAINT, sent },
285 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
286 { 0 }
289 static const struct message lbuttondown_seq[] =
291 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
292 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
293 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
294 { BM_GETSTATE, sent|defwinproc|optional }, /* when touchscreen is present */
295 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
296 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
297 { 0 }
300 static const struct message lbuttonup_seq[] =
302 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
303 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
304 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
305 { WM_COMMAND, sent|wparam|defwinproc, 0 },
306 { 0 }
309 static const struct message setfont_seq[] =
311 { WM_SETFONT, sent },
312 { 0 }
315 static const struct message setstyle_seq[] =
317 { BM_SETSTYLE, sent },
318 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
319 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
320 { WM_APP, sent|wparam|lparam, 0, 0 },
321 { WM_PAINT, sent },
322 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
323 { WM_ERASEBKGND, sent|defwinproc|optional },
324 { WM_PAINT, sent|optional },
325 { 0 }
328 static const struct message setstyle_static_seq[] =
330 { BM_SETSTYLE, sent },
331 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
332 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
333 { WM_APP, sent|wparam|lparam, 0, 0 },
334 { WM_PAINT, sent },
335 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
336 { WM_ERASEBKGND, sent|defwinproc|optional },
337 { 0 }
340 static const struct message setstyle_user_seq[] =
342 { BM_SETSTYLE, sent },
343 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
344 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
345 { WM_APP, sent|wparam|lparam, 0, 0 },
346 { WM_PAINT, sent },
347 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
348 { WM_ERASEBKGND, sent|defwinproc|optional },
349 { 0 }
352 static const struct message setstyle_ownerdraw_seq[] =
354 { BM_SETSTYLE, sent },
355 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
356 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
357 { WM_APP, sent|wparam|lparam, 0, 0 },
358 { WM_PAINT, sent },
359 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
360 { WM_ERASEBKGND, sent|defwinproc|optional },
361 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
362 { 0 }
365 static const struct message setstate_seq[] =
367 { BM_SETSTATE, sent },
368 { WM_APP, sent|wparam|lparam, 0, 0 },
369 { WM_PAINT, sent },
370 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
371 { WM_ERASEBKGND, sent|defwinproc|optional },
372 { WM_PAINT, sent|optional },
373 { 0 }
376 static const struct message setstate_static_seq[] =
378 { BM_SETSTATE, sent },
379 { WM_APP, sent|wparam|lparam, 0, 0 },
380 { WM_PAINT, sent },
381 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
382 { WM_ERASEBKGND, sent|defwinproc|optional },
383 { 0 }
386 static const struct message setstate_user_seq[] =
388 { BM_SETSTATE, sent },
389 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
390 { WM_APP, sent|wparam|lparam, 0, 0 },
391 { WM_PAINT, sent },
392 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
393 { WM_ERASEBKGND, sent|defwinproc|optional },
394 { 0 }
397 static const struct message setstate_ownerdraw_seq[] =
399 { BM_SETSTATE, sent },
400 { WM_APP, sent|wparam|lparam, 0, 0 },
401 { WM_PAINT, sent },
402 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
403 { WM_ERASEBKGND, sent|defwinproc|optional },
404 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
405 { 0 }
408 static const struct message clearstate_seq[] =
410 { BM_SETSTATE, sent },
411 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
412 { WM_APP, sent|wparam|lparam, 0, 0 },
413 { WM_PAINT, sent },
414 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
415 { WM_ERASEBKGND, sent|defwinproc|optional },
416 { 0 }
419 static const struct message clearstate_ownerdraw_seq[] =
421 { BM_SETSTATE, sent },
422 { WM_APP, sent|wparam|lparam, 0, 0 },
423 { WM_PAINT, sent },
424 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
425 { WM_ERASEBKGND, sent|defwinproc|optional },
426 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
427 { 0 }
430 static const struct message setcheck_ignored_seq[] =
432 { BM_SETCHECK, sent },
433 { WM_APP, sent|wparam|lparam, 0, 0 },
434 { WM_PAINT, sent|optional },
435 { 0 }
438 static const struct message setcheck_static_seq[] =
440 { BM_SETCHECK, sent },
441 { WM_APP, sent|wparam|lparam, 0, 0 },
442 { WM_PAINT, sent },
443 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
444 { WM_ERASEBKGND, sent|defwinproc|optional },
445 { 0 }
448 static const struct message setcheck_radio_seq[] =
450 { BM_SETCHECK, sent },
451 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
452 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
453 { WM_APP, sent|wparam|lparam, 0, 0 },
454 { 0 }
457 static const struct message setcheck_radio_redraw_seq[] =
459 { BM_SETCHECK, sent },
460 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
461 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
462 { WM_APP, sent|wparam|lparam, 0, 0 },
463 { WM_PAINT, sent },
464 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
465 { WM_ERASEBKGND, sent|defwinproc|optional },
466 { 0 }
469 static HWND create_button(DWORD style, HWND parent)
471 HMENU menuid = 0;
472 HWND hwnd;
474 if (parent)
476 style |= WS_CHILD|BS_NOTIFY;
477 menuid = (HMENU)ID_BUTTON;
479 hwnd = CreateWindowExA(0, "Button", "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL);
480 ok(hwnd != NULL, "failed to create a button, 0x%08x, %p\n", style, parent);
481 pSetWindowSubclass(hwnd, button_subclass_proc, 0, 0);
482 return hwnd;
485 static void test_button_messages(void)
487 static const struct
489 DWORD style;
490 DWORD dlg_code;
491 const struct message *setfocus;
492 const struct message *killfocus;
493 const struct message *setstyle;
494 const struct message *setstate;
495 const struct message *clearstate;
496 const struct message *setcheck;
497 } button[] = {
498 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
499 setfocus_seq, killfocus_seq, setstyle_seq,
500 setstate_seq, setstate_seq, setcheck_ignored_seq },
501 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
502 setfocus_seq, killfocus_seq, setstyle_seq,
503 setstate_seq, setstate_seq, setcheck_ignored_seq },
504 { BS_CHECKBOX, DLGC_BUTTON,
505 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
506 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
507 { BS_AUTOCHECKBOX, DLGC_BUTTON,
508 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
509 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
510 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
511 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
512 setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
513 { BS_3STATE, DLGC_BUTTON,
514 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
515 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
516 { BS_AUTO3STATE, DLGC_BUTTON,
517 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
518 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
519 { BS_GROUPBOX, DLGC_STATIC,
520 setfocus_groupbox_seq, killfocus_static_seq, setstyle_static_seq,
521 setstate_static_seq, setstate_static_seq, setcheck_ignored_seq },
522 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
523 setfocus_seq, killfocus_seq, setstyle_user_seq,
524 setstate_user_seq, clearstate_seq, setcheck_ignored_seq },
525 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
526 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
527 setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
528 { BS_OWNERDRAW, DLGC_BUTTON,
529 setfocus_ownerdraw_seq, killfocus_ownerdraw_seq, setstyle_ownerdraw_seq,
530 setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq },
532 const struct message *seq;
533 unsigned int i;
534 HWND hwnd, parent;
535 DWORD dlg_code;
536 HFONT zfont;
537 BOOL todo;
539 /* selection with VK_SPACE should capture button window */
540 hwnd = create_button(BS_CHECKBOX | WS_VISIBLE | WS_POPUP, NULL);
541 ok(hwnd != 0, "Failed to create button window\n");
542 ReleaseCapture();
543 SetFocus(hwnd);
544 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
545 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
546 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
547 DestroyWindow(hwnd);
549 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
550 100, 100, 200, 200, 0, 0, 0, NULL);
551 ok(parent != 0, "Failed to create parent window\n");
553 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
555 MSG msg;
556 DWORD style, state;
558 trace("%d: button test sequence\n", i);
559 hwnd = create_button(button[i].style, parent);
561 style = GetWindowLongA(hwnd, GWL_STYLE);
562 style &= ~(WS_CHILD | BS_NOTIFY);
563 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
564 if (button[i].style == BS_USERBUTTON)
565 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
566 else
567 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
569 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
570 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
572 ShowWindow(hwnd, SW_SHOW);
573 UpdateWindow(hwnd);
574 SetFocus(0);
575 flush_events();
576 SetFocus(0);
577 flush_sequences(sequences, NUM_MSG_SEQUENCES);
579 todo = button[i].style != BS_OWNERDRAW;
580 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
581 SetFocus(hwnd);
582 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
583 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
584 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setfocus, "SetFocus(hwnd) on a button", todo);
586 todo = button[i].style == BS_OWNERDRAW;
587 SetFocus(0);
588 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
589 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
590 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].killfocus, "SetFocus(0) on a button", todo);
591 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
593 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
594 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
595 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
596 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstyle, "BM_SETSTYLE on a button", TRUE);
598 style = GetWindowLongA(hwnd, GWL_STYLE);
599 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
600 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
601 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
603 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
604 ok(state == 0, "expected state 0, got %04x\n", state);
606 flush_sequences(sequences, NUM_MSG_SEQUENCES);
608 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
609 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
610 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
611 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstate, "BM_SETSTATE/TRUE on a button", TRUE);
613 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
614 ok(state == BST_PUSHED, "expected state 0x0004, got %04x\n", state);
616 style = GetWindowLongA(hwnd, GWL_STYLE);
617 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
618 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
620 flush_sequences(sequences, NUM_MSG_SEQUENCES);
622 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
623 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
624 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
625 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].clearstate, "BM_SETSTATE/FALSE on a button", TRUE);
627 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
628 ok(state == 0, "expected state 0, got %04x\n", state);
630 style = GetWindowLongA(hwnd, GWL_STYLE);
631 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
632 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
634 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
635 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
637 flush_sequences(sequences, NUM_MSG_SEQUENCES);
639 if (button[i].style == BS_RADIOBUTTON ||
640 button[i].style == BS_AUTORADIOBUTTON)
642 seq = setcheck_radio_seq;
643 todo = TRUE;
645 else
647 seq = setcheck_ignored_seq;
648 todo = FALSE;
650 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
651 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
652 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
653 ok_sequence(sequences, COMBINED_SEQ_INDEX, seq, "BM_SETCHECK on a button", todo);
655 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
656 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
658 style = GetWindowLongA(hwnd, GWL_STYLE);
659 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
660 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
662 flush_sequences(sequences, NUM_MSG_SEQUENCES);
664 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
665 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
666 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
668 if (button[i].style == BS_PUSHBUTTON ||
669 button[i].style == BS_DEFPUSHBUTTON ||
670 button[i].style == BS_GROUPBOX ||
671 button[i].style == BS_USERBUTTON ||
672 button[i].style == BS_OWNERDRAW)
674 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", FALSE);
675 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
676 ok(state == BST_UNCHECKED, "expected check BST_UNCHECKED, got %04x\n", state);
678 else
680 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", TRUE);
681 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
682 ok(state == BST_CHECKED, "expected check BST_CHECKED, got %04x\n", state);
685 style = GetWindowLongA(hwnd, GWL_STYLE);
686 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
687 if (button[i].style == BS_RADIOBUTTON ||
688 button[i].style == BS_AUTORADIOBUTTON)
689 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
690 else
691 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
693 DestroyWindow(hwnd);
696 DestroyWindow(parent);
698 hwnd = create_button(BS_PUSHBUTTON, NULL);
700 SetForegroundWindow(hwnd);
701 flush_events();
703 SetActiveWindow(hwnd);
704 SetFocus(0);
705 flush_sequences(sequences, NUM_MSG_SEQUENCES);
707 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
708 ok_sequence(sequences, COMBINED_SEQ_INDEX, lbuttondown_seq, "WM_LBUTTONDOWN on a button", FALSE);
710 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
711 ok_sequence(sequences, COMBINED_SEQ_INDEX, lbuttonup_seq, "WM_LBUTTONUP on a button", TRUE);
713 flush_sequences(sequences, NUM_MSG_SEQUENCES);
714 zfont = GetStockObject(SYSTEM_FONT);
715 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
716 UpdateWindow(hwnd);
717 ok_sequence(sequences, COMBINED_SEQ_INDEX, setfont_seq, "WM_SETFONT on a button", FALSE);
719 DestroyWindow(hwnd);
722 static void test_button_class(void)
724 static const WCHAR testW[] = {'t','e','s','t',0};
725 WNDCLASSEXW exW, ex2W;
726 WNDCLASSEXA exA;
727 char buffA[100];
728 WCHAR *nameW;
729 HWND hwnd;
730 BOOL ret;
731 int len;
733 ret = GetClassInfoExA(NULL, WC_BUTTONA, &exA);
734 ok(ret, "got %d\n", ret);
735 todo_wine
736 ok(IS_WNDPROC_HANDLE(exA.lpfnWndProc), "got %p\n", exA.lpfnWndProc);
738 ret = GetClassInfoExW(NULL, WC_BUTTONW, &exW);
739 ok(ret, "got %d\n", ret);
740 ok(!IS_WNDPROC_HANDLE(exW.lpfnWndProc), "got %p\n", exW.lpfnWndProc);
742 /* check that versioned class is also accessible */
743 nameW = get_versioned_classname(WC_BUTTONW);
744 ok(lstrcmpW(nameW, WC_BUTTONW), "got %s\n", wine_dbgstr_w(nameW));
746 ret = GetClassInfoExW(NULL, nameW, &ex2W);
747 todo_wine
748 ok(ret, "got %d\n", ret);
749 if (ret) /* TODO: remove once Wine is fixed */
750 ok(ex2W.lpfnWndProc == exW.lpfnWndProc, "got %p, %p\n", exW.lpfnWndProc, ex2W.lpfnWndProc);
752 /* Check reported class name */
753 hwnd = create_button(BS_CHECKBOX, NULL);
754 len = GetClassNameA(hwnd, buffA, sizeof(buffA));
755 ok(len == strlen(buffA), "got %d\n", len);
756 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
758 len = RealGetWindowClassA(hwnd, buffA, sizeof(buffA));
759 ok(len == strlen(buffA), "got %d\n", len);
760 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
761 DestroyWindow(hwnd);
763 /* explicitly create with versioned class name */
764 hwnd = CreateWindowExW(0, nameW, testW, BS_CHECKBOX, 0, 0, 50, 14, NULL, 0, 0, NULL);
765 todo_wine
766 ok(hwnd != NULL, "failed to create a window %s\n", wine_dbgstr_w(nameW));
767 if (hwnd)
769 len = GetClassNameA(hwnd, buffA, sizeof(buffA));
770 ok(len == strlen(buffA), "got %d\n", len);
771 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
773 len = RealGetWindowClassA(hwnd, buffA, sizeof(buffA));
774 ok(len == strlen(buffA), "got %d\n", len);
775 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
777 DestroyWindow(hwnd);
781 static void register_parent_class(void)
783 WNDCLASSA cls;
785 cls.style = 0;
786 cls.lpfnWndProc = test_parent_wndproc;
787 cls.cbClsExtra = 0;
788 cls.cbWndExtra = 0;
789 cls.hInstance = GetModuleHandleA(0);
790 cls.hIcon = 0;
791 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
792 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
793 cls.lpszMenuName = NULL;
794 cls.lpszClassName = "TestParentClass";
795 RegisterClassA(&cls);
798 START_TEST(button)
800 ULONG_PTR ctx_cookie;
801 HANDLE hCtx;
803 if (!load_v6_module(&ctx_cookie, &hCtx))
804 return;
806 register_parent_class();
808 init_functions();
809 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
811 test_button_class();
812 test_button_messages();
814 unload_v6_module(ctx_cookie, hCtx);