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>
31 #include "wine/test.h"
35 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
37 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
38 static BOOL (WINAPI
*pRemoveWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
);
39 static LRESULT (WINAPI
*pDefSubclassProc
)(HWND
, UINT
, WPARAM
, LPARAM
);
41 /****************** button message test *************************/
42 #define ID_BUTTON 0x000e
44 #define COMBINED_SEQ_INDEX 0
45 #define NUM_MSG_SEQUENCES 1
47 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
49 struct wndclass_redirect_data
59 /* returned pointer is valid as long as activation context is alive */
60 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
62 BOOL (WINAPI
*pFindActCtxSectionStringW
)(DWORD
,const GUID
*,ULONG
,LPCWSTR
,PACTCTX_SECTION_KEYED_DATA
);
63 struct wndclass_redirect_data
*wnddata
;
64 ACTCTX_SECTION_KEYED_DATA data
;
67 pFindActCtxSectionStringW
= (void*)GetProcAddress(GetModuleHandleA("kernel32"), "FindActCtxSectionStringW");
69 memset(&data
, 0, sizeof(data
));
70 data
.cbSize
= sizeof(data
);
72 ret
= pFindActCtxSectionStringW(0, NULL
,
73 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
75 ok(ret
, "got %d, error %u\n", ret
, GetLastError());
76 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
77 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
80 static void init_functions(void)
82 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
83 ok(hmod
!= NULL
, "got %p\n", hmod
);
85 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
86 MAKEFUNC_ORD(SetWindowSubclass
, 410);
87 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
88 MAKEFUNC_ORD(DefSubclassProc
, 413);
92 /* try to make sure pending X events have been processed before continuing */
93 static void flush_events(void)
97 int min_timeout
= 100;
98 DWORD time
= GetTickCount() + diff
;
102 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
103 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
104 diff
= time
- GetTickCount();
108 static BOOL
ignore_message( UINT message
)
110 /* these are always ignored */
111 return (message
>= 0xc000 ||
112 message
== WM_GETICON
||
113 message
== WM_GETOBJECT
||
114 message
== WM_TIMECHANGE
||
115 message
== WM_DISPLAYCHANGE
||
116 message
== WM_DEVICECHANGE
||
117 message
== WM_DWMNCRENDERINGCHANGED
||
118 message
== WM_GETTEXTLENGTH
||
119 message
== WM_GETTEXT
);
122 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
124 static LONG defwndproc_counter
= 0;
128 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
136 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
139 msg
.message
= message
;
140 msg
.flags
= sent
|wparam
|lparam
;
141 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
144 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
147 if (message
== WM_NCDESTROY
)
148 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
150 defwndproc_counter
++;
151 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
152 defwndproc_counter
--;
157 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
159 static LONG defwndproc_counter
= 0;
160 static LONG beginpaint_counter
= 0;
164 if (ignore_message( message
)) return 0;
166 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
167 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
168 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
169 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
170 message
== WM_IME_SETCONTEXT
)
183 msg
.message
= message
;
184 msg
.flags
= sent
|parent
|wparam
|lparam
;
185 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
186 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
189 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
192 if (message
== WM_PAINT
)
195 beginpaint_counter
++;
196 BeginPaint( hwnd
, &ps
);
197 beginpaint_counter
--;
198 EndPaint( hwnd
, &ps
);
202 defwndproc_counter
++;
203 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
204 defwndproc_counter
--;
209 static const struct message setfocus_seq
[] =
211 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
212 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
213 { WM_SETFOCUS
, sent
|wparam
},
214 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
215 { WM_APP
, sent
|wparam
|lparam
},
220 static const struct message killfocus_seq
[] =
222 { WM_KILLFOCUS
, sent
|wparam
, 0 },
223 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
224 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
225 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
226 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
231 static const struct message setfocus_static_seq
[] =
233 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
234 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
235 { WM_SETFOCUS
, sent
|wparam
, 0 },
236 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
237 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
238 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
243 static const struct message setfocus_groupbox_seq
[] =
245 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
246 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
247 { WM_SETFOCUS
, sent
|wparam
, 0 },
248 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
249 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
250 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
255 static const struct message killfocus_static_seq
[] =
257 { WM_KILLFOCUS
, sent
|wparam
, 0 },
258 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
259 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
260 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
261 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
266 static const struct message setfocus_ownerdraw_seq
[] =
268 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
269 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
270 { WM_SETFOCUS
, sent
|wparam
, 0 },
271 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
272 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
273 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
274 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
278 static const struct message killfocus_ownerdraw_seq
[] =
280 { WM_KILLFOCUS
, sent
|wparam
, 0 },
281 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
282 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
283 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
284 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
286 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
290 static const struct message lbuttondown_seq
[] =
292 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
293 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
294 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
295 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
296 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
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 },
309 static const struct message setfont_seq
[] =
311 { WM_SETFONT
, sent
},
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 },
322 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
323 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
327 static const struct message setstyle_static_seq
[] =
329 { BM_SETSTYLE
, sent
},
330 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
331 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
332 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
334 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
335 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
339 static const struct message setstyle_user_seq
[] =
341 { BM_SETSTYLE
, sent
},
342 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
343 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
344 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
346 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
347 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
351 static const struct message setstyle_ownerdraw_seq
[] =
353 { BM_SETSTYLE
, sent
},
354 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
355 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
356 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
358 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
359 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
360 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
364 static const struct message setstate_seq
[] =
366 { BM_SETSTATE
, sent
},
367 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
369 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
370 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
374 static const struct message setstate_static_seq
[] =
376 { BM_SETSTATE
, sent
},
377 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
379 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
380 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
384 static const struct message setstate_user_seq
[] =
386 { BM_SETSTATE
, sent
},
387 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
388 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
390 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
391 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
395 static const struct message setstate_ownerdraw_seq
[] =
397 { BM_SETSTATE
, sent
},
398 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
400 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
401 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
402 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
406 static const struct message clearstate_seq
[] =
408 { BM_SETSTATE
, sent
},
409 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
410 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
412 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
413 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
417 static const struct message clearstate_ownerdraw_seq
[] =
419 { BM_SETSTATE
, sent
},
420 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
422 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
423 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
424 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
428 static const struct message setcheck_ignored_seq
[] =
430 { BM_SETCHECK
, sent
},
431 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
435 static const struct message setcheck_uncheck_seq
[] =
437 { BM_SETCHECK
, sent
},
438 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
442 static const struct message setcheck_static_seq
[] =
444 { BM_SETCHECK
, sent
},
445 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
447 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
448 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
452 static const struct message setcheck_radio_seq
[] =
454 { BM_SETCHECK
, sent
},
455 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
456 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
457 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
461 static const struct message setcheck_radio_redraw_seq
[] =
463 { BM_SETCHECK
, sent
},
464 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
465 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
466 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
468 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
469 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
473 static HWND
create_button(DWORD style
, HWND parent
)
480 style
|= WS_CHILD
|BS_NOTIFY
;
481 menuid
= (HMENU
)ID_BUTTON
;
483 hwnd
= CreateWindowExA(0, "Button", "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
484 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
485 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
489 static void test_button_messages(void)
495 const struct message
*setfocus
;
496 const struct message
*killfocus
;
497 const struct message
*setstyle
;
498 const struct message
*setstate
;
499 const struct message
*clearstate
;
500 const struct message
*setcheck
;
502 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
503 setfocus_seq
, killfocus_seq
, setstyle_seq
,
504 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
505 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
506 setfocus_seq
, killfocus_seq
, setstyle_seq
,
507 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
508 { BS_CHECKBOX
, DLGC_BUTTON
,
509 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
510 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
511 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
512 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
513 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
514 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
515 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
516 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
517 { BS_3STATE
, DLGC_BUTTON
,
518 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
519 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
520 { BS_AUTO3STATE
, DLGC_BUTTON
,
521 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
522 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
523 { BS_GROUPBOX
, DLGC_STATIC
,
524 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
525 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
},
526 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
527 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
528 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
},
529 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
530 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
531 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
532 { BS_OWNERDRAW
, DLGC_BUTTON
,
533 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
534 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
},
536 const struct message
*seq
;
543 /* selection with VK_SPACE should capture button window */
544 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
545 ok(hwnd
!= 0, "Failed to create button window\n");
548 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
549 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
550 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
553 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
554 100, 100, 200, 200, 0, 0, 0, NULL
);
555 ok(parent
!= 0, "Failed to create parent window\n");
557 for (i
= 0; i
< sizeof(button
)/sizeof(button
[0]); i
++)
562 trace("%d: button test sequence\n", i
);
563 hwnd
= create_button(button
[i
].style
, parent
);
565 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
566 style
&= ~(WS_CHILD
| BS_NOTIFY
);
567 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
568 if (button
[i
].style
== BS_USERBUTTON
)
569 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
571 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
573 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
574 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
576 ShowWindow(hwnd
, SW_SHOW
);
581 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
583 todo
= button
[i
].style
!= BS_OWNERDRAW
;
584 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
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
].setfocus
, "SetFocus(hwnd) on a button", todo
);
590 todo
= button
[i
].style
== BS_OWNERDRAW
;
592 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
593 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
594 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", todo
);
595 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
597 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
598 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
599 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
600 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", TRUE
);
602 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
603 style
&= ~(WS_VISIBLE
| WS_CHILD
| BS_NOTIFY
);
604 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
605 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
607 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
608 ok(state
== 0, "expected state 0, got %04x\n", state
);
610 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
612 SendMessageA(hwnd
, BM_SETSTATE
, TRUE
, 0);
613 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
614 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
615 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstate
, "BM_SETSTATE/TRUE on a button", TRUE
);
617 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
618 ok(state
== BST_PUSHED
, "expected state 0x0004, got %04x\n", state
);
620 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
621 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
622 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
624 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
626 SendMessageA(hwnd
, BM_SETSTATE
, FALSE
, 0);
627 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
628 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
629 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].clearstate
, "BM_SETSTATE/FALSE on a button", TRUE
);
631 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
632 ok(state
== 0, "expected state 0, got %04x\n", state
);
634 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
635 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
636 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
638 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
639 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
641 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
643 if (button
[i
].style
== BS_RADIOBUTTON
||
644 button
[i
].style
== BS_AUTORADIOBUTTON
)
646 seq
= setcheck_radio_seq
;
651 seq
= setcheck_ignored_seq
;
654 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
655 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
656 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
657 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", todo
);
659 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
660 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
662 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
663 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
664 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
666 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
668 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
669 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
670 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
672 if (button
[i
].style
== BS_PUSHBUTTON
||
673 button
[i
].style
== BS_DEFPUSHBUTTON
||
674 button
[i
].style
== BS_GROUPBOX
||
675 button
[i
].style
== BS_USERBUTTON
||
676 button
[i
].style
== BS_OWNERDRAW
)
678 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
679 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
680 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
684 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", TRUE
);
685 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
686 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
689 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
690 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
691 if (button
[i
].style
== BS_RADIOBUTTON
||
692 button
[i
].style
== BS_AUTORADIOBUTTON
)
693 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
695 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
700 DestroyWindow(parent
);
702 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
704 SetForegroundWindow(hwnd
);
707 SetActiveWindow(hwnd
);
709 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
711 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
712 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
714 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
715 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
717 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
718 zfont
= GetStockObject(SYSTEM_FONT
);
719 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
721 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
726 static void test_button_class(void)
728 static const WCHAR testW
[] = {'t','e','s','t',0};
729 WNDCLASSEXW exW
, ex2W
;
737 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
738 ok(ret
, "got %d\n", ret
);
740 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
742 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
743 ok(ret
, "got %d\n", ret
);
744 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
746 /* check that versioned class is also accessible */
747 nameW
= get_versioned_classname(WC_BUTTONW
);
748 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
750 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
752 ok(ret
, "got %d\n", ret
);
753 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
756 /* Check reported class name */
757 hwnd
= create_button(BS_CHECKBOX
, NULL
);
758 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
759 ok(len
== strlen(buffA
), "got %d\n", len
);
760 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
762 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
763 ok(len
== strlen(buffA
), "got %d\n", len
);
764 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
767 /* explicitely create with versioned class name */
768 hwnd
= CreateWindowExW(0, nameW
, testW
, BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
770 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
773 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
774 ok(len
== strlen(buffA
), "got %d\n", len
);
775 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
777 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
778 ok(len
== strlen(buffA
), "got %d\n", len
);
779 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
785 static void register_parent_class(void)
790 cls
.lpfnWndProc
= test_parent_wndproc
;
793 cls
.hInstance
= GetModuleHandleA(0);
795 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
796 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
797 cls
.lpszMenuName
= NULL
;
798 cls
.lpszClassName
= "TestParentClass";
799 RegisterClassA(&cls
);
804 ULONG_PTR ctx_cookie
;
807 if (!load_v6_module(&ctx_cookie
, &hCtx
))
810 register_parent_class();
813 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
816 test_button_messages();
818 unload_v6_module(ctx_cookie
, hCtx
);