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
26 #include "wine/test.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
54 /* returned pointer is valid as long as activation context is alive */
55 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
57 struct wndclass_redirect_data
*wnddata
;
58 ACTCTX_SECTION_KEYED_DATA data
;
61 memset(&data
, 0, sizeof(data
));
62 data
.cbSize
= sizeof(data
);
63 ret
= FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
, name
, &data
);
64 ok(ret
, "Failed to find class redirection section, error %u\n", GetLastError());
65 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
66 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
69 static void init_functions(void)
71 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
72 ok(hmod
!= NULL
, "got %p\n", hmod
);
74 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
75 MAKEFUNC_ORD(SetWindowSubclass
, 410);
76 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
77 MAKEFUNC_ORD(DefSubclassProc
, 413);
81 /* try to make sure pending X events have been processed before continuing */
82 static void flush_events(void)
86 int min_timeout
= 100;
87 DWORD time
= GetTickCount() + diff
;
91 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
92 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
93 diff
= time
- GetTickCount();
97 static BOOL
ignore_message( UINT message
)
99 /* these are always ignored */
100 return (message
>= 0xc000 ||
101 message
== WM_GETICON
||
102 message
== WM_GETOBJECT
||
103 message
== WM_TIMECHANGE
||
104 message
== WM_DISPLAYCHANGE
||
105 message
== WM_DEVICECHANGE
||
106 message
== WM_DWMNCRENDERINGCHANGED
||
107 message
== WM_GETTEXTLENGTH
||
108 message
== WM_GETTEXT
);
111 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
113 static LONG defwndproc_counter
= 0;
114 struct message msg
= { 0 };
117 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
125 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
128 msg
.message
= message
;
129 msg
.flags
= sent
|wparam
|lparam
;
130 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
133 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
136 if (message
== WM_NCDESTROY
)
137 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
139 defwndproc_counter
++;
140 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
141 defwndproc_counter
--;
146 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
148 static LONG defwndproc_counter
= 0;
149 static LONG beginpaint_counter
= 0;
150 struct message msg
= { 0 };
153 if (ignore_message( message
)) return 0;
155 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
156 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
157 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
158 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
159 message
== WM_IME_SETCONTEXT
)
161 msg
.message
= message
;
162 msg
.flags
= sent
|parent
|wparam
|lparam
;
163 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
164 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
167 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
170 if (message
== WM_PAINT
)
173 beginpaint_counter
++;
174 BeginPaint( hwnd
, &ps
);
175 beginpaint_counter
--;
176 EndPaint( hwnd
, &ps
);
180 defwndproc_counter
++;
181 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
182 defwndproc_counter
--;
187 static const struct message setfocus_seq
[] =
189 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
190 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
191 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
192 { WM_SETFOCUS
, sent
|wparam
},
193 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
194 { WM_APP
, sent
|wparam
|lparam
},
199 static const struct message killfocus_seq
[] =
201 { WM_KILLFOCUS
, sent
|wparam
, 0 },
202 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
203 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
204 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
205 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
210 static const struct message setfocus_static_seq
[] =
212 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
213 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
214 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
215 { WM_SETFOCUS
, sent
|wparam
, 0 },
216 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
217 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
218 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
223 static const struct message setfocus_groupbox_seq
[] =
225 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
226 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
227 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
228 { WM_SETFOCUS
, sent
|wparam
, 0 },
229 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
230 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
231 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
236 static const struct message killfocus_static_seq
[] =
238 { WM_KILLFOCUS
, sent
|wparam
, 0 },
239 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
240 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
241 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
242 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
247 static const struct message setfocus_ownerdraw_seq
[] =
249 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
250 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
251 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
252 { WM_SETFOCUS
, sent
|wparam
, 0 },
253 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
254 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
255 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
256 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
260 static const struct message killfocus_ownerdraw_seq
[] =
262 { WM_KILLFOCUS
, sent
|wparam
, 0 },
263 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
264 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
265 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
266 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
268 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
272 static const struct message lbuttondown_seq
[] =
274 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
275 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
276 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
277 { BM_GETSTATE
, sent
|defwinproc
|optional
}, /* when touchscreen is present */
278 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
279 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
283 static const struct message lbuttonup_seq
[] =
285 { WM_LBUTTONUP
, sent
|wparam
|lparam
, 0, 0 },
286 { BM_SETSTATE
, sent
|wparam
|defwinproc
, FALSE
},
287 { WM_CAPTURECHANGED
, sent
|wparam
|defwinproc
, 0 },
288 { WM_COMMAND
, sent
|wparam
|defwinproc
, 0 },
292 static const struct message setfont_seq
[] =
294 { WM_SETFONT
, sent
},
298 static const struct message setstyle_seq
[] =
300 { BM_SETSTYLE
, sent
},
301 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
302 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
303 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
305 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
306 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
307 { WM_PAINT
, sent
|optional
},
311 static const struct message setstyle_static_seq
[] =
313 { BM_SETSTYLE
, sent
},
314 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
315 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
316 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
318 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
319 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
323 static const struct message setstyle_user_seq
[] =
325 { BM_SETSTYLE
, sent
},
326 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
327 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
328 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
330 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
331 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
335 static const struct message setstyle_ownerdraw_seq
[] =
337 { BM_SETSTYLE
, sent
},
338 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
339 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
340 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
342 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
343 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
344 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
348 static const struct message setstate_seq
[] =
350 { BM_SETSTATE
, sent
},
351 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
353 { WM_PAINT
, sent
|optional
},
357 static const struct message setstate_static_seq
[] =
359 { BM_SETSTATE
, sent
},
360 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
362 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
363 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
367 static const struct message setstate_user_seq
[] =
369 { BM_SETSTATE
, sent
},
370 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
371 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
376 static const struct message setstate_ownerdraw_seq
[] =
378 { BM_SETSTATE
, sent
},
379 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
381 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
382 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
383 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
387 static const struct message clearstate_seq
[] =
389 { BM_SETSTATE
, sent
},
390 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
391 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
393 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
394 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
398 static const struct message clearstate_ownerdraw_seq
[] =
400 { BM_SETSTATE
, sent
},
401 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
403 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
404 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
405 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
409 static const struct message setcheck_ignored_seq
[] =
411 { BM_SETCHECK
, sent
},
412 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
413 { WM_PAINT
, sent
|optional
},
417 static const struct message setcheck_static_seq
[] =
419 { BM_SETCHECK
, sent
},
420 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
422 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
423 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
427 static const struct message setcheck_radio_seq
[] =
429 { BM_SETCHECK
, sent
},
430 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
431 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
432 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
436 static const struct message setcheck_radio_redraw_seq
[] =
438 { BM_SETCHECK
, sent
},
439 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
440 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
441 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
443 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
447 static HWND
create_button(DWORD style
, HWND parent
)
454 style
|= WS_CHILD
|BS_NOTIFY
;
455 menuid
= (HMENU
)ID_BUTTON
;
457 hwnd
= CreateWindowExA(0, "Button", "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
458 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
459 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
463 static void test_button_messages(void)
469 const struct message
*setfocus
;
470 const struct message
*killfocus
;
471 const struct message
*setstyle
;
472 const struct message
*setstate
;
473 const struct message
*clearstate
;
474 const struct message
*setcheck
;
476 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
477 setfocus_seq
, killfocus_seq
, setstyle_seq
,
478 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
479 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
480 setfocus_seq
, killfocus_seq
, setstyle_seq
,
481 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
482 { BS_CHECKBOX
, DLGC_BUTTON
,
483 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
484 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
485 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
486 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
487 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
488 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
489 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
490 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
491 { BS_3STATE
, DLGC_BUTTON
,
492 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
493 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
494 { BS_AUTO3STATE
, DLGC_BUTTON
,
495 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
496 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
497 { BS_GROUPBOX
, DLGC_STATIC
,
498 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
499 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
},
500 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
501 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
502 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
},
503 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
504 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
505 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
506 { BS_OWNERDRAW
, DLGC_BUTTON
,
507 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
508 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
},
509 { BS_SPLITBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
| DLGC_WANTARROWS
,
510 setfocus_seq
, killfocus_seq
, setstyle_seq
,
511 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
512 { BS_DEFSPLITBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
| DLGC_WANTARROWS
,
513 setfocus_seq
, killfocus_seq
, setstyle_seq
,
514 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
515 { BS_COMMANDLINK
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
516 setfocus_seq
, killfocus_seq
, setstyle_seq
,
517 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
518 { BS_DEFCOMMANDLINK
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
519 setfocus_seq
, killfocus_seq
, setstyle_seq
,
520 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
522 const struct message
*seq
;
529 /* selection with VK_SPACE should capture button window */
530 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
531 ok(hwnd
!= 0, "Failed to create button window\n");
534 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
535 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
536 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
539 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
540 100, 100, 200, 200, 0, 0, 0, NULL
);
541 ok(parent
!= 0, "Failed to create parent window\n");
543 for (i
= 0; i
< sizeof(button
)/sizeof(button
[0]); i
++)
548 trace("%d: button test sequence\n", i
);
549 hwnd
= create_button(button
[i
].style
, parent
);
551 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
552 style
&= ~(WS_CHILD
| BS_NOTIFY
);
553 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
554 if (button
[i
].style
== BS_USERBUTTON
)
555 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
557 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
559 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
560 if (button
[i
].style
== BS_SPLITBUTTON
||
561 button
[i
].style
== BS_DEFSPLITBUTTON
||
562 button
[i
].style
== BS_COMMANDLINK
||
563 button
[i
].style
== BS_DEFCOMMANDLINK
)
565 ok(dlg_code
== button
[i
].dlg_code
|| broken(dlg_code
== DLGC_BUTTON
) /* WinXP */, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
568 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
570 ShowWindow(hwnd
, SW_SHOW
);
575 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
577 todo
= button
[i
].style
!= BS_OWNERDRAW
;
578 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
580 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
581 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
582 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setfocus
, "SetFocus(hwnd) on a button", todo
);
584 todo
= button
[i
].style
== BS_OWNERDRAW
;
586 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
587 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
588 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", todo
);
589 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
591 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
592 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
593 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
594 todo
= button
[i
].style
== BS_OWNERDRAW
;
595 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", todo
);
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", FALSE
);
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", FALSE
);
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
;
644 seq
= setcheck_ignored_seq
;
646 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
647 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
648 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
649 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", FALSE
);
651 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
652 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
654 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
655 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
656 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
658 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
660 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
661 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
662 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
663 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
665 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
666 if (button
[i
].style
== BS_PUSHBUTTON
||
667 button
[i
].style
== BS_DEFPUSHBUTTON
||
668 button
[i
].style
== BS_GROUPBOX
||
669 button
[i
].style
== BS_USERBUTTON
||
670 button
[i
].style
== BS_OWNERDRAW
||
671 button
[i
].style
== BS_SPLITBUTTON
||
672 button
[i
].style
== BS_DEFSPLITBUTTON
||
673 button
[i
].style
== BS_COMMANDLINK
||
674 button
[i
].style
== BS_DEFCOMMANDLINK
)
676 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
679 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
681 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
682 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
683 if (button
[i
].style
== BS_RADIOBUTTON
||
684 button
[i
].style
== BS_AUTORADIOBUTTON
)
685 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
687 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
692 DestroyWindow(parent
);
694 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
696 SetForegroundWindow(hwnd
);
699 SetActiveWindow(hwnd
);
701 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
703 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
704 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
706 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
707 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
709 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
710 zfont
= GetStockObject(SYSTEM_FONT
);
711 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
713 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
718 static void test_button_class(void)
720 static const WCHAR testW
[] = {'t','e','s','t',0};
721 WNDCLASSEXW exW
, ex2W
;
729 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
730 ok(ret
, "got %d\n", ret
);
731 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
733 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
734 ok(ret
, "got %d\n", ret
);
735 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
737 /* check that versioned class is also accessible */
738 nameW
= get_versioned_classname(WC_BUTTONW
);
739 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
741 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
742 ok(ret
, "got %d\n", ret
);
743 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
745 /* Check reported class name */
746 hwnd
= create_button(BS_CHECKBOX
, NULL
);
747 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
748 ok(len
== strlen(buffA
), "got %d\n", len
);
749 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
751 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
752 ok(len
== strlen(buffA
), "got %d\n", len
);
753 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
756 /* explicitly create with versioned class name */
757 hwnd
= CreateWindowExW(0, nameW
, testW
, BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
758 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
760 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
761 ok(len
== strlen(buffA
), "got %d\n", len
);
762 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
764 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
765 ok(len
== strlen(buffA
), "got %d\n", len
);
766 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
771 static void register_parent_class(void)
776 cls
.lpfnWndProc
= test_parent_wndproc
;
779 cls
.hInstance
= GetModuleHandleA(0);
781 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
782 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
783 cls
.lpszMenuName
= NULL
;
784 cls
.lpszClassName
= "TestParentClass";
785 RegisterClassA(&cls
);
790 ULONG_PTR ctx_cookie
;
793 if (!load_v6_module(&ctx_cookie
, &hCtx
))
796 register_parent_class();
799 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
802 test_button_messages();
804 unload_v6_module(ctx_cookie
, hCtx
);