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
);
35 static HIMAGELIST (WINAPI
*pImageList_Create
)(int, int, UINT
, int, int);
36 static int (WINAPI
*pImageList_Add
)(HIMAGELIST
, HBITMAP
, HBITMAP
);
37 static BOOL (WINAPI
*pImageList_Destroy
)(HIMAGELIST
);
39 /****************** button message test *************************/
40 #define ID_BUTTON 0x000e
42 #define COMBINED_SEQ_INDEX 0
43 #define NUM_MSG_SEQUENCES 1
45 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
47 struct wndclass_redirect_data
57 /* returned pointer is valid as long as activation context is alive */
58 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
60 struct wndclass_redirect_data
*wnddata
;
61 ACTCTX_SECTION_KEYED_DATA data
;
64 memset(&data
, 0, sizeof(data
));
65 data
.cbSize
= sizeof(data
);
66 ret
= FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
, name
, &data
);
67 ok(ret
, "Failed to find class redirection section, error %u\n", GetLastError());
68 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
69 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
72 static void init_functions(void)
74 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
75 ok(hmod
!= NULL
, "got %p\n", hmod
);
77 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
78 MAKEFUNC_ORD(SetWindowSubclass
, 410);
79 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
80 MAKEFUNC_ORD(DefSubclassProc
, 413);
83 #define X(f) p##f = (void *)GetProcAddress(hmod, #f);
90 /* try to make sure pending X events have been processed before continuing */
91 static void flush_events(void)
95 int min_timeout
= 100;
96 DWORD time
= GetTickCount() + diff
;
100 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
101 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
102 diff
= time
- GetTickCount();
106 static BOOL
ignore_message( UINT message
)
108 /* these are always ignored */
109 return (message
>= 0xc000 ||
110 message
== WM_GETICON
||
111 message
== WM_GETOBJECT
||
112 message
== WM_TIMECHANGE
||
113 message
== WM_DISPLAYCHANGE
||
114 message
== WM_DEVICECHANGE
||
115 message
== WM_DWMNCRENDERINGCHANGED
||
116 message
== WM_GETTEXTLENGTH
||
117 message
== WM_GETTEXT
);
120 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
122 static LONG defwndproc_counter
= 0;
123 struct message msg
= { 0 };
126 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
134 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
137 msg
.message
= message
;
138 msg
.flags
= sent
|wparam
|lparam
;
139 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
142 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
145 if (message
== WM_NCDESTROY
)
146 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
148 defwndproc_counter
++;
149 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
150 defwndproc_counter
--;
155 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
157 static LONG defwndproc_counter
= 0;
158 static LONG beginpaint_counter
= 0;
159 struct message msg
= { 0 };
162 if (ignore_message( message
)) return 0;
164 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
165 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
166 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
167 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
168 message
== WM_IME_SETCONTEXT
)
170 msg
.message
= message
;
171 msg
.flags
= sent
|parent
|wparam
|lparam
;
172 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
173 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
176 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
179 if (message
== WM_PAINT
)
182 beginpaint_counter
++;
183 BeginPaint( hwnd
, &ps
);
184 beginpaint_counter
--;
185 EndPaint( hwnd
, &ps
);
189 defwndproc_counter
++;
190 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
191 defwndproc_counter
--;
196 static const struct message setfocus_seq
[] =
198 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
199 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
200 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
201 { WM_SETFOCUS
, sent
|wparam
},
202 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
203 { WM_APP
, sent
|wparam
|lparam
},
208 static const struct message killfocus_seq
[] =
210 { WM_KILLFOCUS
, sent
|wparam
, 0 },
211 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
212 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
213 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
214 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
219 static const struct message setfocus_static_seq
[] =
221 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
222 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
223 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
224 { WM_SETFOCUS
, sent
|wparam
, 0 },
225 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
226 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
227 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
232 static const struct message setfocus_groupbox_seq
[] =
234 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
235 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
236 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
237 { WM_SETFOCUS
, sent
|wparam
, 0 },
238 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
239 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
240 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
245 static const struct message killfocus_static_seq
[] =
247 { WM_KILLFOCUS
, sent
|wparam
, 0 },
248 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
249 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
250 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
251 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
256 static const struct message setfocus_ownerdraw_seq
[] =
258 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
259 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
260 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
261 { WM_SETFOCUS
, sent
|wparam
, 0 },
262 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
263 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
264 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
265 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
269 static const struct message killfocus_ownerdraw_seq
[] =
271 { WM_KILLFOCUS
, sent
|wparam
, 0 },
272 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
273 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
274 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
275 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
277 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
281 static const struct message lbuttondown_seq
[] =
283 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
284 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
285 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
286 { BM_GETSTATE
, sent
|defwinproc
|optional
}, /* when touchscreen is present */
287 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
288 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
292 static const struct message lbuttonup_seq
[] =
294 { WM_LBUTTONUP
, sent
|wparam
|lparam
, 0, 0 },
295 { BM_SETSTATE
, sent
|wparam
|defwinproc
, FALSE
},
296 { WM_CAPTURECHANGED
, sent
|wparam
|defwinproc
, 0 },
297 { WM_COMMAND
, sent
|wparam
|defwinproc
, 0 },
301 static const struct message setfont_seq
[] =
303 { WM_SETFONT
, sent
},
307 static const struct message setstyle_seq
[] =
309 { BM_SETSTYLE
, sent
},
310 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
311 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
312 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
314 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
315 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
316 { WM_PAINT
, sent
|optional
},
320 static const struct message setstyle_static_seq
[] =
322 { BM_SETSTYLE
, sent
},
323 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
324 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
325 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
327 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
328 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
332 static const struct message setstyle_user_seq
[] =
334 { BM_SETSTYLE
, sent
},
335 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
336 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
337 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
339 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
340 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
344 static const struct message setstyle_ownerdraw_seq
[] =
346 { BM_SETSTYLE
, sent
},
347 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
348 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
349 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
351 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
352 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
353 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
357 static const struct message setstate_seq
[] =
359 { BM_SETSTATE
, sent
},
360 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
362 { WM_PAINT
, sent
|optional
},
366 static const struct message setstate_static_seq
[] =
368 { BM_SETSTATE
, sent
},
369 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
371 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
372 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
376 static const struct message setstate_user_seq
[] =
378 { BM_SETSTATE
, sent
},
379 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
380 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
385 static const struct message setstate_ownerdraw_seq
[] =
387 { BM_SETSTATE
, sent
},
388 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
390 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
391 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
392 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
396 static const struct message clearstate_seq
[] =
398 { BM_SETSTATE
, sent
},
399 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
400 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
402 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
403 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
407 static const struct message clearstate_ownerdraw_seq
[] =
409 { BM_SETSTATE
, sent
},
410 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
412 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
413 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
414 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
418 static const struct message setcheck_ignored_seq
[] =
420 { BM_SETCHECK
, sent
},
421 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
422 { WM_PAINT
, sent
|optional
},
426 static const struct message setcheck_static_seq
[] =
428 { BM_SETCHECK
, sent
},
429 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
431 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
432 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
436 static const struct message setcheck_radio_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 },
445 static const struct message setcheck_radio_redraw_seq
[] =
447 { BM_SETCHECK
, sent
},
448 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
449 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
450 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
452 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
456 static HWND
create_button(DWORD style
, HWND parent
)
463 style
|= WS_CHILD
|BS_NOTIFY
;
464 menuid
= (HMENU
)ID_BUTTON
;
466 hwnd
= CreateWindowExA(0, WC_BUTTONA
, "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
467 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
468 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
472 static void test_button_messages(void)
478 const struct message
*setfocus
;
479 const struct message
*killfocus
;
480 const struct message
*setstyle
;
481 const struct message
*setstate
;
482 const struct message
*clearstate
;
483 const struct message
*setcheck
;
485 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
486 setfocus_seq
, killfocus_seq
, setstyle_seq
,
487 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
488 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
489 setfocus_seq
, killfocus_seq
, setstyle_seq
,
490 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
491 { BS_CHECKBOX
, DLGC_BUTTON
,
492 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
493 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
494 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
495 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
496 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
497 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
498 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
499 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
500 { BS_3STATE
, DLGC_BUTTON
,
501 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
502 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
503 { BS_AUTO3STATE
, DLGC_BUTTON
,
504 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
505 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
},
506 { BS_GROUPBOX
, DLGC_STATIC
,
507 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
508 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
},
509 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
510 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
511 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
},
512 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
513 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
514 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
},
515 { BS_OWNERDRAW
, DLGC_BUTTON
,
516 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
517 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
},
518 { BS_SPLITBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
| DLGC_WANTARROWS
,
519 setfocus_seq
, killfocus_seq
, setstyle_seq
,
520 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
521 { BS_DEFSPLITBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
| DLGC_WANTARROWS
,
522 setfocus_seq
, killfocus_seq
, setstyle_seq
,
523 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
524 { BS_COMMANDLINK
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
525 setfocus_seq
, killfocus_seq
, setstyle_seq
,
526 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
527 { BS_DEFCOMMANDLINK
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
528 setfocus_seq
, killfocus_seq
, setstyle_seq
,
529 setstate_seq
, setstate_seq
, setcheck_ignored_seq
},
531 LOGFONTA logfont
= { 0 };
532 const struct message
*seq
;
539 /* selection with VK_SPACE should capture button window */
540 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
541 ok(hwnd
!= 0, "Failed to create button window\n");
544 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
545 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
546 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
549 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
550 100, 100, 200, 200, 0, 0, 0, NULL
);
551 ok(parent
!= 0, "Failed to create parent window\n");
553 logfont
.lfHeight
= -12;
554 logfont
.lfWeight
= FW_NORMAL
;
555 strcpy(logfont
.lfFaceName
, "Tahoma");
557 hfont2
= CreateFontIndirectA(&logfont
);
558 ok(hfont2
!= NULL
, "Failed to create Tahoma font\n");
560 for (i
= 0; i
< ARRAY_SIZE(button
); i
++)
562 HFONT prevfont
, hfont
;
567 hwnd
= create_button(button
[i
].style
, parent
);
568 ok(hwnd
!= NULL
, "Failed to create a button.\n");
570 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
571 style
&= ~(WS_CHILD
| BS_NOTIFY
);
572 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
573 if (button
[i
].style
== BS_USERBUTTON
)
574 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
576 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
578 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
579 if (button
[i
].style
== BS_SPLITBUTTON
||
580 button
[i
].style
== BS_DEFSPLITBUTTON
||
581 button
[i
].style
== BS_COMMANDLINK
||
582 button
[i
].style
== BS_DEFCOMMANDLINK
)
584 ok(dlg_code
== button
[i
].dlg_code
|| broken(dlg_code
== DLGC_BUTTON
) /* WinXP */, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
587 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
589 ShowWindow(hwnd
, SW_SHOW
);
594 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
596 todo
= button
[i
].style
!= BS_OWNERDRAW
;
597 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
599 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
600 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
601 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setfocus
, "SetFocus(hwnd) on a button", todo
);
603 todo
= button
[i
].style
== BS_OWNERDRAW
;
605 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
606 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
607 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", todo
);
608 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
610 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
611 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
612 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
613 todo
= button
[i
].style
== BS_OWNERDRAW
;
614 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", todo
);
616 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
617 style
&= ~(WS_VISIBLE
| WS_CHILD
| BS_NOTIFY
);
618 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
619 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
621 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
622 ok(state
== 0, "expected state 0, got %04x\n", state
);
624 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
626 SendMessageA(hwnd
, BM_SETSTATE
, TRUE
, 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
].setstate
, "BM_SETSTATE/TRUE on a button", FALSE
);
631 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
632 ok(state
== BST_PUSHED
, "expected state 0x0004, 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 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
640 SendMessageA(hwnd
, BM_SETSTATE
, FALSE
, 0);
641 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
642 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
643 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].clearstate
, "BM_SETSTATE/FALSE on a button", FALSE
);
645 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
646 ok(state
== 0, "expected state 0, got %04x\n", state
);
648 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
649 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
650 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
652 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
653 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
655 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
657 if (button
[i
].style
== BS_RADIOBUTTON
||
658 button
[i
].style
== BS_AUTORADIOBUTTON
)
660 seq
= setcheck_radio_seq
;
663 seq
= setcheck_ignored_seq
;
665 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
666 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
667 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
668 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", FALSE
);
670 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
671 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
673 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
674 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
675 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
677 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
679 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
680 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
681 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
682 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
684 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
685 if (button
[i
].style
== BS_PUSHBUTTON
||
686 button
[i
].style
== BS_DEFPUSHBUTTON
||
687 button
[i
].style
== BS_GROUPBOX
||
688 button
[i
].style
== BS_USERBUTTON
||
689 button
[i
].style
== BS_OWNERDRAW
||
690 button
[i
].style
== BS_SPLITBUTTON
||
691 button
[i
].style
== BS_DEFSPLITBUTTON
||
692 button
[i
].style
== BS_COMMANDLINK
||
693 button
[i
].style
== BS_DEFCOMMANDLINK
)
695 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
698 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
700 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
701 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
702 if (button
[i
].style
== BS_RADIOBUTTON
||
703 button
[i
].style
== BS_AUTORADIOBUTTON
)
704 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
706 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
708 /* Test that original font is not selected back after painting */
709 hfont
= (HFONT
)SendMessageA(hwnd
, WM_GETFONT
, 0, 0);
710 ok(hfont
== NULL
, "Unexpected control font.\n");
712 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)GetStockObject(SYSTEM_FONT
), 0);
714 hdc
= CreateCompatibleDC(0);
716 prevfont
= SelectObject(hdc
, hfont2
);
717 SendMessageA(hwnd
, WM_PRINTCLIENT
, (WPARAM
)hdc
, 0);
718 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
719 "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i
);
720 SelectObject(hdc
, prevfont
);
722 prevfont
= SelectObject(hdc
, hfont2
);
723 SendMessageA(hwnd
, WM_PAINT
, (WPARAM
)hdc
, 0);
724 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
725 "button[%u]: unexpected font selected after WM_PAINT\n", i
);
726 SelectObject(hdc
, prevfont
);
733 DeleteObject(hfont2
);
734 DestroyWindow(parent
);
736 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
738 SetForegroundWindow(hwnd
);
741 SetActiveWindow(hwnd
);
743 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
745 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
746 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
748 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
749 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
751 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
752 zfont
= GetStockObject(SYSTEM_FONT
);
753 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
755 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
760 static void test_button_class(void)
762 static const WCHAR testW
[] = {'t','e','s','t',0};
763 WNDCLASSEXW exW
, ex2W
;
771 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
772 ok(ret
, "got %d\n", ret
);
773 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
774 ok(exA
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exA
.cbClsExtra
);
775 ok(exA
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exA
.cbWndExtra
);
777 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
778 ok(ret
, "got %d\n", ret
);
779 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
780 ok(exW
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exW
.cbClsExtra
);
781 ok(exW
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exW
.cbWndExtra
);
783 /* check that versioned class is also accessible */
784 nameW
= get_versioned_classname(WC_BUTTONW
);
785 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
787 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
788 ok(ret
, "got %d\n", ret
);
789 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
791 /* Check reported class name */
792 hwnd
= create_button(BS_CHECKBOX
, NULL
);
793 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
794 ok(len
== strlen(buffA
), "got %d\n", len
);
795 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
797 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
798 ok(len
== strlen(buffA
), "got %d\n", len
);
799 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
802 /* explicitly create with versioned class name */
803 hwnd
= CreateWindowExW(0, nameW
, testW
, BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
804 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
806 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
807 ok(len
== strlen(buffA
), "got %d\n", len
);
808 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
810 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
811 ok(len
== strlen(buffA
), "got %d\n", len
);
812 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
817 static void test_note(void)
821 WCHAR test_w
[] = {'t', 'e', 's', 't', 0};
822 WCHAR tes_w
[] = {'t', 'e', 's', 0};
823 WCHAR deadbeef_w
[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
829 hwnd
= create_button(BS_COMMANDLINK
, NULL
);
830 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
831 SetLastError(0xdeadbeef);
832 size
= ARRAY_SIZE(buffer_w
);
833 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
834 error
= GetLastError();
835 if (!ret
&& error
== 0xdeadbeef)
837 win_skip("BCM_GETNOTE message is unavailable. Skipping note tests\n"); /* xp or 2003 */
843 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
845 if (type
== BS_DEFCOMMANDLINK
|| type
== BS_COMMANDLINK
)
847 hwnd
= create_button(type
, NULL
);
848 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
850 /* Get note when note hasn't been not set yet */
851 SetLastError(0xdeadbeef);
852 lstrcpyW(buffer_w
, deadbeef_w
);
853 size
= ARRAY_SIZE(buffer_w
);
854 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
855 error
= GetLastError();
856 ok(!ret
, "Expect BCM_GETNOTE return false\n");
857 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
858 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
859 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
860 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
861 ERROR_INVALID_PARAMETER
, error
);
863 /* Get note length when note is not set */
864 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
865 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
867 /* Successful set note, get note and get note length */
868 SetLastError(0xdeadbeef);
869 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)test_w
);
870 ok(ret
, "Expect BCM_SETNOTE return true\n");
871 error
= GetLastError();
872 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
874 SetLastError(0xdeadbeef);
875 lstrcpyW(buffer_w
, deadbeef_w
);
876 size
= ARRAY_SIZE(buffer_w
);
877 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
878 ok(ret
, "Expect BCM_GETNOTE return true\n");
879 ok(!lstrcmpW(buffer_w
, test_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(test_w
),
880 wine_dbgstr_w(buffer_w
));
881 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
882 error
= GetLastError();
883 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
885 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
886 ok(ret
== ARRAY_SIZE(test_w
) - 1, "Got: %d\n", ret
);
888 /* Insufficient buffer, return partial string */
889 SetLastError(0xdeadbeef);
890 lstrcpyW(buffer_w
, deadbeef_w
);
891 size
= ARRAY_SIZE(test_w
) - 1;
892 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
893 ok(!ret
, "Expect BCM_GETNOTE return false\n");
894 ok(!lstrcmpW(buffer_w
, tes_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(tes_w
),
895 wine_dbgstr_w(buffer_w
));
896 ok(size
== ARRAY_SIZE(test_w
), "Got: %d\n", size
);
897 error
= GetLastError();
898 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
899 ERROR_INSUFFICIENT_BUFFER
, error
);
901 /* Set note with NULL buffer */
902 SetLastError(0xdeadbeef);
903 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, 0);
904 ok(ret
, "Expect BCM_SETNOTE return false\n");
905 error
= GetLastError();
906 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
908 /* Check that set note with NULL buffer make note empty */
909 SetLastError(0xdeadbeef);
910 lstrcpyW(buffer_w
, deadbeef_w
);
911 size
= ARRAY_SIZE(buffer_w
);
912 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
913 ok(ret
, "Expect BCM_GETNOTE return true\n");
914 ok(lstrlenW(buffer_w
) == 0, "Expect note length 0\n");
915 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
916 error
= GetLastError();
917 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
918 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
919 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
921 /* Get note with NULL buffer */
922 SetLastError(0xdeadbeef);
923 size
= ARRAY_SIZE(buffer_w
);
924 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, 0);
925 ok(!ret
, "Expect BCM_SETNOTE return false\n");
926 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
927 error
= GetLastError();
928 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
929 ERROR_INVALID_PARAMETER
, error
);
931 /* Get note with NULL size */
932 SetLastError(0xdeadbeef);
933 lstrcpyW(buffer_w
, deadbeef_w
);
934 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, 0, (LPARAM
)buffer_w
);
935 ok(!ret
, "Expect BCM_SETNOTE return false\n");
936 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
937 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
938 error
= GetLastError();
939 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
940 ERROR_INVALID_PARAMETER
, error
);
942 /* Get note with zero size */
943 SetLastError(0xdeadbeef);
945 lstrcpyW(buffer_w
, deadbeef_w
);
946 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
947 ok(!ret
, "Expect BCM_GETNOTE return false\n");
948 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
949 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
950 ok(size
== 1, "Got: %d\n", size
);
951 error
= GetLastError();
952 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
953 ERROR_INSUFFICIENT_BUFFER
, error
);
959 hwnd
= create_button(type
, NULL
);
960 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
961 SetLastError(0xdeadbeef);
962 size
= ARRAY_SIZE(buffer_w
);
963 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
964 ok(!ret
, "Expect BCM_GETNOTE return false\n");
965 error
= GetLastError();
966 ok(error
== ERROR_NOT_SUPPORTED
, "Expect last error: 0x%08x, got: 0x%08x\n",
967 ERROR_NOT_SUPPORTED
, error
);
973 static void test_bm_get_set_image(void)
980 ICONINFO icon_info2x2
;
986 static const DWORD default_style
= BS_PUSHBUTTON
| WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
989 hbmp1x1
= CreateCompatibleBitmap(hdc
, 1, 1);
990 hbmp2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
991 ZeroMemory(&bm
, sizeof(bm
));
992 ok(GetObjectW(hbmp1x1
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
993 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
994 bm
.bmWidth
, bm
.bmHeight
);
995 ZeroMemory(&bm
, sizeof(bm
));
996 ok(GetObjectW(hbmp2x2
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
997 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
998 bm
.bmWidth
, bm
.bmHeight
);
1000 hmask2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
1001 ZeroMemory(&icon_info2x2
, sizeof(icon_info2x2
));
1002 icon_info2x2
.fIcon
= TRUE
;
1003 icon_info2x2
.hbmMask
= hmask2x2
;
1004 icon_info2x2
.hbmColor
= hbmp2x2
;
1005 hicon2x2
= CreateIconIndirect(&icon_info2x2
);
1006 ok(hicon2x2
!=NULL
, "Expect CreateIconIndirect() success\n");
1008 ZeroMemory(&icon_info
, sizeof(icon_info
));
1009 ok(GetIconInfo(hicon2x2
, &icon_info
), "Expect GetIconInfo() success\n");
1010 ZeroMemory(&bm
, sizeof(bm
));
1011 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1012 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1013 bm
.bmWidth
, bm
.bmHeight
);
1014 DeleteObject(icon_info
.hbmColor
);
1015 DeleteObject(icon_info
.hbmMask
);
1017 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1019 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1020 /* Get image when image is not set */
1021 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1022 ok(hbmp
== 0, "Expect hbmp == 0\n");
1024 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1025 ok(hbmp
== 0, "Expect hbmp == 0\n");
1026 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1027 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1028 /* Set null resets image */
1029 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, 0);
1030 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1031 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1032 ok(hbmp
== 0, "Expect hbmp == 0\n");
1033 DestroyWindow(hwnd
);
1035 /* Set bitmap with BS_BITMAP */
1036 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1038 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1039 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1040 ok(hbmp
== 0, "Expect hbmp == 0\n");
1041 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1042 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1043 ZeroMemory(&bm
, sizeof(bm
));
1044 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1045 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1046 bm
.bmWidth
, bm
.bmHeight
);
1047 DestroyWindow(hwnd
);
1049 /* Set bitmap without BS_BITMAP */
1050 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1051 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1052 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1053 ok(hbmp
== 0, "Expect hbmp == 0\n");
1054 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1058 win_skip("Show both image and text is not supported. Skip following tests.\n");
1059 DestroyWindow(hwnd
);
1062 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1063 ZeroMemory(&bm
, sizeof(bm
));
1064 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1065 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1066 bm
.bmWidth
, bm
.bmHeight
);
1067 DestroyWindow(hwnd
);
1069 /* Set icon with BS_ICON */
1070 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1072 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1073 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1074 ok(hicon
== 0, "Expect hicon == 0\n");
1075 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1076 ok(hicon
!= 0, "Expect hicon != 0\n");
1077 ZeroMemory(&icon_info
, sizeof(icon_info
));
1078 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1079 ZeroMemory(&bm
, sizeof(bm
));
1080 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1081 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1082 bm
.bmWidth
, bm
.bmHeight
);
1083 DeleteObject(icon_info
.hbmColor
);
1084 DeleteObject(icon_info
.hbmMask
);
1085 DestroyWindow(hwnd
);
1087 /* Set icon without BS_ICON */
1088 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1089 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1090 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1091 ok(hicon
== 0, "Expect hicon == 0\n");
1092 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1093 ok(hicon
!= 0, "Expect hicon != 0\n");
1094 ZeroMemory(&icon_info
, sizeof(icon_info
));
1095 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1096 ZeroMemory(&bm
, sizeof(bm
));
1097 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1098 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1099 bm
.bmWidth
, bm
.bmHeight
);
1100 DeleteObject(icon_info
.hbmColor
);
1101 DeleteObject(icon_info
.hbmMask
);
1102 DestroyWindow(hwnd
);
1104 /* Set icon with BS_BITMAP */
1105 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1107 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1108 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1109 ok(hicon
== 0, "Expect hicon == 0\n");
1110 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1111 ok(hicon
!= 0, "Expect hicon != 0\n");
1112 ZeroMemory(&icon_info
, sizeof(icon_info
));
1113 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1114 ZeroMemory(&bm
, sizeof(bm
));
1115 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1116 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1117 bm
.bmWidth
, bm
.bmHeight
);
1118 DeleteObject(icon_info
.hbmColor
);
1119 DeleteObject(icon_info
.hbmMask
);
1120 DestroyWindow(hwnd
);
1122 /* Set bitmap with BS_ICON */
1123 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1125 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1126 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1127 ok(hbmp
== 0, "Expect hbmp == 0\n");
1128 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1129 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1130 ZeroMemory(&bm
, sizeof(bm
));
1131 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1132 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1133 bm
.bmWidth
, bm
.bmHeight
);
1134 DestroyWindow(hwnd
);
1136 /* Set bitmap with BS_BITMAP and IMAGE_ICON*/
1137 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1139 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1140 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1141 ok(hbmp
== 0, "Expect hbmp == 0\n");
1142 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1143 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1144 ZeroMemory(&bm
, sizeof(bm
));
1145 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1146 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1147 bm
.bmWidth
, bm
.bmHeight
);
1148 DestroyWindow(hwnd
);
1150 /* Set icon with BS_ICON and IMAGE_BITMAP */
1151 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1153 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1154 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1155 ok(hicon
== 0, "Expect hicon == 0\n");
1156 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1157 ok(hicon
!= 0, "Expect hicon != 0\n");
1158 ZeroMemory(&icon_info
, sizeof(icon_info
));
1159 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1160 ZeroMemory(&bm
, sizeof(bm
));
1161 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1162 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1163 bm
.bmWidth
, bm
.bmHeight
);
1164 DeleteObject(icon_info
.hbmColor
);
1165 DeleteObject(icon_info
.hbmMask
);
1166 DestroyWindow(hwnd
);
1168 /* Set bitmap with BS_ICON and IMAGE_ICON */
1169 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0, 0);
1170 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1171 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1172 ok(hbmp
== 0, "Expect hbmp == 0\n");
1173 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1174 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1175 ZeroMemory(&bm
, sizeof(bm
));
1176 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1177 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1178 bm
.bmWidth
, bm
.bmHeight
);
1179 DestroyWindow(hwnd
);
1181 /* Set icon with BS_BITMAP and IMAGE_BITMAP */
1182 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0, 0, 0);
1183 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1184 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1185 ok(hicon
== 0, "Expect hicon == 0\n");
1186 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1187 ok(hicon
!= 0, "Expect hicon != 0\n");
1188 ZeroMemory(&icon_info
, sizeof(icon_info
));
1189 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1190 ZeroMemory(&bm
, sizeof(bm
));
1191 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1192 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1193 bm
.bmWidth
, bm
.bmHeight
);
1194 DeleteObject(icon_info
.hbmColor
);
1195 DeleteObject(icon_info
.hbmMask
);
1196 DestroyWindow(hwnd
);
1199 DestroyIcon(hicon2x2
);
1200 DeleteObject(hmask2x2
);
1201 DeleteObject(hbmp2x2
);
1202 DeleteObject(hbmp1x1
);
1206 static void register_parent_class(void)
1211 cls
.lpfnWndProc
= test_parent_wndproc
;
1214 cls
.hInstance
= GetModuleHandleA(0);
1216 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1217 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
1218 cls
.lpszMenuName
= NULL
;
1219 cls
.lpszClassName
= "TestParentClass";
1220 RegisterClassA(&cls
);
1223 static void test_button_data(void)
1225 static const DWORD styles
[] =
1253 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1254 100, 100, 200, 200, 0, 0, 0, NULL
);
1255 ok(parent
!= 0, "Failed to create parent window\n");
1257 for (i
= 0; i
< ARRAY_SIZE(styles
); i
++)
1259 struct button_desc
*desc
;
1262 hwnd
= create_button(styles
[i
], parent
);
1263 ok(hwnd
!= NULL
, "Failed to create a button.\n");
1265 desc
= (void *)GetWindowLongPtrA(hwnd
, 0);
1266 ok(desc
!= NULL
, "Expected window data.\n");
1270 ok(desc
->self
== hwnd
, "Unexpected 'self' field.\n");
1271 ok(desc
->parent
== parent
, "Unexpected 'parent' field.\n");
1272 ok(desc
->style
== (WS_CHILD
| BS_NOTIFY
| styles
[i
]), "Unexpected 'style' field.\n");
1275 DestroyWindow(hwnd
);
1278 DestroyWindow(parent
);
1281 static void test_get_set_imagelist(void)
1285 BUTTON_IMAGELIST biml
= {0};
1295 hbmp
= CreateCompatibleBitmap(hdc
, width
, height
);
1296 ok(hbmp
!= NULL
, "Expect hbmp not null\n");
1298 himl
= pImageList_Create(width
, height
, ILC_COLOR
, 1, 0);
1299 ok(himl
!= NULL
, "Expect himl not null\n");
1300 index
= pImageList_Add(himl
, hbmp
, NULL
);
1301 ok(index
== 0, "Expect index == 0\n");
1305 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1307 hwnd
= create_button(type
, NULL
);
1308 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1310 /* Get imagelist when imagelist is unset yet */
1311 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1312 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1313 ok(biml
.himl
== 0 && IsRectEmpty(&biml
.margin
) && biml
.uAlign
== 0,
1314 "Expect BUTTON_IMAGELIST is empty\n");
1316 /* Set imagelist with himl null */
1318 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1319 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1320 ok(ret
|| broken(!ret
), /* xp or 2003 */
1321 "Expect BCM_SETIMAGELIST return true\n");
1323 /* Set imagelist with uAlign invalid */
1326 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1327 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1329 /* Successful get and set imagelist */
1331 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1332 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1333 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1334 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1335 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1336 ok(biml
.himl
== himl
, "Expect himl to be same\n");
1337 ok(biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_CENTER
, "Expect uAlign to be %x\n",
1338 BUTTON_IMAGELIST_ALIGN_CENTER
);
1340 /* BCM_SETIMAGELIST null pointer handling */
1341 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, 0);
1342 ok(!ret
, "Expect BCM_SETIMAGELIST return false\n");
1343 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1344 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1345 ok(biml
.himl
== himl
, "Expect himl to be same\n");
1347 /* BCM_GETIMAGELIST null pointer handling */
1349 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1350 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1351 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1352 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, 0);
1353 ok(!ret
, "Expect BCM_GETIMAGELIST return false\n");
1355 DestroyWindow(hwnd
);
1358 pImageList_Destroy(himl
);
1361 static void test_get_set_textmargin(void)
1371 margin_in
.right
= 3;
1372 margin_in
.bottom
= 4;
1373 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1375 hwnd
= create_button(type
, NULL
);
1376 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1378 /* Get text margin when it is unset */
1379 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1380 ok(ret
, "Expect ret to be true\n");
1381 ok(IsRectEmpty(&margin_out
), "Expect margin empty\n");
1383 /* Successful get and set text margin */
1384 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1385 ok(ret
, "Expect ret to be true\n");
1386 SetRectEmpty(&margin_out
);
1387 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1388 ok(ret
, "Expect ret to be true\n");
1389 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1391 /* BCM_SETTEXTMARGIN null pointer handling */
1392 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, 0);
1393 ok(!ret
, "Expect ret to be false\n");
1394 SetRectEmpty(&margin_out
);
1395 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1396 ok(ret
, "Expect ret to be true\n");
1397 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1399 /* BCM_GETTEXTMARGIN null pointer handling */
1400 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1401 ok(ret
, "Expect ret to be true\n");
1402 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, 0);
1403 ok(!ret
, "Expect ret to be true\n");
1405 DestroyWindow(hwnd
);
1409 static void test_state(void)
1415 /* Initial button state */
1416 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1418 hwnd
= create_button(type
, NULL
);
1419 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
1420 ok(state
== BST_UNCHECKED
, "Expect state 0x%08x, got 0x%08x\n", BST_UNCHECKED
, state
);
1421 DestroyWindow(hwnd
);
1425 static void test_bcm_get_ideal_size(void)
1427 static const WCHAR text2_w
[] = {'t', 'e', 'x', 't', '\n', 't', 'e', 'x', 't', 0};
1428 static const WCHAR text_w
[] = {'t', 'e', 'x', 't', 0};
1429 static const DWORD imagelist_aligns
[] = {BUTTON_IMAGELIST_ALIGN_LEFT
, BUTTON_IMAGELIST_ALIGN_RIGHT
,
1430 BUTTON_IMAGELIST_ALIGN_TOP
, BUTTON_IMAGELIST_ALIGN_BOTTOM
,
1431 BUTTON_IMAGELIST_ALIGN_CENTER
};
1432 static const DWORD aligns
[] = {0, BS_TOP
, BS_LEFT
, BS_RIGHT
, BS_BOTTOM
,
1433 BS_CENTER
, BS_VCENTER
, BS_RIGHTBUTTON
, WS_EX_RIGHT
};
1434 DWORD default_style
= WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
1435 LONG client_width
= 200, client_height
= 200;
1436 LONG width
, height
, line_count
;
1445 HBITMAP hmask
, hbmp
;
1449 BUTTON_IMAGELIST biml
= {0};
1452 /* Check for NULL pointer handling */
1453 hwnd
= CreateWindowW(WC_BUTTONW
, text_w
, BS_PUSHBUTTON
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1455 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, 0);
1456 ok(!ret
, "Expect BCM_GETIDEALSIZE message to return false.\n");
1458 /* Set font so that the test is consistent on Wine and Windows */
1459 ZeroMemory(&lf
, sizeof(lf
));
1460 lf
.lfWeight
= FW_NORMAL
;
1462 lstrcpyA(lf
.lfFaceName
, "Tahoma");
1463 hfont
= CreateFontIndirectA(&lf
);
1467 GetTextMetricsA(hdc
, &tm
);
1468 ReleaseDC(hwnd
, hdc
);
1469 DestroyWindow(hwnd
);
1471 /* XP and 2003 doesn't support command links, getting ideal size with button having only text just return client size on these platforms */
1472 hwnd
= CreateWindowA(WC_BUTTONA
, "test", BS_DEFCOMMANDLINK
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1474 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1475 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1476 ZeroMemory(&size
, sizeof(size
));
1477 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1478 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1479 if (size
.cx
== client_width
&& size
.cy
== client_width
)
1481 /* on XP and 2003, buttons with image are not supported */
1482 win_skip("Skipping further tests on XP and 2003\n");
1486 /* Tests for image placements */
1487 /* Prepare bitmap */
1491 hmask
= CreateCompatibleBitmap(hdc
, width
, height
);
1492 hbmp
= CreateCompatibleBitmap(hdc
, width
, height
);
1494 /* Only bitmap for push button, ideal size should be enough for image and text */
1495 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_DEFPUSHBUTTON
| BS_BITMAP
| default_style
, 0, 0, client_width
,
1496 client_height
, NULL
, NULL
, 0, NULL
);
1497 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1498 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
1499 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1500 ZeroMemory(&size
, sizeof(size
));
1501 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1502 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1503 /* Ideal size contains text rect even show bitmap only */
1504 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1505 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
,
1506 max(height
, tm
.tmHeight
));
1507 DestroyWindow(hwnd
);
1509 /* Image alignments when button has bitmap and text*/
1510 for (i
= 0; i
< ARRAY_SIZE(aligns
); i
++)
1511 for (j
= 0; j
< ARRAY_SIZE(aligns
); j
++)
1513 style
= BS_DEFPUSHBUTTON
| default_style
| aligns
[i
] | aligns
[j
];
1514 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
1515 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1516 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
1517 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1518 ZeroMemory(&size
, sizeof(size
));
1519 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1520 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1521 if (!(style
& (BS_CENTER
| BS_VCENTER
)) || ((style
& BS_CENTER
) && (style
& BS_CENTER
) != BS_CENTER
)
1522 || !(style
& BS_VCENTER
) || (style
& BS_VCENTER
) == BS_VCENTER
)
1523 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1524 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
1525 width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
, max(height
, tm
.tmHeight
));
1527 ok((size
.cx
>= max(4 * tm
.tmMaxCharWidth
, height
) && size
.cy
>= height
+ tm
.tmHeight
),
1528 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
1529 max(4 * tm
.tmMaxCharWidth
, height
), size
.cy
, height
+ tm
.tmHeight
);
1530 DestroyWindow(hwnd
);
1533 /* Image list alignments */
1534 himl
= pImageList_Create(width
, height
, ILC_COLOR
, 1, 1);
1535 pImageList_Add(himl
, hbmp
, 0);
1537 for (i
= 0; i
< ARRAY_SIZE(imagelist_aligns
); i
++)
1539 biml
.uAlign
= imagelist_aligns
[i
];
1540 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_DEFPUSHBUTTON
| default_style
, 0, 0, client_width
, client_height
,
1541 NULL
, NULL
, 0, NULL
);
1542 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1543 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1544 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1545 ZeroMemory(&size
, sizeof(size
));
1546 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1547 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1548 if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_TOP
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_BOTTOM
)
1549 ok((size
.cx
>= max(4 * tm
.tmMaxCharWidth
, height
) && size
.cy
>= height
+ tm
.tmHeight
),
1550 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
1551 max(4 * tm
.tmMaxCharWidth
, height
), size
.cy
, height
+ tm
.tmHeight
);
1552 else if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_LEFT
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_RIGHT
)
1553 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1554 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
1555 width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
, max(height
, tm
.tmHeight
));
1557 ok(size
.cx
>= width
&& size
.cy
>= height
, "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
1558 biml
.uAlign
, size
.cx
, width
, size
.cy
, height
);
1559 DestroyWindow(hwnd
);
1563 /* Create icon from bitmap */
1564 ZeroMemory(&icon_info
, sizeof(icon_info
));
1565 icon_info
.fIcon
= TRUE
;
1566 icon_info
.hbmMask
= hmask
;
1567 icon_info
.hbmColor
= hbmp
;
1568 hicon
= CreateIconIndirect(&icon_info
);
1570 /* Only icon, ideal size should be enough for image and text */
1571 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_DEFPUSHBUTTON
| BS_ICON
| default_style
, 0, 0, client_width
,
1572 client_height
, NULL
, NULL
, 0, NULL
);
1573 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1574 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
1575 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1576 ZeroMemory(&size
, sizeof(size
));
1577 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1578 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1579 /* Ideal size contains text rect even show icons only */
1580 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1581 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
,
1582 max(height
, tm
.tmHeight
));
1583 DestroyWindow(hwnd
);
1585 /* Show icon and text */
1586 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_DEFPUSHBUTTON
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1588 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1589 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
1590 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1591 ZeroMemory(&size
, sizeof(size
));
1592 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1593 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1594 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1595 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
,
1596 max(height
, tm
.tmHeight
));
1597 DestroyWindow(hwnd
);
1600 /* Both bitmap and text for checkbox, ideal size is only enough for text because it doesn't support image(but not image list)*/
1601 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_AUTOCHECKBOX
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1603 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1604 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
1605 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1606 ZeroMemory(&size
, sizeof(size
));
1607 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1608 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1609 ok((size
.cx
<= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cx
>= 4 * tm
.tmMaxCharWidth
1610 && size
.cy
<= max(height
, tm
.tmHeight
) && size
.cy
>= tm
.tmHeight
),
1611 "Expect ideal cx %d within range (%d, %d ) and ideal cy %d within range (%d, %d )\n", size
.cx
,
1612 4 * tm
.tmMaxCharWidth
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
, tm
.tmHeight
, max(height
, tm
.tmHeight
));
1613 DestroyWindow(hwnd
);
1615 /* Both image list and text for checkbox, ideal size should have enough for image list and text */
1616 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1617 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
1618 client_height
, NULL
, NULL
, 0, NULL
);
1619 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1620 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1621 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1622 ZeroMemory(&size
, sizeof(size
));
1623 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1624 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1625 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1626 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
,
1627 max(height
, tm
.tmHeight
));
1628 DestroyWindow(hwnd
);
1630 /* Only bitmap for checkbox, ideal size should have enough for image and text */
1631 hwnd
= CreateWindowA(WC_BUTTONA
, "WWWW", BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
1632 client_height
, NULL
, NULL
, 0, NULL
);
1633 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1634 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
1635 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1636 ZeroMemory(&size
, sizeof(size
));
1637 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1638 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1639 ok((size
.cx
>= width
+ 4 * tm
.tmMaxCharWidth
&& size
.cy
>= max(height
, tm
.tmHeight
)),
1640 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, width
+ 4 * tm
.tmMaxCharWidth
, size
.cy
,
1641 max(height
, tm
.tmHeight
));
1642 DestroyWindow(hwnd
);
1644 /* Test button with only text */
1646 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1648 style
= type
| default_style
;
1649 hwnd
= CreateWindowA(WC_BUTTONA
, "", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
1650 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1651 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1653 ZeroMemory(&size
, sizeof(size
));
1654 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1655 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1657 if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
1659 todo_wine
ok((size
.cx
== 0 && size
.cy
> 0), "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n",
1660 style
, size
.cx
, 0, size
.cy
, 0);
1664 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
1665 "Style 0x%08x expect size.cx == %d and size.cy == %d, got size.cx: %d size.cy: %d\n", style
,
1666 client_width
, client_height
, size
.cx
, size
.cy
);
1668 DestroyWindow(hwnd
);
1671 /* Single line and multiple lines text */
1672 for (line_count
= 1; line_count
<= 2; line_count
++)
1674 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1676 style
= line_count
> 1 ? type
| BS_MULTILINE
: type
;
1677 style
|= default_style
;
1679 hwnd
= CreateWindowW(WC_BUTTONW
, (line_count
== 2 ? text2_w
: text_w
), style
, 0, 0, client_width
,
1680 client_height
, NULL
, NULL
, 0, NULL
);
1681 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1682 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1683 ZeroMemory(&size
, sizeof(size
));
1684 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1685 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1687 if (type
== BS_3STATE
|| type
== BS_AUTO3STATE
|| type
== BS_GROUPBOX
|| type
== BS_PUSHBOX
1688 || type
== BS_OWNERDRAW
)
1690 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
1691 "Style 0x%08x expect ideal size (%d,%d), got (%d,%d)\n", style
, client_width
, client_height
, size
.cx
,
1694 else if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
1696 todo_wine
ok((size
.cx
== 0 && size
.cy
> 0),
1697 "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
, 0,
1703 height
= line_count
== 2 ? 2 * tm
.tmHeight
: tm
.tmHeight
;
1704 ok(size
.cx
>= width
&& size
.cy
>= height
,
1705 "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
, width
, size
.cy
,
1708 DestroyWindow(hwnd
);
1712 pImageList_Destroy(himl
);
1715 DeleteObject(hmask
);
1717 DeleteObject(hfont
);
1722 ULONG_PTR ctx_cookie
;
1725 if (!load_v6_module(&ctx_cookie
, &hCtx
))
1728 register_parent_class();
1731 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1733 test_button_class();
1734 test_button_messages();
1737 test_bm_get_set_image();
1738 test_get_set_imagelist();
1739 test_get_set_textmargin();
1741 test_bcm_get_ideal_size();
1743 unload_v6_module(ctx_cookie
, hCtx
);