Assorted spelling fixes.
[wine.git] / dlls / comctl32 / tests / button.c
blobeb4e924e0f0f642261034e655fef9dc829a94410
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 { WM_SETFOCUS, sent|wparam },
209 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
210 { WM_APP, sent|wparam|lparam },
211 { WM_PAINT, sent },
212 { 0 }
215 static const struct message killfocus_seq[] =
217 { WM_KILLFOCUS, sent|wparam, 0 },
218 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
219 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
220 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
221 { WM_APP, sent|wparam|lparam, 0, 0 },
222 { WM_PAINT, sent },
223 { 0 }
226 static const struct message setfocus_static_seq[] =
228 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
229 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
230 { WM_SETFOCUS, sent|wparam, 0 },
231 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
232 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
233 { WM_APP, sent|wparam|lparam, 0, 0 },
234 { WM_PAINT, sent },
235 { 0 }
238 static const struct message setfocus_groupbox_seq[] =
240 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
241 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
242 { WM_SETFOCUS, sent|wparam, 0 },
243 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
244 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
245 { WM_APP, sent|wparam|lparam, 0, 0 },
246 { WM_PAINT, sent },
247 { 0 }
250 static const struct message killfocus_static_seq[] =
252 { WM_KILLFOCUS, sent|wparam, 0 },
253 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
254 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
255 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
256 { WM_APP, sent|wparam|lparam, 0, 0 },
257 { WM_PAINT, sent },
258 { 0 }
261 static const struct message setfocus_ownerdraw_seq[] =
263 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
264 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
265 { WM_SETFOCUS, sent|wparam, 0 },
266 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
267 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
268 { WM_APP, sent|wparam|lparam, 0, 0 },
269 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
270 { 0 }
273 static const struct message killfocus_ownerdraw_seq[] =
275 { WM_KILLFOCUS, sent|wparam, 0 },
276 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
277 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
278 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
279 { WM_APP, sent|wparam|lparam, 0, 0 },
280 { WM_PAINT, sent },
281 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
282 { 0 }
285 static const struct message lbuttondown_seq[] =
287 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
288 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
289 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
290 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
291 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
292 { 0 }
295 static const struct message lbuttonup_seq[] =
297 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
298 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
299 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
300 { WM_COMMAND, sent|wparam|defwinproc, 0 },
301 { 0 }
304 static const struct message setfont_seq[] =
306 { WM_SETFONT, sent },
307 { 0 }
310 static const struct message setstyle_seq[] =
312 { BM_SETSTYLE, sent },
313 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
314 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
315 { WM_APP, sent|wparam|lparam, 0, 0 },
316 { WM_PAINT, sent },
317 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
318 { WM_ERASEBKGND, sent|defwinproc|optional },
319 { 0 }
322 static const struct message setstyle_static_seq[] =
324 { BM_SETSTYLE, sent },
325 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
326 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
327 { WM_APP, sent|wparam|lparam, 0, 0 },
328 { WM_PAINT, sent },
329 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
330 { WM_ERASEBKGND, sent|defwinproc|optional },
331 { 0 }
334 static const struct message setstyle_user_seq[] =
336 { BM_SETSTYLE, sent },
337 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
338 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
339 { WM_APP, sent|wparam|lparam, 0, 0 },
340 { WM_PAINT, sent },
341 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
342 { WM_ERASEBKGND, sent|defwinproc|optional },
343 { 0 }
346 static const struct message setstyle_ownerdraw_seq[] =
348 { BM_SETSTYLE, sent },
349 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
350 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
351 { WM_APP, sent|wparam|lparam, 0, 0 },
352 { WM_PAINT, sent },
353 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
354 { WM_ERASEBKGND, sent|defwinproc|optional },
355 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
356 { 0 }
359 static const struct message setstate_seq[] =
361 { BM_SETSTATE, sent },
362 { WM_APP, sent|wparam|lparam, 0, 0 },
363 { WM_PAINT, sent },
364 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
365 { WM_ERASEBKGND, sent|defwinproc|optional },
366 { 0 }
369 static const struct message setstate_static_seq[] =
371 { BM_SETSTATE, sent },
372 { WM_APP, sent|wparam|lparam, 0, 0 },
373 { WM_PAINT, sent },
374 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
375 { WM_ERASEBKGND, sent|defwinproc|optional },
376 { 0 }
379 static const struct message setstate_user_seq[] =
381 { BM_SETSTATE, sent },
382 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
383 { WM_APP, sent|wparam|lparam, 0, 0 },
384 { WM_PAINT, sent },
385 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
386 { WM_ERASEBKGND, sent|defwinproc|optional },
387 { 0 }
390 static const struct message setstate_ownerdraw_seq[] =
392 { BM_SETSTATE, sent },
393 { WM_APP, sent|wparam|lparam, 0, 0 },
394 { WM_PAINT, sent },
395 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
396 { WM_ERASEBKGND, sent|defwinproc|optional },
397 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
398 { 0 }
401 static const struct message clearstate_seq[] =
403 { BM_SETSTATE, sent },
404 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
405 { WM_APP, sent|wparam|lparam, 0, 0 },
406 { WM_PAINT, sent },
407 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
408 { WM_ERASEBKGND, sent|defwinproc|optional },
409 { 0 }
412 static const struct message clearstate_ownerdraw_seq[] =
414 { BM_SETSTATE, sent },
415 { WM_APP, sent|wparam|lparam, 0, 0 },
416 { WM_PAINT, sent },
417 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
418 { WM_ERASEBKGND, sent|defwinproc|optional },
419 { WM_DRAWITEM, sent|wparam|parent, ID_BUTTON },
420 { 0 }
423 static const struct message setcheck_ignored_seq[] =
425 { BM_SETCHECK, sent },
426 { WM_APP, sent|wparam|lparam, 0, 0 },
427 { 0 }
430 static const struct message setcheck_uncheck_seq[] =
432 { BM_SETCHECK, sent },
433 { WM_APP, sent|wparam|lparam, 0, 0 },
434 { 0 }
437 static const struct message setcheck_static_seq[] =
439 { BM_SETCHECK, sent },
440 { WM_APP, sent|wparam|lparam, 0, 0 },
441 { WM_PAINT, sent },
442 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
443 { WM_ERASEBKGND, sent|defwinproc|optional },
444 { 0 }
447 static const struct message setcheck_radio_seq[] =
449 { BM_SETCHECK, sent },
450 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
451 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
452 { WM_APP, sent|wparam|lparam, 0, 0 },
453 { 0 }
456 static const struct message setcheck_radio_redraw_seq[] =
458 { BM_SETCHECK, sent },
459 { WM_STYLECHANGING, sent|wparam|defwinproc, GWL_STYLE },
460 { WM_STYLECHANGED, sent|wparam|defwinproc, GWL_STYLE },
461 { WM_APP, sent|wparam|lparam, 0, 0 },
462 { WM_PAINT, sent },
463 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
464 { WM_ERASEBKGND, sent|defwinproc|optional },
465 { 0 }
468 static HWND create_button(DWORD style, HWND parent)
470 HMENU menuid = 0;
471 HWND hwnd;
473 if (parent)
475 style |= WS_CHILD|BS_NOTIFY;
476 menuid = (HMENU)ID_BUTTON;
478 hwnd = CreateWindowExA(0, "Button", "test", style, 0, 0, 50, 14, parent, menuid, 0, NULL);
479 ok(hwnd != NULL, "failed to create a button, 0x%08x, %p\n", style, parent);
480 pSetWindowSubclass(hwnd, button_subclass_proc, 0, 0);
481 return hwnd;
484 static void test_button_messages(void)
486 static const struct
488 DWORD style;
489 DWORD dlg_code;
490 const struct message *setfocus;
491 const struct message *killfocus;
492 const struct message *setstyle;
493 const struct message *setstate;
494 const struct message *clearstate;
495 const struct message *setcheck;
496 } button[] = {
497 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
498 setfocus_seq, killfocus_seq, setstyle_seq,
499 setstate_seq, setstate_seq, setcheck_ignored_seq },
500 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
501 setfocus_seq, killfocus_seq, setstyle_seq,
502 setstate_seq, setstate_seq, setcheck_ignored_seq },
503 { BS_CHECKBOX, DLGC_BUTTON,
504 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
505 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
506 { BS_AUTOCHECKBOX, DLGC_BUTTON,
507 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
508 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
509 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
510 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
511 setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
512 { BS_3STATE, DLGC_BUTTON,
513 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
514 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
515 { BS_AUTO3STATE, DLGC_BUTTON,
516 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
517 setstate_static_seq, setstate_static_seq, setcheck_static_seq },
518 { BS_GROUPBOX, DLGC_STATIC,
519 setfocus_groupbox_seq, killfocus_static_seq, setstyle_static_seq,
520 setstate_static_seq, setstate_static_seq, setcheck_ignored_seq },
521 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
522 setfocus_seq, killfocus_seq, setstyle_user_seq,
523 setstate_user_seq, clearstate_seq, setcheck_ignored_seq },
524 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
525 setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
526 setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
527 { BS_OWNERDRAW, DLGC_BUTTON,
528 setfocus_ownerdraw_seq, killfocus_ownerdraw_seq, setstyle_ownerdraw_seq,
529 setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq },
531 const struct message *seq;
532 unsigned int i;
533 HWND hwnd, parent;
534 DWORD dlg_code;
535 HFONT zfont;
536 BOOL todo;
538 /* selection with VK_SPACE should capture button window */
539 hwnd = create_button(BS_CHECKBOX | WS_VISIBLE | WS_POPUP, NULL);
540 ok(hwnd != 0, "Failed to create button window\n");
541 ReleaseCapture();
542 SetFocus(hwnd);
543 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
544 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
545 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
546 DestroyWindow(hwnd);
548 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
549 100, 100, 200, 200, 0, 0, 0, NULL);
550 ok(parent != 0, "Failed to create parent window\n");
552 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
554 MSG msg;
555 DWORD style, state;
557 trace("%d: button test sequence\n", i);
558 hwnd = create_button(button[i].style, parent);
560 style = GetWindowLongA(hwnd, GWL_STYLE);
561 style &= ~(WS_CHILD | BS_NOTIFY);
562 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
563 if (button[i].style == BS_USERBUTTON)
564 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
565 else
566 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
568 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
569 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
571 ShowWindow(hwnd, SW_SHOW);
572 UpdateWindow(hwnd);
573 SetFocus(0);
574 flush_events();
575 SetFocus(0);
576 flush_sequences(sequences, NUM_MSG_SEQUENCES);
578 todo = button[i].style != BS_OWNERDRAW;
579 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
580 SetFocus(hwnd);
581 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
582 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
583 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setfocus, "SetFocus(hwnd) on a button", todo);
585 todo = button[i].style == BS_OWNERDRAW;
586 SetFocus(0);
587 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
588 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
589 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].killfocus, "SetFocus(0) on a button", todo);
590 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
592 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
593 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
594 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
595 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstyle, "BM_SETSTYLE on a button", TRUE);
597 style = GetWindowLongA(hwnd, GWL_STYLE);
598 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
599 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
600 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
602 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
603 ok(state == 0, "expected state 0, got %04x\n", state);
605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
607 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
608 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
609 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
610 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstate, "BM_SETSTATE/TRUE on a button", TRUE);
612 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
613 ok(state == BST_PUSHED, "expected state 0x0004, got %04x\n", state);
615 style = GetWindowLongA(hwnd, GWL_STYLE);
616 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
617 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
619 flush_sequences(sequences, NUM_MSG_SEQUENCES);
621 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
622 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
623 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
624 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].clearstate, "BM_SETSTATE/FALSE on a button", TRUE);
626 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
627 ok(state == 0, "expected state 0, got %04x\n", state);
629 style = GetWindowLongA(hwnd, GWL_STYLE);
630 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
631 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
633 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
634 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
636 flush_sequences(sequences, NUM_MSG_SEQUENCES);
638 if (button[i].style == BS_RADIOBUTTON ||
639 button[i].style == BS_AUTORADIOBUTTON)
641 seq = setcheck_radio_seq;
642 todo = TRUE;
644 else
646 seq = setcheck_ignored_seq;
647 todo = FALSE;
649 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
650 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
651 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
652 ok_sequence(sequences, COMBINED_SEQ_INDEX, seq, "BM_SETCHECK on a button", todo);
654 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
655 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
657 style = GetWindowLongA(hwnd, GWL_STYLE);
658 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
659 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
661 flush_sequences(sequences, NUM_MSG_SEQUENCES);
663 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
664 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
665 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
667 if (button[i].style == BS_PUSHBUTTON ||
668 button[i].style == BS_DEFPUSHBUTTON ||
669 button[i].style == BS_GROUPBOX ||
670 button[i].style == BS_USERBUTTON ||
671 button[i].style == BS_OWNERDRAW)
673 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", FALSE);
674 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
675 ok(state == BST_UNCHECKED, "expected check BST_UNCHECKED, got %04x\n", state);
677 else
679 ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", TRUE);
680 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
681 ok(state == BST_CHECKED, "expected check BST_CHECKED, got %04x\n", state);
684 style = GetWindowLongA(hwnd, GWL_STYLE);
685 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
686 if (button[i].style == BS_RADIOBUTTON ||
687 button[i].style == BS_AUTORADIOBUTTON)
688 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
689 else
690 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
692 DestroyWindow(hwnd);
695 DestroyWindow(parent);
697 hwnd = create_button(BS_PUSHBUTTON, NULL);
699 SetForegroundWindow(hwnd);
700 flush_events();
702 SetActiveWindow(hwnd);
703 SetFocus(0);
704 flush_sequences(sequences, NUM_MSG_SEQUENCES);
706 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
707 ok_sequence(sequences, COMBINED_SEQ_INDEX, lbuttondown_seq, "WM_LBUTTONDOWN on a button", FALSE);
709 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
710 ok_sequence(sequences, COMBINED_SEQ_INDEX, lbuttonup_seq, "WM_LBUTTONUP on a button", TRUE);
712 flush_sequences(sequences, NUM_MSG_SEQUENCES);
713 zfont = GetStockObject(SYSTEM_FONT);
714 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
715 UpdateWindow(hwnd);
716 ok_sequence(sequences, COMBINED_SEQ_INDEX, setfont_seq, "WM_SETFONT on a button", FALSE);
718 DestroyWindow(hwnd);
721 static void test_button_class(void)
723 static const WCHAR testW[] = {'t','e','s','t',0};
724 WNDCLASSEXW exW, ex2W;
725 WNDCLASSEXA exA;
726 char buffA[100];
727 WCHAR *nameW;
728 HWND hwnd;
729 BOOL ret;
730 int len;
732 ret = GetClassInfoExA(NULL, WC_BUTTONA, &exA);
733 ok(ret, "got %d\n", ret);
734 todo_wine
735 ok(IS_WNDPROC_HANDLE(exA.lpfnWndProc), "got %p\n", exA.lpfnWndProc);
737 ret = GetClassInfoExW(NULL, WC_BUTTONW, &exW);
738 ok(ret, "got %d\n", ret);
739 ok(!IS_WNDPROC_HANDLE(exW.lpfnWndProc), "got %p\n", exW.lpfnWndProc);
741 /* check that versioned class is also accessible */
742 nameW = get_versioned_classname(WC_BUTTONW);
743 ok(lstrcmpW(nameW, WC_BUTTONW), "got %s\n", wine_dbgstr_w(nameW));
745 ret = GetClassInfoExW(NULL, nameW, &ex2W);
746 todo_wine
747 ok(ret, "got %d\n", ret);
748 if (ret) /* TODO: remove once Wine is fixed */
749 ok(ex2W.lpfnWndProc == exW.lpfnWndProc, "got %p, %p\n", exW.lpfnWndProc, ex2W.lpfnWndProc);
751 /* Check reported class name */
752 hwnd = create_button(BS_CHECKBOX, NULL);
753 len = GetClassNameA(hwnd, buffA, sizeof(buffA));
754 ok(len == strlen(buffA), "got %d\n", len);
755 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
757 len = RealGetWindowClassA(hwnd, buffA, sizeof(buffA));
758 ok(len == strlen(buffA), "got %d\n", len);
759 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
760 DestroyWindow(hwnd);
762 /* explicitly create with versioned class name */
763 hwnd = CreateWindowExW(0, nameW, testW, BS_CHECKBOX, 0, 0, 50, 14, NULL, 0, 0, NULL);
764 todo_wine
765 ok(hwnd != NULL, "failed to create a window %s\n", wine_dbgstr_w(nameW));
766 if (hwnd)
768 len = GetClassNameA(hwnd, buffA, sizeof(buffA));
769 ok(len == strlen(buffA), "got %d\n", len);
770 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
772 len = RealGetWindowClassA(hwnd, buffA, sizeof(buffA));
773 ok(len == strlen(buffA), "got %d\n", len);
774 ok(!strcmp(buffA, "Button"), "got %s\n", buffA);
776 DestroyWindow(hwnd);
780 static void register_parent_class(void)
782 WNDCLASSA cls;
784 cls.style = 0;
785 cls.lpfnWndProc = test_parent_wndproc;
786 cls.cbClsExtra = 0;
787 cls.cbWndExtra = 0;
788 cls.hInstance = GetModuleHandleA(0);
789 cls.hIcon = 0;
790 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
791 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
792 cls.lpszMenuName = NULL;
793 cls.lpszClassName = "TestParentClass";
794 RegisterClassA(&cls);
797 START_TEST(button)
799 ULONG_PTR ctx_cookie;
800 HANDLE hCtx;
802 if (!load_v6_module(&ctx_cookie, &hCtx))
803 return;
805 register_parent_class();
807 init_functions();
808 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
810 test_button_class();
811 test_button_messages();
813 unload_v6_module(ctx_cookie, hCtx);