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 is_theme_active
;
34 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
35 static BOOL (WINAPI
*pRemoveWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
);
36 static LRESULT (WINAPI
*pDefSubclassProc
)(HWND
, UINT
, WPARAM
, LPARAM
);
37 static HIMAGELIST (WINAPI
*pImageList_Create
)(int, int, UINT
, int, int);
38 static int (WINAPI
*pImageList_Add
)(HIMAGELIST
, HBITMAP
, HBITMAP
);
39 static BOOL (WINAPI
*pImageList_Destroy
)(HIMAGELIST
);
41 /****************** button message test *************************/
42 #define ID_BUTTON 0x000e
44 #define COMBINED_SEQ_INDEX 0
45 #define PARENT_CD_SEQ_INDEX 1
46 #define NUM_MSG_SEQUENCES 2
48 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
50 struct wndclass_redirect_data
60 /* returned pointer is valid as long as activation context is alive */
61 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
63 struct wndclass_redirect_data
*wnddata
;
64 ACTCTX_SECTION_KEYED_DATA data
;
67 memset(&data
, 0, sizeof(data
));
68 data
.cbSize
= sizeof(data
);
69 ret
= FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
, name
, &data
);
70 ok(ret
, "Failed to find class redirection section, error %u\n", GetLastError());
71 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
72 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
75 static void init_functions(void)
77 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
78 ok(hmod
!= NULL
, "got %p\n", hmod
);
80 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
81 MAKEFUNC_ORD(SetWindowSubclass
, 410);
82 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
83 MAKEFUNC_ORD(DefSubclassProc
, 413);
86 #define X(f) p##f = (void *)GetProcAddress(hmod, #f);
93 /* try to make sure pending X events have been processed before continuing */
94 static void flush_events(void)
98 int min_timeout
= 100;
99 DWORD time
= GetTickCount() + diff
;
103 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
104 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
105 diff
= time
- GetTickCount();
109 static BOOL
ignore_message( UINT message
)
111 /* these are always ignored */
112 return (message
>= 0xc000 ||
113 message
== WM_GETICON
||
114 message
== WM_GETOBJECT
||
115 message
== WM_TIMECHANGE
||
116 message
== WM_DISPLAYCHANGE
||
117 message
== WM_DEVICECHANGE
||
118 message
== WM_DWMNCRENDERINGCHANGED
||
119 message
== WM_GETTEXTLENGTH
||
120 message
== WM_GETTEXT
);
123 static BOOL
equal_dc(HDC hdc1
, HDC hdc2
, int width
, int height
)
127 for (x
= 0; x
< width
; ++x
)
129 for (y
= 0; y
< height
; ++y
)
131 if (GetPixel(hdc1
, x
, y
) != GetPixel(hdc2
, x
, y
))
139 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
141 static LONG defwndproc_counter
= 0;
142 struct message msg
= { 0 };
145 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
153 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
156 msg
.message
= message
;
157 msg
.flags
= sent
|wparam
|lparam
;
158 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
161 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
164 if (message
== WM_NCDESTROY
)
165 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
167 defwndproc_counter
++;
168 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
169 defwndproc_counter
--;
183 #define set_test_cd_state(s) do { \
184 test_cd.state = (s); \
185 test_cd.empty = TRUE; \
186 test_cd.line = __LINE__; \
189 #define set_test_cd_ret(r) do { \
191 test_cd.empty = TRUE; \
192 test_cd.line = __LINE__; \
195 static void disable_test_cd(void)
200 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
202 static LONG defwndproc_counter
= 0;
203 static LONG beginpaint_counter
= 0;
204 static HDC cd_first_hdc
;
205 struct message msg
= { 0 };
206 NMCUSTOMDRAW
*cd
= (NMCUSTOMDRAW
*)lParam
;
207 NMBCDROPDOWN
*bcd
= (NMBCDROPDOWN
*)lParam
;
210 if (ignore_message( message
)) return 0;
212 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
213 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
214 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
215 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
216 message
== WM_IME_SETCONTEXT
)
218 msg
.message
= message
;
219 msg
.flags
= sent
|parent
|wparam
|lparam
;
220 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
221 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
224 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
227 if (message
== WM_NOTIFY
&& cd
->hdr
.code
== NM_CUSTOMDRAW
&& test_cd
.line
)
229 /* Ignore an inconsistency across Windows versions */
230 UINT state
= cd
->uItemState
& ~CDIS_SHOWKEYBOARDCUES
;
232 /* Some Windows configurations paint twice with different DC */
235 cd_first_hdc
= cd
->hdc
;
236 test_cd
.empty
= FALSE
;
239 ok_(__FILE__
,test_cd
.line
)(!(cd
->dwDrawStage
& CDDS_ITEM
),
240 "[%u] CDDS_ITEM is set\n", test_cd
.button
);
242 ok_(__FILE__
,test_cd
.line
)(state
== test_cd
.state
,
243 "[%u] expected uItemState %u, got %u\n", test_cd
.button
,
244 test_cd
.state
, state
);
246 msg
.message
= message
;
247 msg
.flags
= sent
|parent
|wparam
|lparam
|id
|custdraw
;
250 msg
.id
= NM_CUSTOMDRAW
;
251 msg
.stage
= cd
->dwDrawStage
;
252 if (cd
->hdc
== cd_first_hdc
)
253 add_message(sequences
, PARENT_CD_SEQ_INDEX
, &msg
);
259 ret
&= ~CDRF_NOTIFYPOSTPAINT
;
260 cd
->dwItemSpec
= 0xdeadbeef;
263 ret
&= ~CDRF_NOTIFYPOSTERASE
;
267 ok_(__FILE__
,test_cd
.line
)(cd
->dwItemSpec
== 0xdeadbeef,
268 "[%u] NMCUSTOMDRAW was not shared, stage %u\n", test_cd
.button
, msg
.stage
);
274 if (message
== WM_NOTIFY
&& bcd
->hdr
.code
== BCN_DROPDOWN
)
276 UINT button
= GetWindowLongW(bcd
->hdr
.hwndFrom
, GWL_STYLE
) & BS_TYPEMASK
;
279 GetClientRect(bcd
->hdr
.hwndFrom
, &rc
);
281 ok(bcd
->hdr
.hwndFrom
!= NULL
, "Received BCN_DROPDOWN with no hwnd attached, wParam %lu id %lu\n",
282 wParam
, bcd
->hdr
.idFrom
);
283 ok(bcd
->hdr
.idFrom
== wParam
, "[%u] Mismatch between wParam (%lu) and idFrom (%lu)\n",
284 button
, wParam
, bcd
->hdr
.idFrom
);
285 ok(EqualRect(&rc
, &bcd
->rcButton
), "[%u] Wrong rcButton, expected %s got %s\n",
286 button
, wine_dbgstr_rect(&rc
), wine_dbgstr_rect(&bcd
->rcButton
));
288 msg
.message
= message
;
289 msg
.flags
= sent
|parent
|wparam
|lparam
|id
;
292 msg
.id
= BCN_DROPDOWN
;
293 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
297 if (message
== WM_PAINT
)
300 beginpaint_counter
++;
301 BeginPaint( hwnd
, &ps
);
302 beginpaint_counter
--;
303 EndPaint( hwnd
, &ps
);
307 defwndproc_counter
++;
308 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
309 defwndproc_counter
--;
314 static const struct message setfocus_seq
[] =
316 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
317 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
318 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
319 { WM_SETFOCUS
, sent
|wparam
},
320 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
321 { WM_APP
, sent
|wparam
|lparam
},
326 static const struct message killfocus_seq
[] =
328 { WM_KILLFOCUS
, sent
|wparam
, 0 },
329 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
330 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
331 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
332 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
337 static const struct message setfocus_static_seq
[] =
339 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
340 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
341 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
342 { WM_SETFOCUS
, sent
|wparam
, 0 },
343 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
344 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
345 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
350 static const struct message setfocus_groupbox_seq
[] =
352 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
353 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
354 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
355 { WM_SETFOCUS
, sent
|wparam
, 0 },
356 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
357 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
358 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
363 static const struct message killfocus_static_seq
[] =
365 { WM_KILLFOCUS
, sent
|wparam
, 0 },
366 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
367 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
368 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
369 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
374 static const struct message setfocus_ownerdraw_seq
[] =
376 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
377 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
378 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
379 { WM_SETFOCUS
, sent
|wparam
, 0 },
380 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
381 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
382 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
383 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
387 static const struct message killfocus_ownerdraw_seq
[] =
389 { WM_KILLFOCUS
, sent
|wparam
, 0 },
390 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
391 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
392 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
393 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
395 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
399 static const struct message lbuttondown_seq
[] =
401 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
402 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
403 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
404 { BM_GETSTATE
, sent
|defwinproc
|optional
}, /* when touchscreen is present */
405 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
406 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
410 static const struct message lbuttonup_seq
[] =
412 { WM_LBUTTONUP
, sent
|wparam
|lparam
, 0, 0 },
413 { BM_SETSTATE
, sent
|wparam
|defwinproc
, FALSE
},
414 { WM_CAPTURECHANGED
, sent
|wparam
|defwinproc
, 0 },
415 { WM_COMMAND
, sent
|wparam
|defwinproc
, 0 },
419 static const struct message setfont_seq
[] =
421 { WM_SETFONT
, sent
},
425 static const struct message setstyle_seq
[] =
427 { BM_SETSTYLE
, sent
},
428 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
429 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
430 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
432 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
433 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
434 { WM_PAINT
, sent
|optional
},
438 static const struct message setstyle_static_seq
[] =
440 { BM_SETSTYLE
, sent
},
441 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
442 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
443 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
445 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
446 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
450 static const struct message setstyle_user_seq
[] =
452 { BM_SETSTYLE
, sent
},
453 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
454 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
455 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
457 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
458 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
462 static const struct message setstyle_ownerdraw_seq
[] =
464 { BM_SETSTYLE
, sent
},
465 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
466 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
467 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
469 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
470 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
471 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
475 static const struct message setstate_seq
[] =
477 { BM_SETSTATE
, sent
},
478 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
480 { WM_PAINT
, sent
|optional
},
484 static const struct message setstate_static_seq
[] =
486 { BM_SETSTATE
, sent
},
487 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
489 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
490 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
494 static const struct message setstate_user_seq
[] =
496 { BM_SETSTATE
, sent
},
497 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
498 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
503 static const struct message setstate_ownerdraw_seq
[] =
505 { BM_SETSTATE
, sent
},
506 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
508 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
509 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
510 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
514 static const struct message clearstate_seq
[] =
516 { BM_SETSTATE
, sent
},
517 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
518 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
520 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
521 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
525 static const struct message clearstate_ownerdraw_seq
[] =
527 { BM_SETSTATE
, sent
},
528 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
530 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
531 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
532 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
536 static const struct message setcheck_ignored_seq
[] =
538 { BM_SETCHECK
, sent
},
539 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
540 { WM_PAINT
, sent
|optional
},
544 static const struct message setcheck_static_seq
[] =
546 { BM_SETCHECK
, sent
},
547 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
549 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
550 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
554 static const struct message setcheck_radio_seq
[] =
556 { BM_SETCHECK
, sent
},
557 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
558 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
559 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
563 static const struct message setcheck_radio_redraw_seq
[] =
565 { BM_SETCHECK
, sent
},
566 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
567 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
568 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
570 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
574 static const struct message empty_cd_seq
[] = { { 0 } };
576 static const struct message pre_cd_seq
[] =
578 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
582 static const struct message pre_pre_cd_seq
[] =
584 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
585 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
589 static const struct message pre_post_pre_cd_seq
[] =
591 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
592 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTERASE
},
593 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
597 static const struct message pre_pre_post_cd_seq
[] =
599 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
600 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
601 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTPAINT
},
605 static const struct message pre_post_pre_post_cd_seq
[] =
607 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
608 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTERASE
},
609 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
610 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTPAINT
},
614 static const struct message bcn_dropdown_seq
[] =
616 { WM_KEYDOWN
, sent
|wparam
|lparam
, VK_DOWN
, 0 },
617 { BCM_SETDROPDOWNSTATE
, sent
|wparam
|lparam
|defwinproc
, 1, 0 },
618 { WM_NOTIFY
, sent
|parent
|id
, 0, 0, BCN_DROPDOWN
},
619 { BCM_SETDROPDOWNSTATE
, sent
|wparam
|lparam
|defwinproc
, 0, 0 },
620 { WM_KEYUP
, sent
|wparam
|lparam
, VK_DOWN
, 0xc0000000 },
622 { WM_DRAWITEM
, sent
|parent
|optional
}, /* for owner draw button */
623 { WM_PAINT
, sent
|optional
}, /* sometimes sent rarely */
624 { WM_DRAWITEM
, sent
|parent
|optional
},
628 static HWND
create_button(DWORD style
, HWND parent
)
635 style
|= WS_CHILD
|BS_NOTIFY
;
636 menuid
= (HMENU
)ID_BUTTON
;
638 hwnd
= CreateWindowExA(0, WC_BUTTONA
, "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
639 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
640 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
644 static void test_button_messages(void)
657 const struct message
*setfocus
;
658 const struct message
*killfocus
;
659 const struct message
*setstyle
;
660 const struct message
*setstate
;
661 const struct message
*clearstate
;
662 const struct message
*setcheck
;
663 enum cd_seq_type cd_setfocus_type
;
664 enum cd_seq_type cd_setstyle_type
;
665 enum cd_seq_type cd_setstate_type
;
666 enum cd_seq_type cd_setcheck_type
;
668 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
669 setfocus_seq
, killfocus_seq
, setstyle_seq
,
670 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
671 cd_seq_normal
, cd_seq_normal
, cd_seq_normal
, cd_seq_optional
},
672 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
673 setfocus_seq
, killfocus_seq
, setstyle_seq
,
674 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
675 cd_seq_normal
, cd_seq_normal
, cd_seq_normal
, cd_seq_optional
},
676 { BS_CHECKBOX
, DLGC_BUTTON
,
677 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
678 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
679 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
680 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
681 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
682 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
683 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
684 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
685 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
686 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
,
687 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
688 { BS_3STATE
, DLGC_BUTTON
,
689 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
690 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
691 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
692 { BS_AUTO3STATE
, DLGC_BUTTON
,
693 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
694 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
695 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
696 { BS_GROUPBOX
, DLGC_STATIC
,
697 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
698 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
,
699 cd_seq_empty
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
700 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
701 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
702 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
,
703 cd_seq_normal
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
704 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
705 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
706 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
,
707 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
708 { BS_OWNERDRAW
, DLGC_BUTTON
,
709 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
710 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
,
711 cd_seq_empty
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
712 { BS_SPLITBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
| DLGC_WANTARROWS
,
713 setfocus_seq
, killfocus_seq
, setstyle_seq
,
714 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
715 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
716 { BS_DEFSPLITBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
| DLGC_WANTARROWS
,
717 setfocus_seq
, killfocus_seq
, setstyle_seq
,
718 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
719 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
720 { BS_COMMANDLINK
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
721 setfocus_seq
, killfocus_seq
, setstyle_seq
,
722 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
723 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
724 { BS_DEFCOMMANDLINK
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
725 setfocus_seq
, killfocus_seq
, setstyle_seq
,
726 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
727 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
}
729 LOGFONTA logfont
= { 0 };
730 const struct message
*seq
, *cd_seq
;
737 /* selection with VK_SPACE should capture button window */
738 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
739 ok(hwnd
!= 0, "Failed to create button window\n");
742 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
743 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
744 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
747 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
748 100, 100, 200, 200, 0, 0, 0, NULL
);
749 ok(parent
!= 0, "Failed to create parent window\n");
751 logfont
.lfHeight
= -12;
752 logfont
.lfWeight
= FW_NORMAL
;
753 strcpy(logfont
.lfFaceName
, "Tahoma");
755 hfont2
= CreateFontIndirectA(&logfont
);
756 ok(hfont2
!= NULL
, "Failed to create Tahoma font\n");
758 #define check_cd_seq(type, context) do { \
759 if (button[i].type != cd_seq_optional || !test_cd.empty) \
760 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, cd_seq, "[CustomDraw] " context, FALSE); \
763 for (i
= 0; i
< ARRAY_SIZE(button
); i
++)
765 HFONT prevfont
, hfont
;
770 test_cd
.button
= button
[i
].style
;
771 hwnd
= create_button(button
[i
].style
, parent
);
772 ok(hwnd
!= NULL
, "Failed to create a button.\n");
774 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
775 style
&= ~(WS_CHILD
| BS_NOTIFY
);
776 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
777 if (button
[i
].style
== BS_USERBUTTON
)
778 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
780 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
782 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
783 if (button
[i
].style
== BS_SPLITBUTTON
||
784 button
[i
].style
== BS_DEFSPLITBUTTON
||
785 button
[i
].style
== BS_COMMANDLINK
||
786 button
[i
].style
== BS_DEFCOMMANDLINK
)
788 ok(dlg_code
== button
[i
].dlg_code
|| broken(dlg_code
== DLGC_BUTTON
) /* WinXP */, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
791 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
793 ShowWindow(hwnd
, SW_SHOW
);
798 cd_seq
= (button
[i
].cd_setfocus_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
799 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
800 set_test_cd_ret(CDRF_DODEFAULT
);
801 set_test_cd_state(CDIS_FOCUS
);
803 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
805 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
806 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
807 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setfocus
, "SetFocus(hwnd) on a button", FALSE
);
808 check_cd_seq(cd_setfocus_type
, "SetFocus(hwnd)");
810 set_test_cd_state(0);
812 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
813 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
814 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", FALSE
);
815 check_cd_seq(cd_setfocus_type
, "SetFocus(0)");
816 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
818 cd_seq
= (button
[i
].cd_setstyle_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
819 set_test_cd_state(0);
821 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
822 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
823 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
824 todo
= button
[i
].style
== BS_OWNERDRAW
;
825 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", todo
);
826 check_cd_seq(cd_setstyle_type
, "BM_SETSTYLE");
828 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
829 style
&= ~(WS_VISIBLE
| WS_CHILD
| BS_NOTIFY
);
830 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
831 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
833 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
834 ok(state
== 0, "expected state 0, got %04x\n", state
);
836 cd_seq
= (button
[i
].cd_setstate_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
837 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
838 set_test_cd_state(CDIS_SELECTED
);
840 SendMessageA(hwnd
, BM_SETSTATE
, TRUE
, 0);
841 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
842 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
843 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstate
, "BM_SETSTATE/TRUE on a button", FALSE
);
844 check_cd_seq(cd_setstate_type
, "BM_SETSTATE/TRUE");
846 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
847 ok(state
== BST_PUSHED
, "expected state 0x0004, got %04x\n", state
);
849 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
850 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
851 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
853 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
854 set_test_cd_state(0);
856 SendMessageA(hwnd
, BM_SETSTATE
, FALSE
, 0);
857 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
858 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
859 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].clearstate
, "BM_SETSTATE/FALSE on a button", FALSE
);
860 check_cd_seq(cd_setstate_type
, "BM_SETSTATE/FALSE");
862 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
863 ok(state
== 0, "expected state 0, got %04x\n", state
);
865 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
866 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
867 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
869 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
870 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
872 cd_seq
= (button
[i
].cd_setcheck_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
873 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
874 set_test_cd_state(0);
876 if (button
[i
].style
== BS_RADIOBUTTON
||
877 button
[i
].style
== BS_AUTORADIOBUTTON
)
879 seq
= setcheck_radio_seq
;
882 seq
= setcheck_ignored_seq
;
884 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
885 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
886 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
887 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", FALSE
);
888 check_cd_seq(cd_setcheck_type
, "BM_SETCHECK");
890 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
891 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
893 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
894 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
895 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
897 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
898 set_test_cd_state(0);
900 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
901 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
902 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
903 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
904 check_cd_seq(cd_setcheck_type
, "BM_SETCHECK");
906 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
907 if (button
[i
].style
== BS_PUSHBUTTON
||
908 button
[i
].style
== BS_DEFPUSHBUTTON
||
909 button
[i
].style
== BS_GROUPBOX
||
910 button
[i
].style
== BS_USERBUTTON
||
911 button
[i
].style
== BS_OWNERDRAW
||
912 button
[i
].style
== BS_SPLITBUTTON
||
913 button
[i
].style
== BS_DEFSPLITBUTTON
||
914 button
[i
].style
== BS_COMMANDLINK
||
915 button
[i
].style
== BS_DEFCOMMANDLINK
)
917 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
920 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
922 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
923 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
924 if (button
[i
].style
== BS_RADIOBUTTON
||
925 button
[i
].style
== BS_AUTORADIOBUTTON
)
926 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
928 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
930 /* Test that original font is not selected back after painting */
931 hfont
= (HFONT
)SendMessageA(hwnd
, WM_GETFONT
, 0, 0);
932 ok(hfont
== NULL
, "Unexpected control font.\n");
934 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)GetStockObject(SYSTEM_FONT
), 0);
936 hdc
= CreateCompatibleDC(0);
938 prevfont
= SelectObject(hdc
, hfont2
);
939 SendMessageA(hwnd
, WM_PRINTCLIENT
, (WPARAM
)hdc
, 0);
940 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
941 "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i
);
942 SelectObject(hdc
, prevfont
);
944 prevfont
= SelectObject(hdc
, hfont2
);
945 SendMessageA(hwnd
, WM_PAINT
, (WPARAM
)hdc
, 0);
946 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
947 "button[%u]: unexpected font selected after WM_PAINT\n", i
);
948 SelectObject(hdc
, prevfont
);
952 /* Test Custom Draw return values */
953 if (button
[i
].cd_setfocus_type
!= cd_seq_empty
&&
954 broken(button
[i
].style
!= BS_USERBUTTON
) /* WinXP */)
960 const struct message
*seq
;
962 { "CDRF_DODEFAULT", CDRF_DODEFAULT
, pre_pre_cd_seq
},
963 { "CDRF_DOERASE", CDRF_DOERASE
, pre_pre_cd_seq
},
964 { "CDRF_SKIPDEFAULT", CDRF_SKIPDEFAULT
, pre_cd_seq
},
965 { "CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
966 CDRF_SKIPDEFAULT
| CDRF_NOTIFYPOSTERASE
| CDRF_NOTIFYPOSTPAINT
, pre_cd_seq
},
967 { "CDRF_NOTIFYPOSTERASE", CDRF_NOTIFYPOSTERASE
, pre_post_pre_cd_seq
},
968 { "CDRF_NOTIFYPOSTPAINT", CDRF_NOTIFYPOSTPAINT
, pre_pre_post_cd_seq
},
969 { "CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
970 CDRF_NOTIFYPOSTERASE
| CDRF_NOTIFYPOSTPAINT
, pre_post_pre_post_cd_seq
},
974 for (k
= 0; k
< ARRAY_SIZE(ret
); k
++)
978 set_test_cd_ret(ret
[k
].val
);
979 set_test_cd_state(CDIS_FOCUS
);
981 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
983 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
984 if (button
[i
].cd_setfocus_type
!= cd_seq_optional
|| !test_cd
.empty
)
985 ok_sequence(sequences
, PARENT_CD_SEQ_INDEX
, ret
[k
].seq
, ret
[k
].context
, FALSE
);
991 if (!broken(LOBYTE(LOWORD(GetVersion())) < 6)) /* not available pre-Vista */
993 /* Send down arrow key to make the buttons send the drop down notification */
994 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
995 SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
996 SendMessageW(hwnd
, WM_KEYUP
, VK_DOWN
, 0xc0000000);
997 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
998 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, bcn_dropdown_seq
, "BCN_DROPDOWN from the button", FALSE
);
1001 DestroyWindow(hwnd
);
1006 DeleteObject(hfont2
);
1007 DestroyWindow(parent
);
1009 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
1011 SetForegroundWindow(hwnd
);
1014 SetActiveWindow(hwnd
);
1016 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1018 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
1019 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
1021 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
1022 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
1024 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1025 zfont
= GetStockObject(SYSTEM_FONT
);
1026 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
1028 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
1030 DestroyWindow(hwnd
);
1033 static void test_button_class(void)
1035 WNDCLASSEXW exW
, ex2W
;
1043 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
1044 ok(ret
, "got %d\n", ret
);
1045 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
1046 ok(exA
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exA
.cbClsExtra
);
1047 ok(exA
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exA
.cbWndExtra
);
1049 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
1050 ok(ret
, "got %d\n", ret
);
1051 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
1052 ok(exW
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exW
.cbClsExtra
);
1053 ok(exW
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exW
.cbWndExtra
);
1055 /* check that versioned class is also accessible */
1056 nameW
= get_versioned_classname(WC_BUTTONW
);
1057 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
1059 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
1060 ok(ret
, "got %d\n", ret
);
1061 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
1063 /* Check reported class name */
1064 hwnd
= create_button(BS_CHECKBOX
, NULL
);
1065 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
1066 ok(len
== strlen(buffA
), "got %d\n", len
);
1067 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1069 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
1070 ok(len
== strlen(buffA
), "got %d\n", len
);
1071 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1072 DestroyWindow(hwnd
);
1074 /* explicitly create with versioned class name */
1075 hwnd
= CreateWindowExW(0, nameW
, L
"test", BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
1076 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
1078 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
1079 ok(len
== strlen(buffA
), "got %d\n", len
);
1080 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1082 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
1083 ok(len
== strlen(buffA
), "got %d\n", len
);
1084 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1086 DestroyWindow(hwnd
);
1089 static void test_note(void)
1093 WCHAR test_w
[] = {'t', 'e', 's', 't', 0};
1094 WCHAR tes_w
[] = {'t', 'e', 's', 0};
1095 WCHAR deadbeef_w
[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
1101 hwnd
= create_button(BS_COMMANDLINK
, NULL
);
1102 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1103 SetLastError(0xdeadbeef);
1104 size
= ARRAY_SIZE(buffer_w
);
1105 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1106 error
= GetLastError();
1107 if (!ret
&& error
== 0xdeadbeef)
1109 win_skip("BCM_GETNOTE message is unavailable. Skipping note tests\n"); /* xp or 2003 */
1110 DestroyWindow(hwnd
);
1113 DestroyWindow(hwnd
);
1115 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1117 if (type
== BS_DEFCOMMANDLINK
|| type
== BS_COMMANDLINK
)
1119 hwnd
= create_button(type
, NULL
);
1120 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1122 /* Get note when note hasn't been not set yet */
1123 SetLastError(0xdeadbeef);
1124 lstrcpyW(buffer_w
, deadbeef_w
);
1125 size
= ARRAY_SIZE(buffer_w
);
1126 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1127 error
= GetLastError();
1128 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1129 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1130 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1131 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1132 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1133 ERROR_INVALID_PARAMETER
, error
);
1135 /* Get note length when note is not set */
1136 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1137 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
1139 /* Successful set note, get note and get note length */
1140 SetLastError(0xdeadbeef);
1141 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)test_w
);
1142 ok(ret
, "Expect BCM_SETNOTE return true\n");
1143 error
= GetLastError();
1144 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1146 SetLastError(0xdeadbeef);
1147 lstrcpyW(buffer_w
, deadbeef_w
);
1148 size
= ARRAY_SIZE(buffer_w
);
1149 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1150 ok(ret
, "Expect BCM_GETNOTE return true\n");
1151 ok(!lstrcmpW(buffer_w
, test_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(test_w
),
1152 wine_dbgstr_w(buffer_w
));
1153 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1154 error
= GetLastError();
1155 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1157 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1158 ok(ret
== ARRAY_SIZE(test_w
) - 1, "Got: %d\n", ret
);
1160 /* Insufficient buffer, return partial string */
1161 SetLastError(0xdeadbeef);
1162 lstrcpyW(buffer_w
, deadbeef_w
);
1163 size
= ARRAY_SIZE(test_w
) - 1;
1164 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1165 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1166 ok(!lstrcmpW(buffer_w
, tes_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(tes_w
),
1167 wine_dbgstr_w(buffer_w
));
1168 ok(size
== ARRAY_SIZE(test_w
), "Got: %d\n", size
);
1169 error
= GetLastError();
1170 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1171 ERROR_INSUFFICIENT_BUFFER
, error
);
1173 /* Set note with NULL buffer */
1174 SetLastError(0xdeadbeef);
1175 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, 0);
1176 ok(ret
, "Expect BCM_SETNOTE return false\n");
1177 error
= GetLastError();
1178 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1180 /* Check that set note with NULL buffer make note empty */
1181 SetLastError(0xdeadbeef);
1182 lstrcpyW(buffer_w
, deadbeef_w
);
1183 size
= ARRAY_SIZE(buffer_w
);
1184 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1185 ok(ret
, "Expect BCM_GETNOTE return true\n");
1186 ok(!*buffer_w
, "Expect note length 0\n");
1187 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1188 error
= GetLastError();
1189 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1190 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1191 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
1193 /* Get note with NULL buffer */
1194 SetLastError(0xdeadbeef);
1195 size
= ARRAY_SIZE(buffer_w
);
1196 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, 0);
1197 ok(!ret
, "Expect BCM_SETNOTE return false\n");
1198 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1199 error
= GetLastError();
1200 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1201 ERROR_INVALID_PARAMETER
, error
);
1203 /* Get note with NULL size */
1204 SetLastError(0xdeadbeef);
1205 lstrcpyW(buffer_w
, deadbeef_w
);
1206 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, 0, (LPARAM
)buffer_w
);
1207 ok(!ret
, "Expect BCM_SETNOTE return false\n");
1208 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1209 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1210 error
= GetLastError();
1211 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1212 ERROR_INVALID_PARAMETER
, error
);
1214 /* Get note with zero size */
1215 SetLastError(0xdeadbeef);
1217 lstrcpyW(buffer_w
, deadbeef_w
);
1218 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1219 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1220 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1221 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1222 ok(size
== 1, "Got: %d\n", size
);
1223 error
= GetLastError();
1224 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1225 ERROR_INSUFFICIENT_BUFFER
, error
);
1227 DestroyWindow(hwnd
);
1231 hwnd
= create_button(type
, NULL
);
1232 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1233 SetLastError(0xdeadbeef);
1234 size
= ARRAY_SIZE(buffer_w
);
1235 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1236 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1237 error
= GetLastError();
1238 ok(error
== ERROR_NOT_SUPPORTED
, "Expect last error: 0x%08x, got: 0x%08x\n",
1239 ERROR_NOT_SUPPORTED
, error
);
1240 DestroyWindow(hwnd
);
1245 static void test_bm_get_set_image(void)
1252 ICONINFO icon_info2x2
;
1258 static const DWORD default_style
= BS_PUSHBUTTON
| WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
1261 hbmp1x1
= CreateCompatibleBitmap(hdc
, 1, 1);
1262 hbmp2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
1263 ZeroMemory(&bm
, sizeof(bm
));
1264 ok(GetObjectW(hbmp1x1
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1265 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1266 bm
.bmWidth
, bm
.bmHeight
);
1267 ZeroMemory(&bm
, sizeof(bm
));
1268 ok(GetObjectW(hbmp2x2
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1269 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1270 bm
.bmWidth
, bm
.bmHeight
);
1272 hmask2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
1273 ZeroMemory(&icon_info2x2
, sizeof(icon_info2x2
));
1274 icon_info2x2
.fIcon
= TRUE
;
1275 icon_info2x2
.hbmMask
= hmask2x2
;
1276 icon_info2x2
.hbmColor
= hbmp2x2
;
1277 hicon2x2
= CreateIconIndirect(&icon_info2x2
);
1278 ok(hicon2x2
!=NULL
, "Expect CreateIconIndirect() success\n");
1280 ZeroMemory(&icon_info
, sizeof(icon_info
));
1281 ok(GetIconInfo(hicon2x2
, &icon_info
), "Expect GetIconInfo() success\n");
1282 ZeroMemory(&bm
, sizeof(bm
));
1283 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1284 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1285 bm
.bmWidth
, bm
.bmHeight
);
1286 DeleteObject(icon_info
.hbmColor
);
1287 DeleteObject(icon_info
.hbmMask
);
1289 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1291 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1292 /* Get image when image is not set */
1293 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1294 ok(hbmp
== 0, "Expect hbmp == 0\n");
1296 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1297 ok(hbmp
== 0, "Expect hbmp == 0\n");
1298 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1299 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1300 /* Set null resets image */
1301 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, 0);
1302 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1303 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1304 ok(hbmp
== 0, "Expect hbmp == 0\n");
1305 DestroyWindow(hwnd
);
1307 /* Set bitmap with BS_BITMAP */
1308 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1310 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1311 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1312 ok(hbmp
== 0, "Expect hbmp == 0\n");
1313 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1314 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1315 ZeroMemory(&bm
, sizeof(bm
));
1316 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1317 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1318 bm
.bmWidth
, bm
.bmHeight
);
1319 DestroyWindow(hwnd
);
1321 /* Set bitmap without BS_BITMAP */
1322 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1323 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1324 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1325 ok(hbmp
== 0, "Expect hbmp == 0\n");
1326 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1330 win_skip("Show both image and text is not supported. Skip following tests.\n");
1331 DestroyWindow(hwnd
);
1334 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1335 ZeroMemory(&bm
, sizeof(bm
));
1336 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1337 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1338 bm
.bmWidth
, bm
.bmHeight
);
1339 DestroyWindow(hwnd
);
1341 /* Set icon with BS_ICON */
1342 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1344 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1345 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1346 ok(hicon
== 0, "Expect hicon == 0\n");
1347 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1348 ok(hicon
!= 0, "Expect hicon != 0\n");
1349 ZeroMemory(&icon_info
, sizeof(icon_info
));
1350 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1351 ZeroMemory(&bm
, sizeof(bm
));
1352 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1353 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1354 bm
.bmWidth
, bm
.bmHeight
);
1355 DeleteObject(icon_info
.hbmColor
);
1356 DeleteObject(icon_info
.hbmMask
);
1357 DestroyWindow(hwnd
);
1359 /* Set icon without BS_ICON */
1360 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1361 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1362 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1363 ok(hicon
== 0, "Expect hicon == 0\n");
1364 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1365 ok(hicon
!= 0, "Expect hicon != 0\n");
1366 ZeroMemory(&icon_info
, sizeof(icon_info
));
1367 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1368 ZeroMemory(&bm
, sizeof(bm
));
1369 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1370 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1371 bm
.bmWidth
, bm
.bmHeight
);
1372 DeleteObject(icon_info
.hbmColor
);
1373 DeleteObject(icon_info
.hbmMask
);
1374 DestroyWindow(hwnd
);
1376 /* Set icon with BS_BITMAP */
1377 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1379 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1380 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1381 ok(hicon
== 0, "Expect hicon == 0\n");
1382 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1383 ok(hicon
!= 0, "Expect hicon != 0\n");
1384 ZeroMemory(&icon_info
, sizeof(icon_info
));
1385 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1386 ZeroMemory(&bm
, sizeof(bm
));
1387 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1388 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1389 bm
.bmWidth
, bm
.bmHeight
);
1390 DeleteObject(icon_info
.hbmColor
);
1391 DeleteObject(icon_info
.hbmMask
);
1392 DestroyWindow(hwnd
);
1394 /* Set bitmap with BS_ICON */
1395 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1397 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1398 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1399 ok(hbmp
== 0, "Expect hbmp == 0\n");
1400 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1401 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1402 ZeroMemory(&bm
, sizeof(bm
));
1403 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1404 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1405 bm
.bmWidth
, bm
.bmHeight
);
1406 DestroyWindow(hwnd
);
1408 /* Set bitmap with BS_BITMAP and IMAGE_ICON*/
1409 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1411 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1412 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1413 ok(hbmp
== 0, "Expect hbmp == 0\n");
1414 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1415 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1416 ZeroMemory(&bm
, sizeof(bm
));
1417 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1418 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1419 bm
.bmWidth
, bm
.bmHeight
);
1420 DestroyWindow(hwnd
);
1422 /* Set icon with BS_ICON and IMAGE_BITMAP */
1423 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1425 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1426 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1427 ok(hicon
== 0, "Expect hicon == 0\n");
1428 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1429 ok(hicon
!= 0, "Expect hicon != 0\n");
1430 ZeroMemory(&icon_info
, sizeof(icon_info
));
1431 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1432 ZeroMemory(&bm
, sizeof(bm
));
1433 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1434 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1435 bm
.bmWidth
, bm
.bmHeight
);
1436 DeleteObject(icon_info
.hbmColor
);
1437 DeleteObject(icon_info
.hbmMask
);
1438 DestroyWindow(hwnd
);
1440 /* Set bitmap with BS_ICON and IMAGE_ICON */
1441 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0, 0);
1442 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1443 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1444 ok(hbmp
== 0, "Expect hbmp == 0\n");
1445 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1446 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1447 ZeroMemory(&bm
, sizeof(bm
));
1448 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1449 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1450 bm
.bmWidth
, bm
.bmHeight
);
1451 DestroyWindow(hwnd
);
1453 /* Set icon with BS_BITMAP and IMAGE_BITMAP */
1454 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0, 0, 0);
1455 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1456 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1457 ok(hicon
== 0, "Expect hicon == 0\n");
1458 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1459 ok(hicon
!= 0, "Expect hicon != 0\n");
1460 ZeroMemory(&icon_info
, sizeof(icon_info
));
1461 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1462 ZeroMemory(&bm
, sizeof(bm
));
1463 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1464 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1465 bm
.bmWidth
, bm
.bmHeight
);
1466 DeleteObject(icon_info
.hbmColor
);
1467 DeleteObject(icon_info
.hbmMask
);
1468 DestroyWindow(hwnd
);
1471 DestroyIcon(hicon2x2
);
1472 DeleteObject(hmask2x2
);
1473 DeleteObject(hbmp2x2
);
1474 DeleteObject(hbmp1x1
);
1478 static void register_parent_class(void)
1483 cls
.lpfnWndProc
= test_parent_wndproc
;
1486 cls
.hInstance
= GetModuleHandleA(0);
1488 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1489 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
1490 cls
.lpszMenuName
= NULL
;
1491 cls
.lpszClassName
= "TestParentClass";
1492 RegisterClassA(&cls
);
1495 static void test_bcm_splitinfo(HWND hwnd
)
1497 UINT button
= GetWindowLongA(hwnd
, GWL_STYLE
) & BS_TYPEMASK
;
1498 int glyph_size
= GetSystemMetrics(SM_CYMENUCHECK
);
1499 int border_w
= GetSystemMetrics(SM_CXEDGE
) * 2;
1500 BUTTON_SPLITINFO info
, dummy
;
1504 memset(&info
, 0xCC, sizeof(info
));
1506 memcpy(&dummy
, &info
, sizeof(info
));
1508 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1513 win_skip("BCM_GETSPLITINFO message is unavailable. Skipping related tests\n"); /* Pre-Vista */
1517 ok(!memcmp(&info
, &dummy
, sizeof(info
)), "[%u] split info struct was changed with mask = 0\n", button
);
1519 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, 0);
1520 ok(ret
== FALSE
, "[%u] expected FALSE, got %d\n", button
, ret
);
1521 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, 0);
1522 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1524 info
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
| BCSIF_STYLE
;
1525 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1526 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1527 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
| BCSIF_STYLE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1528 ok(info
.himlGlyph
== (HIMAGELIST
)0x36, "[%u] expected 0x36 default glyph, got 0x%p\n", button
, info
.himlGlyph
);
1529 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x default style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1530 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d default size.cx, got %d\n", button
, glyph_size
, info
.size
.cx
);
1531 ok(info
.size
.cy
== 0, "[%u] expected 0 default size.cy, got %d\n", button
, info
.size
.cy
);
1533 info
.mask
= BCSIF_SIZE
;
1534 info
.size
.cx
= glyph_size
+ 7;
1536 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1537 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1538 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1539 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1540 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1541 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1542 ok(info
.size
.cx
== glyph_size
+ 7, "[%u] expected %d, got %d\n", button
, glyph_size
+ 7, info
.size
.cx
);
1543 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1545 /* Invalid size.cx resets it to default glyph size, while size.cy is stored */
1548 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1549 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1550 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1551 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1552 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1553 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1554 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1555 ok(info
.size
.cy
== -20, "[%u] expected -20, got %d\n", button
, info
.size
.cy
);
1557 info
.size
.cx
= -glyph_size
- 7;
1559 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1560 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1561 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1562 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1563 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1564 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1565 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1566 ok(info
.size
.cy
== -10, "[%u] expected -10, got %d\n", button
, info
.size
.cy
);
1568 /* Set to a valid size other than glyph_size */
1569 info
.mask
= BCSIF_SIZE
;
1570 info
.size
.cx
= glyph_size
+ 7;
1572 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1573 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1574 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1575 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1576 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1577 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1578 ok(info
.size
.cx
== glyph_size
+ 7, "[%u] expected %d, got %d\n", button
, glyph_size
+ 7, info
.size
.cx
);
1579 ok(info
.size
.cy
== 11, "[%u] expected 11, got %d\n", button
, info
.size
.cy
);
1581 /* Change the glyph, size.cx should be automatically adjusted and size.cy set to 0 */
1582 dummy
.mask
= BCSIF_GLYPH
;
1583 dummy
.himlGlyph
= (HIMAGELIST
)0x35;
1584 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1585 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1586 info
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
;
1587 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1588 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1589 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1590 ok(info
.himlGlyph
== (HIMAGELIST
)0x35, "[%u] expected 0x35, got %p\n", button
, info
.himlGlyph
);
1591 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1592 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1594 /* Unless the size is specified manually */
1595 dummy
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
;
1596 dummy
.himlGlyph
= (HIMAGELIST
)0x34;
1597 dummy
.size
.cx
= glyph_size
+ 11;
1599 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1600 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1601 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1602 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1603 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1604 ok(info
.himlGlyph
== (HIMAGELIST
)0x34, "[%u] expected 0x34, got %p\n", button
, info
.himlGlyph
);
1605 ok(info
.size
.cx
== glyph_size
+ 11, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1606 ok(info
.size
.cy
== 7, "[%u] expected 7, got %d\n", button
, info
.size
.cy
);
1608 /* Add the BCSS_IMAGE style manually with the wrong BCSIF_GLYPH mask, should treat it as invalid image */
1609 info
.mask
= BCSIF_GLYPH
| BCSIF_STYLE
;
1610 info
.himlGlyph
= (HIMAGELIST
)0x37;
1611 info
.uSplitStyle
= BCSS_IMAGE
;
1612 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1613 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1614 info
.mask
|= BCSIF_SIZE
;
1615 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1616 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1617 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1618 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1619 ok(info
.uSplitStyle
== BCSS_IMAGE
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
, info
.uSplitStyle
);
1620 ok(info
.size
.cx
== border_w
, "[%u] expected %d, got %d\n", button
, border_w
, info
.size
.cx
);
1621 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1623 /* Change the size to prevent ambiguity */
1624 dummy
.mask
= BCSIF_SIZE
;
1625 dummy
.size
.cx
= glyph_size
+ 5;
1627 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1628 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1629 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1630 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1631 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1632 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1633 ok(info
.uSplitStyle
== BCSS_IMAGE
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
, info
.uSplitStyle
);
1634 ok(info
.size
.cx
== glyph_size
+ 5, "[%u] expected %d, got %d\n", button
, glyph_size
+ 5, info
.size
.cx
);
1635 ok(info
.size
.cy
== 4, "[%u] expected 4, got %d\n", button
, info
.size
.cy
);
1637 /* Now remove the BCSS_IMAGE style manually with the wrong BCSIF_IMAGE mask */
1638 info
.mask
= BCSIF_IMAGE
| BCSIF_STYLE
;
1639 info
.himlGlyph
= (HIMAGELIST
)0x35;
1640 info
.uSplitStyle
= BCSS_STRETCH
;
1641 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1642 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1643 info
.mask
|= BCSIF_SIZE
;
1644 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1645 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1646 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1647 ok(info
.himlGlyph
== (HIMAGELIST
)0x35, "[%u] expected 0x35, got %p\n", button
, info
.himlGlyph
);
1648 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1649 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1650 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1652 /* Add a proper valid image, the BCSS_IMAGE style should be set automatically */
1653 img
= pImageList_Create(42, 33, ILC_COLOR
, 1, 1);
1654 ok(img
!= NULL
, "[%u] failed to create ImageList\n", button
);
1655 info
.mask
= BCSIF_IMAGE
;
1656 info
.himlGlyph
= img
;
1657 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1658 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1659 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1660 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1661 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1662 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1663 ok(info
.himlGlyph
== img
, "[%u] expected %p, got %p\n", button
, img
, info
.himlGlyph
);
1664 ok(info
.uSplitStyle
== (BCSS_IMAGE
| BCSS_STRETCH
), "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
| BCSS_STRETCH
, info
.uSplitStyle
);
1665 ok(info
.size
.cx
== 42 + border_w
, "[%u] expected %d, got %d\n", button
, 42 + border_w
, info
.size
.cx
);
1666 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1667 pImageList_Destroy(img
);
1668 dummy
.mask
= BCSIF_SIZE
;
1669 dummy
.size
.cx
= glyph_size
+ 5;
1671 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1672 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1674 /* Change it to a glyph; when both specified, BCSIF_GLYPH takes priority */
1675 info
.mask
= BCSIF_GLYPH
| BCSIF_IMAGE
;
1676 info
.himlGlyph
= (HIMAGELIST
)0x37;
1677 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1678 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1679 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1680 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1681 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1682 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1683 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1684 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1685 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1686 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1688 /* Try a NULL image */
1689 info
.mask
= BCSIF_IMAGE
;
1690 info
.himlGlyph
= NULL
;
1691 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1692 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1693 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1694 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1695 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1696 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1697 ok(info
.himlGlyph
== NULL
, "[%u] expected NULL, got %p\n", button
, info
.himlGlyph
);
1698 ok(info
.uSplitStyle
== (BCSS_IMAGE
| BCSS_STRETCH
), "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
| BCSS_STRETCH
, info
.uSplitStyle
);
1699 ok(info
.size
.cx
== border_w
, "[%u] expected %d, got %d\n", button
, border_w
, info
.size
.cx
);
1700 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1703 static void test_button_data(void)
1705 static const DWORD styles
[] =
1733 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1734 100, 100, 200, 200, 0, 0, 0, NULL
);
1735 ok(parent
!= 0, "Failed to create parent window\n");
1737 for (i
= 0; i
< ARRAY_SIZE(styles
); i
++)
1739 struct button_desc
*desc
;
1742 hwnd
= create_button(styles
[i
], parent
);
1743 ok(hwnd
!= NULL
, "Failed to create a button.\n");
1745 desc
= (void *)GetWindowLongPtrA(hwnd
, 0);
1746 ok(desc
!= NULL
, "Expected window data.\n");
1750 ok(desc
->self
== hwnd
, "Unexpected 'self' field.\n");
1751 ok(desc
->parent
== parent
, "Unexpected 'parent' field.\n");
1752 ok(desc
->style
== (WS_CHILD
| BS_NOTIFY
| styles
[i
]), "Unexpected 'style' field.\n");
1755 /* Data set and retrieved by these messages is valid for all buttons */
1756 test_bcm_splitinfo(hwnd
);
1758 DestroyWindow(hwnd
);
1761 DestroyWindow(parent
);
1764 static void test_get_set_imagelist(void)
1768 BUTTON_IMAGELIST biml
= {0};
1778 hbmp
= CreateCompatibleBitmap(hdc
, width
, height
);
1779 ok(hbmp
!= NULL
, "Expect hbmp not null\n");
1781 himl
= pImageList_Create(width
, height
, ILC_COLOR
, 1, 0);
1782 ok(himl
!= NULL
, "Expect himl not null\n");
1783 index
= pImageList_Add(himl
, hbmp
, NULL
);
1784 ok(index
== 0, "Expect index == 0\n");
1788 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1790 hwnd
= create_button(type
, NULL
);
1791 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1793 /* Get imagelist when imagelist is unset yet */
1794 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1795 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1796 ok(biml
.himl
== 0 && IsRectEmpty(&biml
.margin
) && biml
.uAlign
== 0,
1797 "Expect BUTTON_IMAGELIST is empty\n");
1799 /* Set imagelist with himl null */
1801 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1802 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1803 ok(ret
|| broken(!ret
), /* xp or 2003 */
1804 "Expect BCM_SETIMAGELIST return true\n");
1806 /* Set imagelist with uAlign invalid */
1809 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1810 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1812 /* Successful get and set imagelist */
1814 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1815 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1816 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1817 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1818 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1819 ok(biml
.himl
== himl
, "Expect himl to be same\n");
1820 ok(biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_CENTER
, "Expect uAlign to be %x\n",
1821 BUTTON_IMAGELIST_ALIGN_CENTER
);
1823 /* BCM_SETIMAGELIST null pointer handling */
1824 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, 0);
1825 ok(!ret
, "Expect BCM_SETIMAGELIST return false\n");
1826 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1827 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1828 ok(biml
.himl
== himl
, "Expect himl to be same\n");
1830 /* BCM_GETIMAGELIST null pointer handling */
1832 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1833 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1834 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1835 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, 0);
1836 ok(!ret
, "Expect BCM_GETIMAGELIST return false\n");
1838 DestroyWindow(hwnd
);
1841 pImageList_Destroy(himl
);
1844 static void test_get_set_textmargin(void)
1852 SetRect(&margin_in
, 2, 1, 3, 4);
1853 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1855 hwnd
= create_button(type
, NULL
);
1856 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1858 /* Get text margin when it is unset */
1859 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1860 ok(ret
, "Expect ret to be true\n");
1861 ok(IsRectEmpty(&margin_out
), "Expect margin empty\n");
1863 /* Successful get and set text margin */
1864 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1865 ok(ret
, "Expect ret to be true\n");
1866 SetRectEmpty(&margin_out
);
1867 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1868 ok(ret
, "Expect ret to be true\n");
1869 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1871 /* BCM_SETTEXTMARGIN null pointer handling */
1872 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, 0);
1873 ok(!ret
, "Expect ret to be false\n");
1874 SetRectEmpty(&margin_out
);
1875 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1876 ok(ret
, "Expect ret to be true\n");
1877 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1879 /* BCM_GETTEXTMARGIN null pointer handling */
1880 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1881 ok(ret
, "Expect ret to be true\n");
1882 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, 0);
1883 ok(!ret
, "Expect ret to be true\n");
1885 DestroyWindow(hwnd
);
1889 static void test_state(void)
1895 /* Initial button state */
1896 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1898 hwnd
= create_button(type
, NULL
);
1899 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
1900 ok(state
== BST_UNCHECKED
, "Expect state 0x%08x, got 0x%08x\n", BST_UNCHECKED
, state
);
1901 DestroyWindow(hwnd
);
1905 static void test_bcm_get_ideal_size(void)
1907 static const char *button_text2
= "WWWW\nWWWW";
1908 static const char *button_text
= "WWWW";
1909 static const DWORD imagelist_aligns
[] = {BUTTON_IMAGELIST_ALIGN_LEFT
, BUTTON_IMAGELIST_ALIGN_RIGHT
,
1910 BUTTON_IMAGELIST_ALIGN_TOP
, BUTTON_IMAGELIST_ALIGN_BOTTOM
,
1911 BUTTON_IMAGELIST_ALIGN_CENTER
};
1912 static const DWORD aligns
[] = {0, BS_TOP
, BS_LEFT
, BS_RIGHT
, BS_BOTTOM
,
1913 BS_CENTER
, BS_VCENTER
, BS_RIGHTBUTTON
, WS_EX_RIGHT
};
1914 DWORD default_style
= WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
1915 const LONG client_width
= 400, client_height
= 200, extra_width
= 123, large_height
= 500;
1922 { BS_PUSHBUTTON
, 0 },
1923 { BS_DEFPUSHBUTTON
, 0 },
1924 { BS_SPLITBUTTON
, extra_width
* 2 + GetSystemMetrics(SM_CXEDGE
) },
1925 { BS_DEFSPLITBUTTON
, extra_width
* 2 + GetSystemMetrics(SM_CXEDGE
) }
1927 LONG image_width
= 48, height
= 48, line_count
, text_width
;
1928 HFONT hfont
, prev_font
;
1936 HBITMAP hmask
, hbmp
;
1940 BUTTON_IMAGELIST biml
= {0};
1944 /* Check for NULL pointer handling */
1945 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_PUSHBUTTON
| default_style
, 0, 0, client_width
, client_height
,
1946 NULL
, NULL
, 0, NULL
);
1947 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, 0);
1948 ok(!ret
, "Expect BCM_GETIDEALSIZE message to return false.\n");
1950 /* Set font so that the test is consistent on Wine and Windows */
1951 ZeroMemory(&lf
, sizeof(lf
));
1952 lf
.lfWeight
= FW_NORMAL
;
1954 lstrcpyA(lf
.lfFaceName
, "Tahoma");
1955 hfont
= CreateFontIndirectA(&lf
);
1956 ok(hfont
!= NULL
, "Failed to create test font.\n");
1960 prev_font
= SelectObject(hdc
, hfont
);
1961 GetTextMetricsA(hdc
, &tm
);
1962 SelectObject(hdc
, prev_font
);
1963 DrawTextA(hdc
, button_text
, -1, &rect
, DT_CALCRECT
);
1964 text_width
= rect
.right
- rect
.left
;
1965 ReleaseDC(hwnd
, hdc
);
1966 DestroyWindow(hwnd
);
1968 /* XP and 2003 doesn't support command links, getting ideal size with button having only text returns client size on these platforms. */
1969 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_DEFCOMMANDLINK
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1971 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1972 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1973 ZeroMemory(&size
, sizeof(size
));
1974 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1975 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1976 if (size
.cx
== client_width
&& size
.cy
== client_height
)
1978 /* on XP and 2003, buttons with image are not supported */
1979 win_skip("Skipping further tests on XP and 2003\n");
1983 /* Tests for image placements */
1984 /* Prepare bitmap */
1986 hmask
= CreateCompatibleBitmap(hdc
, image_width
, height
);
1987 hbmp
= CreateCompatibleBitmap(hdc
, image_width
, height
);
1988 himl
= pImageList_Create(image_width
, height
, ILC_COLOR
, 1, 1);
1989 pImageList_Add(himl
, hbmp
, 0);
1991 #define set_split_info(hwnd) do { \
1992 BUTTON_SPLITINFO _info; \
1994 _info.mask = BCSIF_SIZE; \
1995 _info.size.cx = extra_width; \
1996 _info.size.cy = large_height; \
1997 _ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&_info); \
1998 ok(_ret == TRUE, "Expected BCM_SETSPLITINFO message to return true\n"); \
2001 for (k
= 0; k
< ARRAY_SIZE(pushtype
); k
++)
2003 /* Only bitmap for push button, ideal size should be enough for image and text */
2004 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2005 client_height
, NULL
, NULL
, 0, NULL
);
2006 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2007 set_split_info(hwnd
);
2008 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2009 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2010 ZeroMemory(&size
, sizeof(size
));
2011 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2012 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2013 /* Ideal size contains text rect even show bitmap only */
2014 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2015 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2016 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2017 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2018 DestroyWindow(hwnd
);
2020 /* Image alignments when button has bitmap and text*/
2021 for (i
= 0; i
< ARRAY_SIZE(aligns
); i
++)
2022 for (j
= 0; j
< ARRAY_SIZE(aligns
); j
++)
2024 style
= pushtype
[k
].style
| default_style
| aligns
[i
] | aligns
[j
];
2025 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2026 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2027 set_split_info(hwnd
);
2028 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2029 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2030 ZeroMemory(&size
, sizeof(size
));
2031 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2032 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2033 if (!(style
& (BS_CENTER
| BS_VCENTER
)) || ((style
& BS_CENTER
) && (style
& BS_CENTER
) != BS_CENTER
)
2034 || !(style
& BS_VCENTER
) || (style
& BS_VCENTER
) == BS_VCENTER
)
2035 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2036 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
2037 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2039 ok(size
.cx
>= max(text_width
, height
) + pushtype
[k
].extra_width
&& size
.cy
>= height
+ tm
.tmHeight
,
2040 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
2041 max(text_width
, height
) + pushtype
[k
].extra_width
, size
.cy
, height
+ tm
.tmHeight
);
2042 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2043 DestroyWindow(hwnd
);
2046 /* Image list alignments */
2048 for (i
= 0; i
< ARRAY_SIZE(imagelist_aligns
); i
++)
2050 biml
.uAlign
= imagelist_aligns
[i
];
2051 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| default_style
, 0, 0, client_width
,
2052 client_height
, NULL
, NULL
, 0, NULL
);
2053 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2054 set_split_info(hwnd
);
2055 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2056 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
2057 ZeroMemory(&size
, sizeof(size
));
2058 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2059 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2060 if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_TOP
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_BOTTOM
)
2061 ok(size
.cx
>= max(text_width
, height
) + pushtype
[k
].extra_width
&& size
.cy
>= height
+ tm
.tmHeight
,
2062 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
2063 max(text_width
, height
) + pushtype
[k
].extra_width
, size
.cy
, height
+ tm
.tmHeight
);
2064 else if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_LEFT
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_RIGHT
)
2065 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2066 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
2067 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2069 ok(size
.cx
>= image_width
+ pushtype
[k
].extra_width
&& size
.cy
>= height
,
2070 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
2071 biml
.uAlign
, size
.cx
, image_width
+ pushtype
[k
].extra_width
, size
.cy
, height
);
2072 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2073 DestroyWindow(hwnd
);
2077 /* Create icon from bitmap */
2078 ZeroMemory(&icon_info
, sizeof(icon_info
));
2079 icon_info
.fIcon
= TRUE
;
2080 icon_info
.hbmMask
= hmask
;
2081 icon_info
.hbmColor
= hbmp
;
2082 hicon
= CreateIconIndirect(&icon_info
);
2084 /* Only icon, ideal size should be enough for image and text */
2085 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| BS_ICON
| default_style
, 0, 0, client_width
,
2086 client_height
, NULL
, NULL
, 0, NULL
);
2087 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2088 set_split_info(hwnd
);
2089 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
2090 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2091 ZeroMemory(&size
, sizeof(size
));
2092 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2093 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2094 /* Ideal size contains text rect even show icons only */
2095 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2096 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2097 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2098 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2099 DestroyWindow(hwnd
);
2101 /* Show icon and text */
2102 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| default_style
, 0, 0, client_width
,
2103 client_height
, NULL
, NULL
, 0, NULL
);
2104 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2105 set_split_info(hwnd
);
2106 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
2107 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2108 ZeroMemory(&size
, sizeof(size
));
2109 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2110 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2111 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2112 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2113 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2114 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2115 DestroyWindow(hwnd
);
2119 #undef set_split_info
2122 /* Both bitmap and text for checkbox, ideal size is only enough for text because it doesn't support image(but not image list)*/
2123 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| default_style
, 0, 0, client_width
, client_height
,
2124 NULL
, NULL
, 0, NULL
);
2125 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2126 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2127 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2128 ZeroMemory(&size
, sizeof(size
));
2129 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2130 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2131 ok((size
.cx
<= image_width
+ text_width
&& size
.cx
>= text_width
&& size
.cy
<= max(height
, tm
.tmHeight
)
2132 && size
.cy
>= tm
.tmHeight
),
2133 "Expect ideal cx %d within range (%d, %d ) and ideal cy %d within range (%d, %d )\n", size
.cx
,
2134 text_width
, image_width
+ text_width
, size
.cy
, tm
.tmHeight
, max(height
, tm
.tmHeight
));
2135 DestroyWindow(hwnd
);
2137 /* Both image list and text for checkbox, ideal size should have enough for image list and text */
2138 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
2139 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2140 client_height
, NULL
, NULL
, 0, NULL
);
2141 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2142 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
2143 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2144 ZeroMemory(&size
, sizeof(size
));
2145 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2146 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2147 ok((size
.cx
>= image_width
+ text_width
&& size
.cy
>= max(height
, tm
.tmHeight
)),
2148 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, image_width
+ text_width
, size
.cy
,
2149 max(height
, tm
.tmHeight
));
2150 DestroyWindow(hwnd
);
2152 /* Only bitmap for checkbox, ideal size should have enough for image and text */
2153 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2154 client_height
, NULL
, NULL
, 0, NULL
);
2155 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2156 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2157 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2158 ZeroMemory(&size
, sizeof(size
));
2159 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2160 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2161 ok((size
.cx
>= image_width
+ text_width
&& size
.cy
>= max(height
, tm
.tmHeight
)),
2162 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, image_width
+ text_width
, size
.cy
,
2163 max(height
, tm
.tmHeight
));
2164 DestroyWindow(hwnd
);
2166 /* Test button with only text */
2168 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
2170 style
= type
| default_style
;
2171 hwnd
= CreateWindowA(WC_BUTTONA
, "", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2172 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2173 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2175 ZeroMemory(&size
, sizeof(size
));
2176 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2177 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2179 if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
2181 ok((size
.cx
== 0 && size
.cy
> 0), "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n",
2182 style
, size
.cx
, 0, size
.cy
, 0);
2186 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
2187 "Style 0x%08x expect size.cx == %d and size.cy == %d, got size.cx: %d size.cy: %d\n", style
,
2188 client_width
, client_height
, size
.cx
, size
.cy
);
2190 DestroyWindow(hwnd
);
2193 /* Single line and multiple lines text */
2194 for (line_count
= 1; line_count
<= 2; line_count
++)
2196 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
2198 style
= line_count
> 1 ? type
| BS_MULTILINE
: type
;
2199 style
|= default_style
;
2201 hwnd
= CreateWindowA(WC_BUTTONA
, (line_count
== 2 ? button_text2
: button_text
), style
, 0, 0, client_width
,
2202 client_height
, NULL
, NULL
, 0, NULL
);
2203 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2204 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2205 ZeroMemory(&size
, sizeof(size
));
2206 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2207 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2209 if (type
== BS_3STATE
|| type
== BS_AUTO3STATE
|| type
== BS_GROUPBOX
|| type
== BS_PUSHBOX
2210 || type
== BS_OWNERDRAW
)
2212 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
2213 "Style 0x%08x expect ideal size (%d,%d), got (%d,%d)\n", style
, client_width
, client_height
, size
.cx
,
2216 else if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
2218 ok((size
.cx
== 0 && size
.cy
> 0),
2219 "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n", style
, size
.cx
, 0,
2224 height
= line_count
== 2 ? 2 * tm
.tmHeight
: tm
.tmHeight
;
2225 ok(size
.cx
>= 0 && size
.cy
>= height
, "Style 0x%08x expect ideal cx %d >= 0 and ideal cy %d >= %d\n",
2226 style
, size
.cx
, size
.cy
, height
);
2228 DestroyWindow(hwnd
);
2232 /* Command Link with note */
2233 hwnd
= CreateWindowA(WC_BUTTONA
, "a", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2234 ok(hwnd
!= NULL
, "Expected hwnd not NULL\n");
2235 SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp
);
2236 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)L
"W");
2237 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2240 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2241 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2242 ok(size
.cx
== 13 && size
.cy
> 0, "Expected ideal cx %d == %d and ideal cy %d > %d\n", size
.cx
, 13, size
.cy
, 0);
2246 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2247 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2248 ok(size
.cx
< 32767, "Expected ideal cx to have been adjusted\n");
2249 ok(size
.cx
> image_width
&& size
.cy
== height
, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size
.cx
, image_width
, size
.cy
, height
);
2251 /* Try longer note without word breaks, shouldn't extend height because no word splitting */
2252 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)L
"WWWWWWWWWWWWWWWW");
2253 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2256 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2257 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2258 ok(size
.cx
== k
&& size
.cy
== height
, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size
.cx
, k
, size
.cy
, height
);
2260 /* Now let it extend the width */
2263 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2264 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2265 ok(size
.cx
> k
&& size
.cy
== height
, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size
.cx
, k
, size
.cy
, height
);
2267 /* Use a very long note with words and the same width, should extend the height due to word wrap */
2268 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)L
"This is a long note for the button with many words, which should "
2269 "be overall longer than the text (given the smaller font) and thus wrap.");
2270 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2272 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2273 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2274 ok(size
.cx
<= k
&& size
.cy
> height
, "Expected ideal cx %d <= %d and ideal cy %d > %d\n", size
.cx
, k
, size
.cy
, height
);
2276 /* Now try the wordy note with a width smaller than the image itself, which prevents wrapping */
2278 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2279 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2280 ok(size
.cx
== 13 && size
.cy
== height
, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size
.cx
, 13, size
.cy
, height
);
2281 DestroyWindow(hwnd
);
2284 pImageList_Destroy(himl
);
2286 DeleteObject(hmask
);
2288 DeleteObject(hfont
);
2291 static void test_style(void)
2293 DWORD type
, expected_type
;
2298 for (i
= BS_PUSHBUTTON
; i
<= BS_DEFCOMMANDLINK
; ++i
)
2300 button
= CreateWindowA(WC_BUTTONA
, "test", i
, 0, 0, 50, 50, NULL
, 0, 0, NULL
);
2301 ok(button
!= NULL
, "Expected button not null.\n");
2303 type
= GetWindowLongW(button
, GWL_STYLE
) & BS_TYPEMASK
;
2304 expected_type
= (i
== BS_USERBUTTON
? BS_PUSHBUTTON
: i
);
2305 ok(type
== expected_type
, "Expected type %#x, got %#x.\n", expected_type
, type
);
2307 for (j
= BS_PUSHBUTTON
; j
<= BS_DEFCOMMANDLINK
; ++j
)
2309 ret
= SendMessageA(button
, BM_SETSTYLE
, j
, FALSE
);
2310 ok(ret
== 0, "Expected %#x, got %#lx.\n", 0, ret
);
2312 type
= GetWindowLongW(button
, GWL_STYLE
) & BS_TYPEMASK
;
2313 if (i
>= BS_SPLITBUTTON
&& j
<= BS_DEFPUSHBUTTON
)
2314 expected_type
= (i
& ~BS_DEFPUSHBUTTON
) | j
;
2318 ok(type
== expected_type
|| broken(type
== j
), /* XP */
2319 "Original type %#x, expected new type %#x, got %#x.\n", i
, expected_type
, type
);
2321 DestroyWindow(button
);
2325 static void test_visual(void)
2327 HBITMAP mem_bitmap1
, mem_bitmap2
;
2328 HDC mem_dc1
, mem_dc2
, button_dc
;
2329 HWND button
, parent
;
2334 parent
= CreateWindowA("TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
, 100,
2335 100, 200, 200, 0, 0, 0, NULL
);
2336 ok(!!parent
, "Failed to create the parent window.\n");
2337 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; ++type
)
2339 /* Use WS_DISABLED to avoid glowing animations on Vista and Win7 */
2340 button
= create_button(type
| WS_VISIBLE
| WS_DISABLED
, parent
);
2343 button_dc
= GetDC(button
);
2344 GetClientRect(button
, &rect
);
2345 width
= rect
.right
- rect
.left
;
2346 height
= rect
.bottom
- rect
.top
;
2348 mem_dc1
= CreateCompatibleDC(button_dc
);
2349 mem_bitmap1
= CreateCompatibleBitmap(button_dc
, width
, height
);
2350 SelectObject(mem_dc1
, mem_bitmap1
);
2351 BitBlt(mem_dc1
, 0, 0, width
, height
, button_dc
, 0, 0, SRCCOPY
);
2353 /* Send WM_SETTEXT with the same window name */
2354 SendMessageA(button
, WM_SETTEXT
, 0, (LPARAM
)"test");
2357 mem_dc2
= CreateCompatibleDC(button_dc
);
2358 mem_bitmap2
= CreateCompatibleBitmap(button_dc
, width
, height
);
2359 SelectObject(mem_dc2
, mem_bitmap2
);
2360 BitBlt(mem_dc2
, 0, 0, width
, height
, button_dc
, 0, 0, SRCCOPY
);
2362 todo_wine_if(type
== BS_PUSHBOX
|| (is_theme_active
&& type
== BS_GROUPBOX
))
2363 ok(equal_dc(mem_dc1
, mem_dc2
, width
, height
), "Type %#x: Expected content unchanged.\n", type
);
2365 DeleteObject(mem_bitmap2
);
2366 DeleteObject(mem_bitmap1
);
2369 ReleaseDC(button
, button_dc
);
2370 DestroyWindow(button
);
2373 DestroyWindow(parent
);
2378 BOOL (WINAPI
* pIsThemeActive
)(VOID
);
2379 ULONG_PTR ctx_cookie
;
2383 if (!load_v6_module(&ctx_cookie
, &hCtx
))
2386 uxtheme
= LoadLibraryA("uxtheme.dll");
2389 pIsThemeActive
= (void*)GetProcAddress(uxtheme
, "IsThemeActive");
2391 is_theme_active
= pIsThemeActive();
2392 FreeLibrary(uxtheme
);
2395 register_parent_class();
2398 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2400 test_button_class();
2401 test_button_messages();
2404 test_bm_get_set_image();
2405 test_get_set_imagelist();
2406 test_get_set_textmargin();
2408 test_bcm_get_ideal_size();
2412 unload_v6_module(ctx_cookie
, hCtx
);