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
25 //#include <windows.h>
33 #include "wine/test.h"
37 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
39 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
40 static BOOL (WINAPI
*pRemoveWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
);
41 static LRESULT (WINAPI
*pDefSubclassProc
)(HWND
, UINT
, WPARAM
, LPARAM
);
43 /****************** button message test *************************/
44 #define ID_BUTTON 0x000e
46 #define COMBINED_SEQ_INDEX 0
47 #define NUM_MSG_SEQUENCES 1
49 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
51 struct wndclass_redirect_data
61 /* returned pointer is valid as long as activation context is alive */
62 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
64 BOOL (WINAPI
*pFindActCtxSectionStringW
)(DWORD
,const GUID
*,ULONG
,LPCWSTR
,PACTCTX_SECTION_KEYED_DATA
);
65 struct wndclass_redirect_data
*wnddata
;
66 ACTCTX_SECTION_KEYED_DATA data
;
69 pFindActCtxSectionStringW
= (void*)GetProcAddress(GetModuleHandleA("kernel32"), "FindActCtxSectionStringW");
71 memset(&data
, 0, sizeof(data
));
72 data
.cbSize
= sizeof(data
);
74 ret
= pFindActCtxSectionStringW(0, NULL
,
75 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
77 ok(ret
, "got %d, error %u\n", ret
, GetLastError());
78 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
79 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
82 static void init_functions(void)
84 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
85 ok(hmod
!= NULL
, "got %p\n", hmod
);
87 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
88 MAKEFUNC_ORD(SetWindowSubclass
, 410);
89 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
90 MAKEFUNC_ORD(DefSubclassProc
, 413);
94 /* try to make sure pending X events have been processed before continuing */
95 static void flush_events(void)
99 int min_timeout
= 100;
100 DWORD time
= GetTickCount() + diff
;
104 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
105 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
106 diff
= time
- GetTickCount();
110 static BOOL
ignore_message( UINT message
)
112 /* these are always ignored */
113 return (message
>= 0xc000 ||
114 message
== WM_GETICON
||
115 message
== WM_GETOBJECT
||
116 message
== WM_TIMECHANGE
||
117 message
== WM_DISPLAYCHANGE
||
118 message
== WM_DEVICECHANGE
||
119 message
== WM_DWMNCRENDERINGCHANGED
||
120 message
== WM_GETTEXTLENGTH
||
121 message
== WM_GETTEXT
);
124 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
126 static LONG defwndproc_counter
= 0;
130 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
138 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
141 msg
.message
= message
;
142 msg
.flags
= sent
|wparam
|lparam
;
143 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
146 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
149 if (message
== WM_NCDESTROY
)
150 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
152 defwndproc_counter
++;
153 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
154 defwndproc_counter
--;
159 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
161 static LONG defwndproc_counter
= 0;
162 static LONG beginpaint_counter
= 0;
166 if (ignore_message( message
)) return 0;
168 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
169 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
170 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
171 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
172 message
== WM_IME_SETCONTEXT
)
185 msg
.message
= message
;
186 msg
.flags
= sent
|parent
|wparam
|lparam
;
187 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
188 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
191 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
194 if (message
== WM_PAINT
)
197 beginpaint_counter
++;
198 BeginPaint( hwnd
, &ps
);
199 beginpaint_counter
--;
200 EndPaint( hwnd
, &ps
);
204 defwndproc_counter
++;
205 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
206 defwndproc_counter
--;
211 static const struct message setfocus_seq
[] =
213 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
214 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
215 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
216 { WM_SETFOCUS
, sent
|wparam
},
217 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
218 { WM_APP
, sent
|wparam
|lparam
},
223 static const struct message killfocus_seq
[] =
225 { WM_KILLFOCUS
, sent
|wparam
, 0 },
226 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
227 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
228 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
229 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
234 static const struct message setfocus_static_seq
[] =
236 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
237 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
238 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
239 { WM_SETFOCUS
, sent
|wparam
, 0 },
240 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
241 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
242 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
247 static const struct message setfocus_groupbox_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_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
254 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
255 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
260 static const struct message killfocus_static_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 },
271 static const struct message setfocus_ownerdraw_seq
[] =
273 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
274 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
275 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
276 { WM_SETFOCUS
, sent
|wparam
, 0 },
277 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
278 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
279 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
280 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
284 static const struct message killfocus_ownerdraw_seq
[] =
286 { WM_KILLFOCUS
, sent
|wparam
, 0 },
287 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
288 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
289 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
290 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
292 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
296 static const struct message lbuttondown_seq
[] =
298 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
299 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
300 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
301 { BM_GETSTATE
, sent
|defwinproc
|optional
}, /* when touchscreen is present */
302 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
303 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
307 static const struct message lbuttonup_seq
[] =
309 { WM_LBUTTONUP
, sent
|wparam
|lparam
, 0, 0 },
310 { BM_SETSTATE
, sent
|wparam
|defwinproc
, FALSE
},
311 { WM_CAPTURECHANGED
, sent
|wparam
|defwinproc
, 0 },
312 { WM_COMMAND
, sent
|wparam
|defwinproc
, 0 },
316 static const struct message setfont_seq
[] =
318 { WM_SETFONT
, sent
},
322 static const struct message setstyle_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 },
329 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
330 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
331 { WM_PAINT
, sent
|optional
},
335 static const struct message setstyle_static_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
|defwinproc
|optional
}, /* FIXME: Wine sends it */
343 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
347 static const struct message setstyle_user_seq
[] =
349 { BM_SETSTYLE
, sent
},
350 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
351 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
352 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
354 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
355 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
359 static const struct message setstyle_ownerdraw_seq
[] =
361 { BM_SETSTYLE
, sent
},
362 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
363 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
364 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
366 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
367 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
368 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
372 static const struct message setstate_seq
[] =
374 { BM_SETSTATE
, sent
},
375 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
377 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
378 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
379 { WM_PAINT
, sent
|optional
},
383 static const struct message setstate_static_seq
[] =
385 { BM_SETSTATE
, sent
},
386 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
388 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
389 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
393 static const struct message setstate_user_seq
[] =
395 { BM_SETSTATE
, sent
},
396 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
397 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
399 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
400 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
404 static const struct message setstate_ownerdraw_seq
[] =
406 { BM_SETSTATE
, sent
},
407 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
409 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
410 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
411 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
415 static const struct message clearstate_seq
[] =
417 { BM_SETSTATE
, sent
},
418 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
419 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
421 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
422 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
426 static const struct message clearstate_ownerdraw_seq
[] =
428 { BM_SETSTATE
, sent
},
429 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
431 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
432 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
433 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
437 static const struct message setcheck_ignored_seq
[] =
439 { BM_SETCHECK
, sent
},
440 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
441 { WM_PAINT
, sent
|optional
},
445 static const struct message setcheck_static_seq
[] =
447 { BM_SETCHECK
, sent
},
448 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
450 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
451 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
455 static const struct message setcheck_radio_seq
[] =
457 { BM_SETCHECK
, sent
},
458 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
459 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
460 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
464 static const struct message setcheck_radio_redraw_seq
[] =
466 { BM_SETCHECK
, sent
},
467 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
468 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
469 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
471 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
472 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
476 static HWND
create_button(DWORD style
, HWND parent
)
483 style
|= WS_CHILD
|BS_NOTIFY
;
484 menuid
= (HMENU
)ID_BUTTON
;
486 hwnd
= CreateWindowExA(0, "Button", "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
487 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
488 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
492 static void test_button_messages(void)
498 const struct message
*setfocus
;
499 const struct message
*killfocus
;
500 const struct message
*setstyle
;
501 const struct message
*setstate
;
502 const struct message
*clearstate
;
503 const struct message
*setcheck
;
505 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
506 setfocus_seq
, killfocus_seq
, setstyle_seq
,
507 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
508 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
509 setfocus_seq
, killfocus_seq
, setstyle_seq
,
510 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
511 { BS_CHECKBOX
, DLGC_BUTTON
,
512 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
513 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
514 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
515 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
516 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
517 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
518 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
519 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
520 { BS_3STATE
, DLGC_BUTTON
,
521 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
522 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
523 { BS_AUTO3STATE
, DLGC_BUTTON
,
524 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
525 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
526 { BS_GROUPBOX
, DLGC_STATIC
,
527 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
528 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
},
529 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
530 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
531 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
},
532 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
533 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
534 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
535 { BS_OWNERDRAW
, DLGC_BUTTON
,
536 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
537 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
},
539 const struct message
*seq
;
546 /* selection with VK_SPACE should capture button window */
547 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
548 ok(hwnd
!= 0, "Failed to create button window\n");
551 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
552 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
553 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
556 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
557 100, 100, 200, 200, 0, 0, 0, NULL
);
558 ok(parent
!= 0, "Failed to create parent window\n");
560 for (i
= 0; i
< sizeof(button
)/sizeof(button
[0]); i
++)
565 trace("%d: button test sequence\n", i
);
566 hwnd
= create_button(button
[i
].style
, parent
);
568 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
569 style
&= ~(WS_CHILD
| BS_NOTIFY
);
570 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
571 if (button
[i
].style
== BS_USERBUTTON
)
572 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
574 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
576 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
577 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
579 ShowWindow(hwnd
, SW_SHOW
);
584 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
586 todo
= button
[i
].style
!= BS_OWNERDRAW
;
587 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
589 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
590 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
591 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setfocus
, "SetFocus(hwnd) on a button", todo
);
593 todo
= button
[i
].style
== BS_OWNERDRAW
;
595 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
596 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
597 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", todo
);
598 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
600 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
601 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
602 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
603 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", TRUE
);
605 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
606 style
&= ~(WS_VISIBLE
| WS_CHILD
| BS_NOTIFY
);
607 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
608 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
610 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
611 ok(state
== 0, "expected state 0, got %04x\n", state
);
613 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
615 SendMessageA(hwnd
, BM_SETSTATE
, TRUE
, 0);
616 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
617 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
618 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstate
, "BM_SETSTATE/TRUE on a button", TRUE
);
620 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
621 ok(state
== BST_PUSHED
, "expected state 0x0004, got %04x\n", state
);
623 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
624 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
625 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
627 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
629 SendMessageA(hwnd
, BM_SETSTATE
, FALSE
, 0);
630 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
631 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
632 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].clearstate
, "BM_SETSTATE/FALSE on a button", TRUE
);
634 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
635 ok(state
== 0, "expected state 0, got %04x\n", state
);
637 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
638 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
639 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
641 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
642 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
644 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
646 if (button
[i
].style
== BS_RADIOBUTTON
||
647 button
[i
].style
== BS_AUTORADIOBUTTON
)
649 seq
= setcheck_radio_seq
;
654 seq
= setcheck_ignored_seq
;
657 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
658 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
659 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
660 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", todo
);
662 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
663 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
665 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
666 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
667 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
669 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
671 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
672 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
673 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
675 if (button
[i
].style
== BS_PUSHBUTTON
||
676 button
[i
].style
== BS_DEFPUSHBUTTON
||
677 button
[i
].style
== BS_GROUPBOX
||
678 button
[i
].style
== BS_USERBUTTON
||
679 button
[i
].style
== BS_OWNERDRAW
)
681 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
682 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
683 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
687 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", TRUE
);
688 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
689 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
692 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
693 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
694 if (button
[i
].style
== BS_RADIOBUTTON
||
695 button
[i
].style
== BS_AUTORADIOBUTTON
)
696 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
698 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
703 DestroyWindow(parent
);
705 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
707 SetForegroundWindow(hwnd
);
710 SetActiveWindow(hwnd
);
712 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
714 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
715 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
717 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
718 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
720 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
721 zfont
= GetStockObject(SYSTEM_FONT
);
722 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
724 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
729 static void test_button_class(void)
731 static const WCHAR testW
[] = {'t','e','s','t',0};
732 WNDCLASSEXW exW
, ex2W
;
740 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
741 ok(ret
, "got %d\n", ret
);
743 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
745 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
746 ok(ret
, "got %d\n", ret
);
747 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
749 /* check that versioned class is also accessible */
750 nameW
= get_versioned_classname(WC_BUTTONW
);
751 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
753 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
755 ok(ret
, "got %d\n", ret
);
756 if (ret
) /* TODO: remove once Wine is fixed */
757 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
759 /* Check reported class name */
760 hwnd
= create_button(BS_CHECKBOX
, NULL
);
761 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
762 ok(len
== strlen(buffA
), "got %d\n", len
);
763 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
765 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
766 ok(len
== strlen(buffA
), "got %d\n", len
);
767 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
770 /* explicitly create with versioned class name */
771 hwnd
= CreateWindowExW(0, nameW
, testW
, BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
773 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
776 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
777 ok(len
== strlen(buffA
), "got %d\n", len
);
778 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
780 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
781 ok(len
== strlen(buffA
), "got %d\n", len
);
782 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
788 static void register_parent_class(void)
793 cls
.lpfnWndProc
= test_parent_wndproc
;
796 cls
.hInstance
= GetModuleHandleA(0);
798 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
799 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
800 cls
.lpszMenuName
= NULL
;
801 cls
.lpszClassName
= "TestParentClass";
802 RegisterClassA(&cls
);
807 ULONG_PTR ctx_cookie
;
810 if (!load_v6_module(&ctx_cookie
, &hCtx
))
813 register_parent_class();
816 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
819 test_button_messages();
821 unload_v6_module(ctx_cookie
, hCtx
);