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
30 #include "wine/test.h"
35 #define BS_PUSHBOX 0x0000000AL
38 #define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
40 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
41 static BOOL (WINAPI
*pRemoveWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
);
42 static LRESULT (WINAPI
*pDefSubclassProc
)(HWND
, UINT
, WPARAM
, LPARAM
);
43 static HIMAGELIST (WINAPI
*pImageList_Create
)(int, int, UINT
, int, int);
44 static int (WINAPI
*pImageList_Add
)(HIMAGELIST
, HBITMAP
, HBITMAP
);
45 static BOOL (WINAPI
*pImageList_Destroy
)(HIMAGELIST
);
47 /****************** button message test *************************/
48 #define ID_BUTTON 0x000e
50 #define COMBINED_SEQ_INDEX 0
51 #define PARENT_CD_SEQ_INDEX 1
52 #define NUM_MSG_SEQUENCES 2
54 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
56 struct wndclass_redirect_data
66 /* returned pointer is valid as long as activation context is alive */
67 static WCHAR
* get_versioned_classname(const WCHAR
*name
)
69 struct wndclass_redirect_data
*wnddata
;
70 ACTCTX_SECTION_KEYED_DATA data
;
73 memset(&data
, 0, sizeof(data
));
74 data
.cbSize
= sizeof(data
);
75 ret
= FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
, name
, &data
);
76 ok(ret
, "Failed to find class redirection section, error %u\n", GetLastError());
77 wnddata
= (struct wndclass_redirect_data
*)data
.lpData
;
78 return (WCHAR
*)((BYTE
*)wnddata
+ wnddata
->name_offset
);
81 static void init_functions(void)
83 HMODULE hmod
= GetModuleHandleA("comctl32.dll");
84 ok(hmod
!= NULL
, "got %p\n", hmod
);
86 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
87 MAKEFUNC_ORD(SetWindowSubclass
, 410);
88 MAKEFUNC_ORD(RemoveWindowSubclass
, 412);
89 MAKEFUNC_ORD(DefSubclassProc
, 413);
92 #define X(f) p##f = (void *)GetProcAddress(hmod, #f);
99 /* try to make sure pending X events have been processed before continuing */
100 static void flush_events(void)
104 int min_timeout
= 100;
105 DWORD time
= GetTickCount() + diff
;
109 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
110 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
111 diff
= time
- GetTickCount();
115 static BOOL
ignore_message( UINT message
)
117 /* these are always ignored */
118 return (message
>= 0xc000 ||
119 message
== WM_GETICON
||
120 message
== WM_GETOBJECT
||
121 message
== WM_TIMECHANGE
||
122 message
== WM_DISPLAYCHANGE
||
123 message
== WM_DEVICECHANGE
||
124 message
== WM_DWMNCRENDERINGCHANGED
||
125 message
== WM_GETTEXTLENGTH
||
126 message
== WM_GETTEXT
);
129 static LRESULT CALLBACK
button_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, UINT_PTR id
, DWORD_PTR ref_data
)
131 static LONG defwndproc_counter
= 0;
132 struct message msg
= { 0 };
135 if (ignore_message( message
)) return pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
143 ok(GetCapture() == hwnd
, "GetCapture() = %p\n", GetCapture());
146 msg
.message
= message
;
147 msg
.flags
= sent
|wparam
|lparam
;
148 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
151 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
154 if (message
== WM_NCDESTROY
)
155 pRemoveWindowSubclass(hwnd
, button_subclass_proc
, 0);
157 defwndproc_counter
++;
158 ret
= pDefSubclassProc(hwnd
, message
, wParam
, lParam
);
159 defwndproc_counter
--;
173 #define set_test_cd_state(s) do { \
174 test_cd.state = (s); \
175 test_cd.empty = TRUE; \
176 test_cd.line = __LINE__; \
179 #define set_test_cd_ret(r) do { \
181 test_cd.empty = TRUE; \
182 test_cd.line = __LINE__; \
185 static void disable_test_cd(void)
190 static LRESULT WINAPI
test_parent_wndproc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
192 static LONG defwndproc_counter
= 0;
193 static LONG beginpaint_counter
= 0;
194 static HDC cd_first_hdc
;
195 struct message msg
= { 0 };
196 NMCUSTOMDRAW
*cd
= (NMCUSTOMDRAW
*)lParam
;
197 NMBCDROPDOWN
*bcd
= (NMBCDROPDOWN
*)lParam
;
200 if (ignore_message( message
)) return 0;
202 if (message
== WM_PARENTNOTIFY
|| message
== WM_CANCELMODE
||
203 message
== WM_SETFOCUS
|| message
== WM_KILLFOCUS
||
204 message
== WM_ENABLE
|| message
== WM_ENTERIDLE
||
205 message
== WM_DRAWITEM
|| message
== WM_COMMAND
||
206 message
== WM_IME_SETCONTEXT
)
208 msg
.message
= message
;
209 msg
.flags
= sent
|parent
|wparam
|lparam
;
210 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
211 if (beginpaint_counter
) msg
.flags
|= beginpaint
;
214 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
217 if (message
== WM_NOTIFY
&& cd
->hdr
.code
== NM_CUSTOMDRAW
&& test_cd
.line
)
219 /* Ignore an inconsistency across Windows versions */
220 UINT state
= cd
->uItemState
& ~CDIS_SHOWKEYBOARDCUES
;
222 /* Some Windows configurations paint twice with different DC */
225 cd_first_hdc
= cd
->hdc
;
226 test_cd
.empty
= FALSE
;
229 ok_(__FILE__
,test_cd
.line
)(!(cd
->dwDrawStage
& CDDS_ITEM
),
230 "[%u] CDDS_ITEM is set\n", test_cd
.button
);
232 ok_(__FILE__
,test_cd
.line
)(state
== test_cd
.state
,
233 "[%u] expected uItemState %u, got %u\n", test_cd
.button
,
234 test_cd
.state
, state
);
236 msg
.message
= message
;
237 msg
.flags
= sent
|parent
|wparam
|lparam
|id
|custdraw
;
240 msg
.id
= NM_CUSTOMDRAW
;
241 msg
.stage
= cd
->dwDrawStage
;
242 if (cd
->hdc
== cd_first_hdc
)
243 add_message(sequences
, PARENT_CD_SEQ_INDEX
, &msg
);
249 ret
&= ~CDRF_NOTIFYPOSTPAINT
;
250 cd
->dwItemSpec
= 0xdeadbeef;
253 ret
&= ~CDRF_NOTIFYPOSTERASE
;
257 ok_(__FILE__
,test_cd
.line
)(cd
->dwItemSpec
== 0xdeadbeef,
258 "[%u] NMCUSTOMDRAW was not shared, stage %u\n", test_cd
.button
, msg
.stage
);
264 if (message
== WM_NOTIFY
&& bcd
->hdr
.code
== BCN_DROPDOWN
)
266 UINT button
= GetWindowLongW(bcd
->hdr
.hwndFrom
, GWL_STYLE
) & BS_TYPEMASK
;
269 GetClientRect(bcd
->hdr
.hwndFrom
, &rc
);
271 ok(bcd
->hdr
.hwndFrom
!= NULL
, "Received BCN_DROPDOWN with no hwnd attached, wParam %lu id %lu\n",
272 wParam
, bcd
->hdr
.idFrom
);
273 ok(bcd
->hdr
.idFrom
== wParam
, "[%u] Mismatch between wParam (%lu) and idFrom (%lu)\n",
274 button
, wParam
, bcd
->hdr
.idFrom
);
275 ok(EqualRect(&rc
, &bcd
->rcButton
), "[%u] Wrong rcButton, expected %s got %s\n",
276 button
, wine_dbgstr_rect(&rc
), wine_dbgstr_rect(&bcd
->rcButton
));
278 msg
.message
= message
;
279 msg
.flags
= sent
|parent
|wparam
|lparam
|id
;
282 msg
.id
= BCN_DROPDOWN
;
283 add_message(sequences
, COMBINED_SEQ_INDEX
, &msg
);
287 if (message
== WM_PAINT
)
290 beginpaint_counter
++;
291 BeginPaint( hwnd
, &ps
);
292 beginpaint_counter
--;
293 EndPaint( hwnd
, &ps
);
297 defwndproc_counter
++;
298 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
299 defwndproc_counter
--;
304 static const struct message setfocus_seq
[] =
306 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
307 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
308 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
309 { WM_SETFOCUS
, sent
|wparam
},
310 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
311 { WM_APP
, sent
|wparam
|lparam
},
316 static const struct message killfocus_seq
[] =
318 { WM_KILLFOCUS
, sent
|wparam
, 0 },
319 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
320 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
321 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
322 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
327 static const struct message setfocus_static_seq
[] =
329 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
330 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
331 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
332 { WM_SETFOCUS
, sent
|wparam
, 0 },
333 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
334 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
335 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
340 static const struct message setfocus_groupbox_seq
[] =
342 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
343 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
344 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
345 { WM_SETFOCUS
, sent
|wparam
, 0 },
346 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
347 { WM_COMMAND
, sent
|wparam
|parent
|optional
, MAKEWPARAM(ID_BUTTON
, BN_CLICKED
) }, /* radio button */
348 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
353 static const struct message killfocus_static_seq
[] =
355 { WM_KILLFOCUS
, sent
|wparam
, 0 },
356 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
357 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
358 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
359 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
364 static const struct message setfocus_ownerdraw_seq
[] =
366 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
367 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
368 { BM_GETSTATE
, sent
|optional
}, /* when touchscreen is present */
369 { WM_SETFOCUS
, sent
|wparam
, 0 },
370 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
371 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_SETFOCUS
) },
372 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
373 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 1 },
377 static const struct message killfocus_ownerdraw_seq
[] =
379 { WM_KILLFOCUS
, sent
|wparam
, 0 },
380 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_KILLFOCUS
) },
381 { WM_IME_SETCONTEXT
, sent
|wparam
|optional
, 0 },
382 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 1 },
383 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
385 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
389 static const struct message lbuttondown_seq
[] =
391 { WM_LBUTTONDOWN
, sent
|wparam
|lparam
, 0, 0 },
392 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
393 { WM_IME_NOTIFY
, sent
|wparam
|defwinproc
|optional
, 2 },
394 { BM_GETSTATE
, sent
|defwinproc
|optional
}, /* when touchscreen is present */
395 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
396 { BM_SETSTATE
, sent
|wparam
|defwinproc
, TRUE
},
400 static const struct message lbuttonup_seq
[] =
402 { WM_LBUTTONUP
, sent
|wparam
|lparam
, 0, 0 },
403 { BM_SETSTATE
, sent
|wparam
|defwinproc
, FALSE
},
404 { WM_CAPTURECHANGED
, sent
|wparam
|defwinproc
, 0 },
405 { WM_COMMAND
, sent
|wparam
|defwinproc
, 0 },
409 static const struct message setfont_seq
[] =
411 { WM_SETFONT
, sent
},
415 static const struct message setstyle_seq
[] =
417 { BM_SETSTYLE
, sent
},
418 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
419 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
420 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
422 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
423 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
424 { WM_PAINT
, sent
|optional
},
428 static const struct message setstyle_static_seq
[] =
430 { BM_SETSTYLE
, sent
},
431 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
432 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
433 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
435 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
436 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
440 static const struct message setstyle_user_seq
[] =
442 { BM_SETSTYLE
, sent
},
443 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
444 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
445 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
447 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
448 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
452 static const struct message setstyle_ownerdraw_seq
[] =
454 { BM_SETSTYLE
, sent
},
455 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
456 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
457 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
459 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
460 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
461 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
465 static const struct message setstate_seq
[] =
467 { BM_SETSTATE
, sent
},
468 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
470 { WM_PAINT
, sent
|optional
},
474 static const struct message setstate_static_seq
[] =
476 { BM_SETSTATE
, sent
},
477 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
479 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
480 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
484 static const struct message setstate_user_seq
[] =
486 { BM_SETSTATE
, sent
},
487 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_HILITE
) },
488 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
493 static const struct message setstate_ownerdraw_seq
[] =
495 { BM_SETSTATE
, sent
},
496 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
498 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
499 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
500 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
504 static const struct message clearstate_seq
[] =
506 { BM_SETSTATE
, sent
},
507 { WM_COMMAND
, sent
|wparam
|parent
, MAKEWPARAM(ID_BUTTON
, BN_UNHILITE
) },
508 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
510 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
511 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
515 static const struct message clearstate_ownerdraw_seq
[] =
517 { BM_SETSTATE
, sent
},
518 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
520 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
521 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
522 { WM_DRAWITEM
, sent
|wparam
|parent
, ID_BUTTON
},
526 static const struct message setcheck_ignored_seq
[] =
528 { BM_SETCHECK
, sent
},
529 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
530 { WM_PAINT
, sent
|optional
},
534 static const struct message setcheck_static_seq
[] =
536 { BM_SETCHECK
, sent
},
537 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
539 { WM_NCPAINT
, sent
|optional
}, /* FIXME: Wine sends it */
540 { WM_ERASEBKGND
, sent
|defwinproc
|optional
},
544 static const struct message setcheck_radio_seq
[] =
546 { BM_SETCHECK
, sent
},
547 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
548 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
549 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
553 static const struct message setcheck_radio_redraw_seq
[] =
555 { BM_SETCHECK
, sent
},
556 { WM_STYLECHANGING
, sent
|wparam
|defwinproc
, GWL_STYLE
},
557 { WM_STYLECHANGED
, sent
|wparam
|defwinproc
, GWL_STYLE
},
558 { WM_APP
, sent
|wparam
|lparam
, 0, 0 },
560 { WM_NCPAINT
, sent
|defwinproc
|optional
}, /* FIXME: Wine sends it */
564 static const struct message empty_cd_seq
[] = { { 0 } };
566 static const struct message pre_cd_seq
[] =
568 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
572 static const struct message pre_pre_cd_seq
[] =
574 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
575 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
579 static const struct message pre_post_pre_cd_seq
[] =
581 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
582 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTERASE
},
583 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
587 static const struct message pre_pre_post_cd_seq
[] =
589 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
590 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
591 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTPAINT
},
595 static const struct message pre_post_pre_post_cd_seq
[] =
597 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREERASE
},
598 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTERASE
},
599 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_PREPAINT
},
600 { WM_NOTIFY
, sent
|parent
|id
|custdraw
, 0, 0, NM_CUSTOMDRAW
, CDDS_POSTPAINT
},
604 static const struct message bcn_dropdown_seq
[] =
606 { WM_KEYDOWN
, sent
|wparam
|lparam
, VK_DOWN
, 0 },
607 { BCM_SETDROPDOWNSTATE
, sent
|wparam
|lparam
|defwinproc
, 1, 0 },
608 { WM_NOTIFY
, sent
|parent
|id
, 0, 0, BCN_DROPDOWN
},
609 { BCM_SETDROPDOWNSTATE
, sent
|wparam
|lparam
|defwinproc
, 0, 0 },
610 { WM_KEYUP
, sent
|wparam
|lparam
, VK_DOWN
, 0xc0000000 },
612 { WM_DRAWITEM
, sent
|parent
|optional
}, /* for owner draw button */
613 { WM_PAINT
, sent
|optional
}, /* sometimes sent rarely */
614 { WM_DRAWITEM
, sent
|parent
|optional
},
618 static HWND
create_button(DWORD style
, HWND parent
)
625 style
|= WS_CHILD
|BS_NOTIFY
;
626 menuid
= (HMENU
)ID_BUTTON
;
628 hwnd
= CreateWindowExA(0, WC_BUTTONA
, "test", style
, 0, 0, 50, 14, parent
, menuid
, 0, NULL
);
629 ok(hwnd
!= NULL
, "failed to create a button, 0x%08x, %p\n", style
, parent
);
630 pSetWindowSubclass(hwnd
, button_subclass_proc
, 0, 0);
634 static void test_button_messages(void)
647 const struct message
*setfocus
;
648 const struct message
*killfocus
;
649 const struct message
*setstyle
;
650 const struct message
*setstate
;
651 const struct message
*clearstate
;
652 const struct message
*setcheck
;
653 enum cd_seq_type cd_setfocus_type
;
654 enum cd_seq_type cd_setstyle_type
;
655 enum cd_seq_type cd_setstate_type
;
656 enum cd_seq_type cd_setcheck_type
;
658 { BS_PUSHBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
659 setfocus_seq
, killfocus_seq
, setstyle_seq
,
660 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
661 cd_seq_normal
, cd_seq_normal
, cd_seq_normal
, cd_seq_optional
},
662 { BS_DEFPUSHBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
663 setfocus_seq
, killfocus_seq
, setstyle_seq
,
664 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
665 cd_seq_normal
, cd_seq_normal
, cd_seq_normal
, cd_seq_optional
},
666 { BS_CHECKBOX
, DLGC_BUTTON
,
667 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
668 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
669 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
670 { BS_AUTOCHECKBOX
, DLGC_BUTTON
,
671 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
672 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
673 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
674 { BS_RADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
675 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
676 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
,
677 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
678 { BS_3STATE
, DLGC_BUTTON
,
679 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
680 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
681 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
682 { BS_AUTO3STATE
, DLGC_BUTTON
,
683 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
684 setstate_static_seq
, setstate_static_seq
, setcheck_static_seq
,
685 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
686 { BS_GROUPBOX
, DLGC_STATIC
,
687 setfocus_groupbox_seq
, killfocus_static_seq
, setstyle_static_seq
,
688 setstate_static_seq
, setstate_static_seq
, setcheck_ignored_seq
,
689 cd_seq_empty
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
690 { BS_USERBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
691 setfocus_seq
, killfocus_seq
, setstyle_user_seq
,
692 setstate_user_seq
, clearstate_seq
, setcheck_ignored_seq
,
693 cd_seq_normal
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
694 { BS_AUTORADIOBUTTON
, DLGC_BUTTON
| DLGC_RADIOBUTTON
,
695 setfocus_static_seq
, killfocus_static_seq
, setstyle_static_seq
,
696 setstate_static_seq
, setstate_static_seq
, setcheck_radio_redraw_seq
,
697 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_optional
},
698 { BS_OWNERDRAW
, DLGC_BUTTON
,
699 setfocus_ownerdraw_seq
, killfocus_ownerdraw_seq
, setstyle_ownerdraw_seq
,
700 setstate_ownerdraw_seq
, clearstate_ownerdraw_seq
, setcheck_ignored_seq
,
701 cd_seq_empty
, cd_seq_empty
, cd_seq_empty
, cd_seq_empty
},
702 { BS_SPLITBUTTON
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
| DLGC_WANTARROWS
,
703 setfocus_seq
, killfocus_seq
, setstyle_seq
,
704 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
705 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
706 { BS_DEFSPLITBUTTON
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
| DLGC_WANTARROWS
,
707 setfocus_seq
, killfocus_seq
, setstyle_seq
,
708 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
709 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
710 { BS_COMMANDLINK
, DLGC_BUTTON
| DLGC_UNDEFPUSHBUTTON
,
711 setfocus_seq
, killfocus_seq
, setstyle_seq
,
712 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
713 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
},
714 { BS_DEFCOMMANDLINK
, DLGC_BUTTON
| DLGC_DEFPUSHBUTTON
,
715 setfocus_seq
, killfocus_seq
, setstyle_seq
,
716 setstate_seq
, setstate_seq
, setcheck_ignored_seq
,
717 cd_seq_optional
, cd_seq_optional
, cd_seq_optional
, cd_seq_empty
}
719 LOGFONTA logfont
= { 0 };
720 const struct message
*seq
, *cd_seq
;
727 /* selection with VK_SPACE should capture button window */
728 hwnd
= create_button(BS_CHECKBOX
| WS_VISIBLE
| WS_POPUP
, NULL
);
729 ok(hwnd
!= 0, "Failed to create button window\n");
732 SendMessageA(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
733 ok(GetCapture() == hwnd
, "Should be captured on VK_SPACE WM_KEYDOWN\n");
734 SendMessageA(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
737 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
738 100, 100, 200, 200, 0, 0, 0, NULL
);
739 ok(parent
!= 0, "Failed to create parent window\n");
741 logfont
.lfHeight
= -12;
742 logfont
.lfWeight
= FW_NORMAL
;
743 strcpy(logfont
.lfFaceName
, "Tahoma");
745 hfont2
= CreateFontIndirectA(&logfont
);
746 ok(hfont2
!= NULL
, "Failed to create Tahoma font\n");
748 #define check_cd_seq(type, context) do { \
749 if (button[i].type != cd_seq_optional || !test_cd.empty) \
750 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, cd_seq, "[CustomDraw] " context, FALSE); \
753 for (i
= 0; i
< ARRAY_SIZE(button
); i
++)
755 HFONT prevfont
, hfont
;
760 test_cd
.button
= button
[i
].style
;
761 hwnd
= create_button(button
[i
].style
, parent
);
762 ok(hwnd
!= NULL
, "Failed to create a button.\n");
764 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
765 style
&= ~(WS_CHILD
| BS_NOTIFY
);
766 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
767 if (button
[i
].style
== BS_USERBUTTON
)
768 ok(style
== BS_PUSHBUTTON
, "expected style BS_PUSHBUTTON got %x\n", style
);
770 ok(style
== button
[i
].style
, "expected style %x got %x\n", button
[i
].style
, style
);
772 dlg_code
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
773 if (button
[i
].style
== BS_SPLITBUTTON
||
774 button
[i
].style
== BS_DEFSPLITBUTTON
||
775 button
[i
].style
== BS_COMMANDLINK
||
776 button
[i
].style
== BS_DEFCOMMANDLINK
)
778 ok(dlg_code
== button
[i
].dlg_code
|| broken(dlg_code
== DLGC_BUTTON
) /* WinXP */, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
781 ok(dlg_code
== button
[i
].dlg_code
, "%u: wrong dlg_code %08x\n", i
, dlg_code
);
783 ShowWindow(hwnd
, SW_SHOW
);
788 cd_seq
= (button
[i
].cd_setfocus_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
789 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
790 set_test_cd_ret(CDRF_DODEFAULT
);
791 set_test_cd_state(CDIS_FOCUS
);
793 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
795 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
796 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
797 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setfocus
, "SetFocus(hwnd) on a button", FALSE
);
798 check_cd_seq(cd_setfocus_type
, "SetFocus(hwnd)");
800 set_test_cd_state(0);
802 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
803 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
804 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].killfocus
, "SetFocus(0) on a button", FALSE
);
805 check_cd_seq(cd_setfocus_type
, "SetFocus(0)");
806 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
808 cd_seq
= (button
[i
].cd_setstyle_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
809 set_test_cd_state(0);
811 SendMessageA(hwnd
, BM_SETSTYLE
, button
[i
].style
| BS_BOTTOM
, TRUE
);
812 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
813 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
814 todo
= button
[i
].style
== BS_OWNERDRAW
;
815 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstyle
, "BM_SETSTYLE on a button", todo
);
816 check_cd_seq(cd_setstyle_type
, "BM_SETSTYLE");
818 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
819 style
&= ~(WS_VISIBLE
| WS_CHILD
| BS_NOTIFY
);
820 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
821 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
823 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
824 ok(state
== 0, "expected state 0, got %04x\n", state
);
826 cd_seq
= (button
[i
].cd_setstate_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
827 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
828 set_test_cd_state(CDIS_SELECTED
);
830 SendMessageA(hwnd
, BM_SETSTATE
, TRUE
, 0);
831 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
832 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
833 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setstate
, "BM_SETSTATE/TRUE on a button", FALSE
);
834 check_cd_seq(cd_setstate_type
, "BM_SETSTATE/TRUE");
836 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
837 ok(state
== BST_PUSHED
, "expected state 0x0004, got %04x\n", state
);
839 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
840 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
841 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
843 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
844 set_test_cd_state(0);
846 SendMessageA(hwnd
, BM_SETSTATE
, FALSE
, 0);
847 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
848 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
849 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].clearstate
, "BM_SETSTATE/FALSE on a button", FALSE
);
850 check_cd_seq(cd_setstate_type
, "BM_SETSTATE/FALSE");
852 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
853 ok(state
== 0, "expected state 0, got %04x\n", state
);
855 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
856 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
857 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
859 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
860 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
862 cd_seq
= (button
[i
].cd_setcheck_type
== cd_seq_empty
) ? empty_cd_seq
: pre_pre_cd_seq
;
863 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
864 set_test_cd_state(0);
866 if (button
[i
].style
== BS_RADIOBUTTON
||
867 button
[i
].style
== BS_AUTORADIOBUTTON
)
869 seq
= setcheck_radio_seq
;
872 seq
= setcheck_ignored_seq
;
874 SendMessageA(hwnd
, BM_SETCHECK
, BST_UNCHECKED
, 0);
875 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
876 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
877 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, seq
, "BM_SETCHECK on a button", FALSE
);
878 check_cd_seq(cd_setcheck_type
, "BM_SETCHECK");
880 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
881 ok(state
== BST_UNCHECKED
, "expected BST_UNCHECKED, got %04x\n", state
);
883 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
884 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
885 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
887 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
888 set_test_cd_state(0);
890 SendMessageA(hwnd
, BM_SETCHECK
, BST_CHECKED
, 0);
891 SendMessageA(hwnd
, WM_APP
, 0, 0); /* place a separator mark here */
892 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
893 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, button
[i
].setcheck
, "BM_SETCHECK on a button", FALSE
);
894 check_cd_seq(cd_setcheck_type
, "BM_SETCHECK");
896 state
= SendMessageA(hwnd
, BM_GETCHECK
, 0, 0);
897 if (button
[i
].style
== BS_PUSHBUTTON
||
898 button
[i
].style
== BS_DEFPUSHBUTTON
||
899 button
[i
].style
== BS_GROUPBOX
||
900 button
[i
].style
== BS_USERBUTTON
||
901 button
[i
].style
== BS_OWNERDRAW
||
902 button
[i
].style
== BS_SPLITBUTTON
||
903 button
[i
].style
== BS_DEFSPLITBUTTON
||
904 button
[i
].style
== BS_COMMANDLINK
||
905 button
[i
].style
== BS_DEFCOMMANDLINK
)
907 ok(state
== BST_UNCHECKED
, "expected check BST_UNCHECKED, got %04x\n", state
);
910 ok(state
== BST_CHECKED
, "expected check BST_CHECKED, got %04x\n", state
);
912 style
= GetWindowLongA(hwnd
, GWL_STYLE
);
913 style
&= ~(WS_CHILD
| BS_NOTIFY
| WS_VISIBLE
);
914 if (button
[i
].style
== BS_RADIOBUTTON
||
915 button
[i
].style
== BS_AUTORADIOBUTTON
)
916 ok(style
== (button
[i
].style
| WS_TABSTOP
), "expected style %04x | WS_TABSTOP got %04x\n", button
[i
].style
, style
);
918 ok(style
== button
[i
].style
, "expected style %04x got %04x\n", button
[i
].style
, style
);
920 /* Test that original font is not selected back after painting */
921 hfont
= (HFONT
)SendMessageA(hwnd
, WM_GETFONT
, 0, 0);
922 ok(hfont
== NULL
, "Unexpected control font.\n");
924 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)GetStockObject(SYSTEM_FONT
), 0);
926 hdc
= CreateCompatibleDC(0);
928 prevfont
= SelectObject(hdc
, hfont2
);
929 SendMessageA(hwnd
, WM_PRINTCLIENT
, (WPARAM
)hdc
, 0);
930 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
931 "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i
);
932 SelectObject(hdc
, prevfont
);
934 prevfont
= SelectObject(hdc
, hfont2
);
935 SendMessageA(hwnd
, WM_PAINT
, (WPARAM
)hdc
, 0);
936 ok(hfont2
!= GetCurrentObject(hdc
, OBJ_FONT
) || broken(hfont2
== GetCurrentObject(hdc
, OBJ_FONT
)) /* WinXP */,
937 "button[%u]: unexpected font selected after WM_PAINT\n", i
);
938 SelectObject(hdc
, prevfont
);
942 /* Test Custom Draw return values */
943 if (button
[i
].cd_setfocus_type
!= cd_seq_empty
&&
944 broken(button
[i
].style
!= BS_USERBUTTON
) /* WinXP */)
950 const struct message
*seq
;
952 { "CDRF_DODEFAULT", CDRF_DODEFAULT
, pre_pre_cd_seq
},
953 { "CDRF_DOERASE", CDRF_DOERASE
, pre_pre_cd_seq
},
954 { "CDRF_SKIPDEFAULT", CDRF_SKIPDEFAULT
, pre_cd_seq
},
955 { "CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
956 CDRF_SKIPDEFAULT
| CDRF_NOTIFYPOSTERASE
| CDRF_NOTIFYPOSTPAINT
, pre_cd_seq
},
957 { "CDRF_NOTIFYPOSTERASE", CDRF_NOTIFYPOSTERASE
, pre_post_pre_cd_seq
},
958 { "CDRF_NOTIFYPOSTPAINT", CDRF_NOTIFYPOSTPAINT
, pre_pre_post_cd_seq
},
959 { "CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
960 CDRF_NOTIFYPOSTERASE
| CDRF_NOTIFYPOSTPAINT
, pre_post_pre_post_cd_seq
},
964 for (k
= 0; k
< ARRAY_SIZE(ret
); k
++)
968 set_test_cd_ret(ret
[k
].val
);
969 set_test_cd_state(CDIS_FOCUS
);
971 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
973 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
974 if (button
[i
].cd_setfocus_type
!= cd_seq_optional
|| !test_cd
.empty
)
975 ok_sequence(sequences
, PARENT_CD_SEQ_INDEX
, ret
[k
].seq
, ret
[k
].context
, FALSE
);
981 if (!broken(LOBYTE(LOWORD(GetVersion())) < 6)) /* not available pre-Vista */
983 /* Send down arrow key to make the buttons send the drop down notification */
984 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
985 SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
986 SendMessageW(hwnd
, WM_KEYUP
, VK_DOWN
, 0xc0000000);
987 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
988 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, bcn_dropdown_seq
, "BCN_DROPDOWN from the button", FALSE
);
996 DeleteObject(hfont2
);
997 DestroyWindow(parent
);
999 hwnd
= create_button(BS_PUSHBUTTON
, NULL
);
1001 SetForegroundWindow(hwnd
);
1004 SetActiveWindow(hwnd
);
1006 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1008 SendMessageA(hwnd
, WM_LBUTTONDOWN
, 0, 0);
1009 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttondown_seq
, "WM_LBUTTONDOWN on a button", FALSE
);
1011 SendMessageA(hwnd
, WM_LBUTTONUP
, 0, 0);
1012 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, lbuttonup_seq
, "WM_LBUTTONUP on a button", TRUE
);
1014 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1015 zfont
= GetStockObject(SYSTEM_FONT
);
1016 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)zfont
, TRUE
);
1018 ok_sequence(sequences
, COMBINED_SEQ_INDEX
, setfont_seq
, "WM_SETFONT on a button", FALSE
);
1020 DestroyWindow(hwnd
);
1023 static void test_button_class(void)
1025 static const WCHAR testW
[] = {'t','e','s','t',0};
1026 WNDCLASSEXW exW
, ex2W
;
1034 ret
= GetClassInfoExA(NULL
, WC_BUTTONA
, &exA
);
1035 ok(ret
, "got %d\n", ret
);
1036 ok(IS_WNDPROC_HANDLE(exA
.lpfnWndProc
), "got %p\n", exA
.lpfnWndProc
);
1037 ok(exA
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exA
.cbClsExtra
);
1038 ok(exA
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exA
.cbWndExtra
);
1040 ret
= GetClassInfoExW(NULL
, WC_BUTTONW
, &exW
);
1041 ok(ret
, "got %d\n", ret
);
1042 ok(!IS_WNDPROC_HANDLE(exW
.lpfnWndProc
), "got %p\n", exW
.lpfnWndProc
);
1043 ok(exW
.cbClsExtra
== 0, "Unexpected class bytes %d.\n", exW
.cbClsExtra
);
1044 ok(exW
.cbWndExtra
== sizeof(void *), "Unexpected window bytes %d.\n", exW
.cbWndExtra
);
1046 /* check that versioned class is also accessible */
1047 nameW
= get_versioned_classname(WC_BUTTONW
);
1048 ok(lstrcmpW(nameW
, WC_BUTTONW
), "got %s\n", wine_dbgstr_w(nameW
));
1050 ret
= GetClassInfoExW(NULL
, nameW
, &ex2W
);
1051 ok(ret
, "got %d\n", ret
);
1052 ok(ex2W
.lpfnWndProc
== exW
.lpfnWndProc
, "got %p, %p\n", exW
.lpfnWndProc
, ex2W
.lpfnWndProc
);
1054 /* Check reported class name */
1055 hwnd
= create_button(BS_CHECKBOX
, NULL
);
1056 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
1057 ok(len
== strlen(buffA
), "got %d\n", len
);
1058 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1060 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
1061 ok(len
== strlen(buffA
), "got %d\n", len
);
1062 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1063 DestroyWindow(hwnd
);
1065 /* explicitly create with versioned class name */
1066 hwnd
= CreateWindowExW(0, nameW
, testW
, BS_CHECKBOX
, 0, 0, 50, 14, NULL
, 0, 0, NULL
);
1067 ok(hwnd
!= NULL
, "failed to create a window %s\n", wine_dbgstr_w(nameW
));
1069 len
= GetClassNameA(hwnd
, buffA
, sizeof(buffA
));
1070 ok(len
== strlen(buffA
), "got %d\n", len
);
1071 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1073 len
= RealGetWindowClassA(hwnd
, buffA
, sizeof(buffA
));
1074 ok(len
== strlen(buffA
), "got %d\n", len
);
1075 ok(!strcmp(buffA
, "Button"), "got %s\n", buffA
);
1077 DestroyWindow(hwnd
);
1080 static void test_note(void)
1084 WCHAR test_w
[] = {'t', 'e', 's', 't', 0};
1085 WCHAR tes_w
[] = {'t', 'e', 's', 0};
1086 WCHAR deadbeef_w
[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
1092 hwnd
= create_button(BS_COMMANDLINK
, NULL
);
1093 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1094 SetLastError(0xdeadbeef);
1095 size
= ARRAY_SIZE(buffer_w
);
1096 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1097 error
= GetLastError();
1098 if (!ret
&& error
== 0xdeadbeef)
1100 win_skip("BCM_GETNOTE message is unavailable. Skipping note tests\n"); /* xp or 2003 */
1101 DestroyWindow(hwnd
);
1104 DestroyWindow(hwnd
);
1106 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1108 if (type
== BS_DEFCOMMANDLINK
|| type
== BS_COMMANDLINK
)
1110 hwnd
= create_button(type
, NULL
);
1111 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1113 /* Get note when note hasn't been not set yet */
1114 SetLastError(0xdeadbeef);
1115 lstrcpyW(buffer_w
, deadbeef_w
);
1116 size
= ARRAY_SIZE(buffer_w
);
1117 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1118 error
= GetLastError();
1119 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1120 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1121 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1122 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1123 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1124 ERROR_INVALID_PARAMETER
, error
);
1126 /* Get note length when note is not set */
1127 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1128 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
1130 /* Successful set note, get note and get note length */
1131 SetLastError(0xdeadbeef);
1132 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)test_w
);
1133 ok(ret
, "Expect BCM_SETNOTE return true\n");
1134 error
= GetLastError();
1135 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1137 SetLastError(0xdeadbeef);
1138 lstrcpyW(buffer_w
, deadbeef_w
);
1139 size
= ARRAY_SIZE(buffer_w
);
1140 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1141 ok(ret
, "Expect BCM_GETNOTE return true\n");
1142 ok(!lstrcmpW(buffer_w
, test_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(test_w
),
1143 wine_dbgstr_w(buffer_w
));
1144 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1145 error
= GetLastError();
1146 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1148 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1149 ok(ret
== ARRAY_SIZE(test_w
) - 1, "Got: %d\n", ret
);
1151 /* Insufficient buffer, return partial string */
1152 SetLastError(0xdeadbeef);
1153 lstrcpyW(buffer_w
, deadbeef_w
);
1154 size
= ARRAY_SIZE(test_w
) - 1;
1155 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1156 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1157 ok(!lstrcmpW(buffer_w
, tes_w
), "Expect note: %s, got: %s\n", wine_dbgstr_w(tes_w
),
1158 wine_dbgstr_w(buffer_w
));
1159 ok(size
== ARRAY_SIZE(test_w
), "Got: %d\n", size
);
1160 error
= GetLastError();
1161 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1162 ERROR_INSUFFICIENT_BUFFER
, error
);
1164 /* Set note with NULL buffer */
1165 SetLastError(0xdeadbeef);
1166 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, 0);
1167 ok(ret
, "Expect BCM_SETNOTE return false\n");
1168 error
= GetLastError();
1169 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1171 /* Check that set note with NULL buffer make note empty */
1172 SetLastError(0xdeadbeef);
1173 lstrcpyW(buffer_w
, deadbeef_w
);
1174 size
= ARRAY_SIZE(buffer_w
);
1175 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1176 ok(ret
, "Expect BCM_GETNOTE return true\n");
1177 ok(lstrlenW(buffer_w
) == 0, "Expect note length 0\n");
1178 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1179 error
= GetLastError();
1180 ok(error
== NO_ERROR
, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR
, error
);
1181 ret
= SendMessageA(hwnd
, BCM_GETNOTELENGTH
, 0, 0);
1182 ok(ret
== 0, "Expect note length: %d, got: %d\n", 0, ret
);
1184 /* Get note with NULL buffer */
1185 SetLastError(0xdeadbeef);
1186 size
= ARRAY_SIZE(buffer_w
);
1187 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, 0);
1188 ok(!ret
, "Expect BCM_SETNOTE return false\n");
1189 ok(size
== ARRAY_SIZE(buffer_w
), "Got: %d\n", size
);
1190 error
= GetLastError();
1191 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1192 ERROR_INVALID_PARAMETER
, error
);
1194 /* Get note with NULL size */
1195 SetLastError(0xdeadbeef);
1196 lstrcpyW(buffer_w
, deadbeef_w
);
1197 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, 0, (LPARAM
)buffer_w
);
1198 ok(!ret
, "Expect BCM_SETNOTE return false\n");
1199 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1200 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1201 error
= GetLastError();
1202 ok(error
== ERROR_INVALID_PARAMETER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1203 ERROR_INVALID_PARAMETER
, error
);
1205 /* Get note with zero size */
1206 SetLastError(0xdeadbeef);
1208 lstrcpyW(buffer_w
, deadbeef_w
);
1209 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1210 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1211 ok(!lstrcmpW(buffer_w
, deadbeef_w
), "Expect note: %s, got: %s\n",
1212 wine_dbgstr_w(deadbeef_w
), wine_dbgstr_w(buffer_w
));
1213 ok(size
== 1, "Got: %d\n", size
);
1214 error
= GetLastError();
1215 ok(error
== ERROR_INSUFFICIENT_BUFFER
, "Expect last error: 0x%08x, got: 0x%08x\n",
1216 ERROR_INSUFFICIENT_BUFFER
, error
);
1218 DestroyWindow(hwnd
);
1222 hwnd
= create_button(type
, NULL
);
1223 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1224 SetLastError(0xdeadbeef);
1225 size
= ARRAY_SIZE(buffer_w
);
1226 ret
= SendMessageA(hwnd
, BCM_GETNOTE
, (WPARAM
)&size
, (LPARAM
)buffer_w
);
1227 ok(!ret
, "Expect BCM_GETNOTE return false\n");
1228 error
= GetLastError();
1229 ok(error
== ERROR_NOT_SUPPORTED
, "Expect last error: 0x%08x, got: 0x%08x\n",
1230 ERROR_NOT_SUPPORTED
, error
);
1231 DestroyWindow(hwnd
);
1236 static void test_bm_get_set_image(void)
1243 ICONINFO icon_info2x2
;
1249 static const DWORD default_style
= BS_PUSHBUTTON
| WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
1252 hbmp1x1
= CreateCompatibleBitmap(hdc
, 1, 1);
1253 hbmp2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
1254 ZeroMemory(&bm
, sizeof(bm
));
1255 ok(GetObjectW(hbmp1x1
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1256 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1257 bm
.bmWidth
, bm
.bmHeight
);
1258 ZeroMemory(&bm
, sizeof(bm
));
1259 ok(GetObjectW(hbmp2x2
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1260 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1261 bm
.bmWidth
, bm
.bmHeight
);
1263 hmask2x2
= CreateCompatibleBitmap(hdc
, 2, 2);
1264 ZeroMemory(&icon_info2x2
, sizeof(icon_info2x2
));
1265 icon_info2x2
.fIcon
= TRUE
;
1266 icon_info2x2
.hbmMask
= hmask2x2
;
1267 icon_info2x2
.hbmColor
= hbmp2x2
;
1268 hicon2x2
= CreateIconIndirect(&icon_info2x2
);
1269 ok(hicon2x2
!=NULL
, "Expect CreateIconIndirect() success\n");
1271 ZeroMemory(&icon_info
, sizeof(icon_info
));
1272 ok(GetIconInfo(hicon2x2
, &icon_info
), "Expect GetIconInfo() success\n");
1273 ZeroMemory(&bm
, sizeof(bm
));
1274 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1275 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1276 bm
.bmWidth
, bm
.bmHeight
);
1277 DeleteObject(icon_info
.hbmColor
);
1278 DeleteObject(icon_info
.hbmMask
);
1280 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1282 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1283 /* Get image when image is not set */
1284 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1285 ok(hbmp
== 0, "Expect hbmp == 0\n");
1287 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1288 ok(hbmp
== 0, "Expect hbmp == 0\n");
1289 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1290 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1291 /* Set null resets image */
1292 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, 0);
1293 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1294 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1295 ok(hbmp
== 0, "Expect hbmp == 0\n");
1296 DestroyWindow(hwnd
);
1298 /* Set bitmap with BS_BITMAP */
1299 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1301 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1302 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1303 ok(hbmp
== 0, "Expect hbmp == 0\n");
1304 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1305 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1306 ZeroMemory(&bm
, sizeof(bm
));
1307 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1308 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1309 bm
.bmWidth
, bm
.bmHeight
);
1310 DestroyWindow(hwnd
);
1312 /* Set bitmap without BS_BITMAP */
1313 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1314 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1315 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1316 ok(hbmp
== 0, "Expect hbmp == 0\n");
1317 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1321 win_skip("Show both image and text is not supported. Skip following tests.\n");
1322 DestroyWindow(hwnd
);
1325 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1326 ZeroMemory(&bm
, sizeof(bm
));
1327 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1328 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1329 bm
.bmWidth
, bm
.bmHeight
);
1330 DestroyWindow(hwnd
);
1332 /* Set icon with BS_ICON */
1333 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1335 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1336 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1337 ok(hicon
== 0, "Expect hicon == 0\n");
1338 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1339 ok(hicon
!= 0, "Expect hicon != 0\n");
1340 ZeroMemory(&icon_info
, sizeof(icon_info
));
1341 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1342 ZeroMemory(&bm
, sizeof(bm
));
1343 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1344 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1345 bm
.bmWidth
, bm
.bmHeight
);
1346 DeleteObject(icon_info
.hbmColor
);
1347 DeleteObject(icon_info
.hbmMask
);
1348 DestroyWindow(hwnd
);
1350 /* Set icon without BS_ICON */
1351 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
, 0, 0, 100, 100, 0, 0, 0, 0);
1352 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1353 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1354 ok(hicon
== 0, "Expect hicon == 0\n");
1355 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1356 ok(hicon
!= 0, "Expect hicon != 0\n");
1357 ZeroMemory(&icon_info
, sizeof(icon_info
));
1358 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1359 ZeroMemory(&bm
, sizeof(bm
));
1360 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1361 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1362 bm
.bmWidth
, bm
.bmHeight
);
1363 DeleteObject(icon_info
.hbmColor
);
1364 DeleteObject(icon_info
.hbmMask
);
1365 DestroyWindow(hwnd
);
1367 /* Set icon with BS_BITMAP */
1368 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1370 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1371 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hicon2x2
);
1372 ok(hicon
== 0, "Expect hicon == 0\n");
1373 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1374 ok(hicon
!= 0, "Expect hicon != 0\n");
1375 ZeroMemory(&icon_info
, sizeof(icon_info
));
1376 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1377 ZeroMemory(&bm
, sizeof(bm
));
1378 ok(GetObjectW(icon_info
.hbmColor
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1379 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1380 bm
.bmWidth
, bm
.bmHeight
);
1381 DeleteObject(icon_info
.hbmColor
);
1382 DeleteObject(icon_info
.hbmMask
);
1383 DestroyWindow(hwnd
);
1385 /* Set bitmap with BS_ICON */
1386 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1388 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1389 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp1x1
);
1390 ok(hbmp
== 0, "Expect hbmp == 0\n");
1391 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1392 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1393 ZeroMemory(&bm
, sizeof(bm
));
1394 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1395 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1396 bm
.bmWidth
, bm
.bmHeight
);
1397 DestroyWindow(hwnd
);
1399 /* Set bitmap with BS_BITMAP and IMAGE_ICON*/
1400 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0,
1402 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1403 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1404 ok(hbmp
== 0, "Expect hbmp == 0\n");
1405 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1406 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1407 ZeroMemory(&bm
, sizeof(bm
));
1408 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1409 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1410 bm
.bmWidth
, bm
.bmHeight
);
1411 DestroyWindow(hwnd
);
1413 /* Set icon with BS_ICON and IMAGE_BITMAP */
1414 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0,
1416 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1417 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1418 ok(hicon
== 0, "Expect hicon == 0\n");
1419 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1420 ok(hicon
!= 0, "Expect hicon != 0\n");
1421 ZeroMemory(&icon_info
, sizeof(icon_info
));
1422 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1423 ZeroMemory(&bm
, sizeof(bm
));
1424 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1425 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1426 bm
.bmWidth
, bm
.bmHeight
);
1427 DeleteObject(icon_info
.hbmColor
);
1428 DeleteObject(icon_info
.hbmMask
);
1429 DestroyWindow(hwnd
);
1431 /* Set bitmap with BS_ICON and IMAGE_ICON */
1432 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_ICON
, 0, 0, 100, 100, 0, 0, 0, 0);
1433 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1434 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_ICON
, (LPARAM
)hbmp1x1
);
1435 ok(hbmp
== 0, "Expect hbmp == 0\n");
1436 hbmp
= (HBITMAP
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_ICON
, 0);
1437 ok(hbmp
!= 0, "Expect hbmp != 0\n");
1438 ZeroMemory(&bm
, sizeof(bm
));
1439 ok(GetObjectW(hbmp
, sizeof(bm
), &bm
), "Expect GetObjectW() success\n");
1440 ok(bm
.bmWidth
== 1 && bm
.bmHeight
== 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
1441 bm
.bmWidth
, bm
.bmHeight
);
1442 DestroyWindow(hwnd
);
1444 /* Set icon with BS_BITMAP and IMAGE_BITMAP */
1445 hwnd
= CreateWindowA(WC_BUTTONA
, "test", default_style
| BS_BITMAP
, 0, 0, 100, 100, 0, 0, 0, 0);
1446 ok(hwnd
!= NULL
, "Expect hwnd to be not NULL\n");
1447 hicon
= (HICON
)SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hicon2x2
);
1448 ok(hicon
== 0, "Expect hicon == 0\n");
1449 hicon
= (HICON
)SendMessageA(hwnd
, BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1450 ok(hicon
!= 0, "Expect hicon != 0\n");
1451 ZeroMemory(&icon_info
, sizeof(icon_info
));
1452 ok(GetIconInfo(hicon
, &icon_info
), "Expect GetIconInfo() success\n");
1453 ZeroMemory(&bm
, sizeof(bm
));
1454 ok(GetObjectW(icon_info
.hbmColor
, sizeof(BITMAP
), &bm
), "Expect GetObjectW() success\n");
1455 ok(bm
.bmWidth
== 2 && bm
.bmHeight
== 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
1456 bm
.bmWidth
, bm
.bmHeight
);
1457 DeleteObject(icon_info
.hbmColor
);
1458 DeleteObject(icon_info
.hbmMask
);
1459 DestroyWindow(hwnd
);
1462 DestroyIcon(hicon2x2
);
1463 DeleteObject(hmask2x2
);
1464 DeleteObject(hbmp2x2
);
1465 DeleteObject(hbmp1x1
);
1469 static void register_parent_class(void)
1474 cls
.lpfnWndProc
= test_parent_wndproc
;
1477 cls
.hInstance
= GetModuleHandleA(0);
1479 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1480 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
1481 cls
.lpszMenuName
= NULL
;
1482 cls
.lpszClassName
= "TestParentClass";
1483 RegisterClassA(&cls
);
1486 static void test_bcm_splitinfo(HWND hwnd
)
1488 UINT button
= GetWindowLongA(hwnd
, GWL_STYLE
) & BS_TYPEMASK
;
1489 int glyph_size
= GetSystemMetrics(SM_CYMENUCHECK
);
1490 int border_w
= GetSystemMetrics(SM_CXEDGE
) * 2;
1491 BUTTON_SPLITINFO info
, dummy
;
1495 memset(&info
, 0xCC, sizeof(info
));
1497 memcpy(&dummy
, &info
, sizeof(info
));
1499 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1504 win_skip("BCM_GETSPLITINFO message is unavailable. Skipping related tests\n"); /* Pre-Vista */
1508 ok(!memcmp(&info
, &dummy
, sizeof(info
)), "[%u] split info struct was changed with mask = 0\n", button
);
1510 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, 0);
1511 ok(ret
== FALSE
, "[%u] expected FALSE, got %d\n", button
, ret
);
1512 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, 0);
1513 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1515 info
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
| BCSIF_STYLE
;
1516 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1517 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1518 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
| BCSIF_STYLE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1519 ok(info
.himlGlyph
== (HIMAGELIST
)0x36, "[%u] expected 0x36 default glyph, got 0x%p\n", button
, info
.himlGlyph
);
1520 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x default style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1521 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d default size.cx, got %d\n", button
, glyph_size
, info
.size
.cx
);
1522 ok(info
.size
.cy
== 0, "[%u] expected 0 default size.cy, got %d\n", button
, info
.size
.cy
);
1524 info
.mask
= BCSIF_SIZE
;
1525 info
.size
.cx
= glyph_size
+ 7;
1527 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1528 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1529 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1530 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1531 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1532 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1533 ok(info
.size
.cx
== glyph_size
+ 7, "[%u] expected %d, got %d\n", button
, glyph_size
+ 7, info
.size
.cx
);
1534 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1536 /* Invalid size.cx resets it to default glyph size, while size.cy is stored */
1539 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1540 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1541 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1542 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1543 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1544 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1545 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1546 ok(info
.size
.cy
== -20, "[%u] expected -20, got %d\n", button
, info
.size
.cy
);
1548 info
.size
.cx
= -glyph_size
- 7;
1550 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1551 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1552 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1553 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1554 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1555 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1556 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1557 ok(info
.size
.cy
== -10, "[%u] expected -10, got %d\n", button
, info
.size
.cy
);
1559 /* Set to a valid size other than glyph_size */
1560 info
.mask
= BCSIF_SIZE
;
1561 info
.size
.cx
= glyph_size
+ 7;
1563 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1564 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1565 info
.size
.cx
= info
.size
.cy
= 0xdeadbeef;
1566 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1567 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1568 ok(info
.mask
== BCSIF_SIZE
, "[%u] wrong mask, got %u\n", button
, info
.mask
);
1569 ok(info
.size
.cx
== glyph_size
+ 7, "[%u] expected %d, got %d\n", button
, glyph_size
+ 7, info
.size
.cx
);
1570 ok(info
.size
.cy
== 11, "[%u] expected 11, got %d\n", button
, info
.size
.cy
);
1572 /* Change the glyph, size.cx should be automatically adjusted and size.cy set to 0 */
1573 dummy
.mask
= BCSIF_GLYPH
;
1574 dummy
.himlGlyph
= (HIMAGELIST
)0x35;
1575 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1576 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1577 info
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
;
1578 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1579 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1580 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1581 ok(info
.himlGlyph
== (HIMAGELIST
)0x35, "[%u] expected 0x35, got %p\n", button
, info
.himlGlyph
);
1582 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1583 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1585 /* Unless the size is specified manually */
1586 dummy
.mask
= BCSIF_GLYPH
| BCSIF_SIZE
;
1587 dummy
.himlGlyph
= (HIMAGELIST
)0x34;
1588 dummy
.size
.cx
= glyph_size
+ 11;
1590 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1591 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1592 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1593 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1594 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1595 ok(info
.himlGlyph
== (HIMAGELIST
)0x34, "[%u] expected 0x34, got %p\n", button
, info
.himlGlyph
);
1596 ok(info
.size
.cx
== glyph_size
+ 11, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1597 ok(info
.size
.cy
== 7, "[%u] expected 7, got %d\n", button
, info
.size
.cy
);
1599 /* Add the BCSS_IMAGE style manually with the wrong BCSIF_GLYPH mask, should treat it as invalid image */
1600 info
.mask
= BCSIF_GLYPH
| BCSIF_STYLE
;
1601 info
.himlGlyph
= (HIMAGELIST
)0x37;
1602 info
.uSplitStyle
= BCSS_IMAGE
;
1603 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1604 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1605 info
.mask
|= BCSIF_SIZE
;
1606 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1607 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1608 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1609 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1610 ok(info
.uSplitStyle
== BCSS_IMAGE
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
, info
.uSplitStyle
);
1611 ok(info
.size
.cx
== border_w
, "[%u] expected %d, got %d\n", button
, border_w
, info
.size
.cx
);
1612 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1614 /* Change the size to prevent ambiguity */
1615 dummy
.mask
= BCSIF_SIZE
;
1616 dummy
.size
.cx
= glyph_size
+ 5;
1618 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1619 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1620 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1621 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1622 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1623 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1624 ok(info
.uSplitStyle
== BCSS_IMAGE
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
, info
.uSplitStyle
);
1625 ok(info
.size
.cx
== glyph_size
+ 5, "[%u] expected %d, got %d\n", button
, glyph_size
+ 5, info
.size
.cx
);
1626 ok(info
.size
.cy
== 4, "[%u] expected 4, got %d\n", button
, info
.size
.cy
);
1628 /* Now remove the BCSS_IMAGE style manually with the wrong BCSIF_IMAGE mask */
1629 info
.mask
= BCSIF_IMAGE
| BCSIF_STYLE
;
1630 info
.himlGlyph
= (HIMAGELIST
)0x35;
1631 info
.uSplitStyle
= BCSS_STRETCH
;
1632 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1633 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1634 info
.mask
|= BCSIF_SIZE
;
1635 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1636 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1637 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1638 ok(info
.himlGlyph
== (HIMAGELIST
)0x35, "[%u] expected 0x35, got %p\n", button
, info
.himlGlyph
);
1639 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1640 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1641 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1643 /* Add a proper valid image, the BCSS_IMAGE style should be set automatically */
1644 img
= pImageList_Create(42, 33, ILC_COLOR
, 1, 1);
1645 ok(img
!= NULL
, "[%u] failed to create ImageList\n", button
);
1646 info
.mask
= BCSIF_IMAGE
;
1647 info
.himlGlyph
= img
;
1648 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1649 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1650 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1651 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1652 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1653 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1654 ok(info
.himlGlyph
== img
, "[%u] expected %p, got %p\n", button
, img
, info
.himlGlyph
);
1655 ok(info
.uSplitStyle
== (BCSS_IMAGE
| BCSS_STRETCH
), "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
| BCSS_STRETCH
, info
.uSplitStyle
);
1656 ok(info
.size
.cx
== 42 + border_w
, "[%u] expected %d, got %d\n", button
, 42 + border_w
, info
.size
.cx
);
1657 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1658 pImageList_Destroy(img
);
1659 dummy
.mask
= BCSIF_SIZE
;
1660 dummy
.size
.cx
= glyph_size
+ 5;
1662 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&dummy
);
1663 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1665 /* Change it to a glyph; when both specified, BCSIF_GLYPH takes priority */
1666 info
.mask
= BCSIF_GLYPH
| BCSIF_IMAGE
;
1667 info
.himlGlyph
= (HIMAGELIST
)0x37;
1668 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1669 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1670 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1671 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1672 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1673 ok(info
.mask
== (BCSIF_GLYPH
| BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1674 ok(info
.himlGlyph
== (HIMAGELIST
)0x37, "[%u] expected 0x37, got %p\n", button
, info
.himlGlyph
);
1675 ok(info
.uSplitStyle
== BCSS_STRETCH
, "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_STRETCH
, info
.uSplitStyle
);
1676 ok(info
.size
.cx
== glyph_size
, "[%u] expected %d, got %d\n", button
, glyph_size
, info
.size
.cx
);
1677 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1679 /* Try a NULL image */
1680 info
.mask
= BCSIF_IMAGE
;
1681 info
.himlGlyph
= NULL
;
1682 ret
= SendMessageA(hwnd
, BCM_SETSPLITINFO
, 0, (LPARAM
)&info
);
1683 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1684 info
.mask
|= BCSIF_STYLE
| BCSIF_SIZE
;
1685 ret
= SendMessageA(hwnd
, BCM_GETSPLITINFO
, 0, (LPARAM
)&info
);
1686 ok(ret
== TRUE
, "[%u] expected TRUE, got %d\n", button
, ret
);
1687 ok(info
.mask
== (BCSIF_IMAGE
| BCSIF_STYLE
| BCSIF_SIZE
), "[%u] wrong mask, got %u\n", button
, info
.mask
);
1688 ok(info
.himlGlyph
== NULL
, "[%u] expected NULL, got %p\n", button
, info
.himlGlyph
);
1689 ok(info
.uSplitStyle
== (BCSS_IMAGE
| BCSS_STRETCH
), "[%u] expected 0x%08x style, got 0x%08x\n", button
, BCSS_IMAGE
| BCSS_STRETCH
, info
.uSplitStyle
);
1690 ok(info
.size
.cx
== border_w
, "[%u] expected %d, got %d\n", button
, border_w
, info
.size
.cx
);
1691 ok(info
.size
.cy
== 0, "[%u] expected 0, got %d\n", button
, info
.size
.cy
);
1694 static void test_button_data(void)
1696 static const DWORD styles
[] =
1724 parent
= CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1725 100, 100, 200, 200, 0, 0, 0, NULL
);
1726 ok(parent
!= 0, "Failed to create parent window\n");
1728 for (i
= 0; i
< ARRAY_SIZE(styles
); i
++)
1730 struct button_desc
*desc
;
1733 hwnd
= create_button(styles
[i
], parent
);
1734 ok(hwnd
!= NULL
, "Failed to create a button.\n");
1736 desc
= (void *)GetWindowLongPtrA(hwnd
, 0);
1737 ok(desc
!= NULL
, "Expected window data.\n");
1741 ok(desc
->self
== hwnd
, "Unexpected 'self' field.\n");
1742 ok(desc
->parent
== parent
, "Unexpected 'parent' field.\n");
1743 ok(desc
->style
== (WS_CHILD
| BS_NOTIFY
| styles
[i
]), "Unexpected 'style' field.\n");
1746 /* Data set and retrieved by these messages is valid for all buttons */
1747 test_bcm_splitinfo(hwnd
);
1749 DestroyWindow(hwnd
);
1752 DestroyWindow(parent
);
1755 static void test_get_set_imagelist(void)
1759 BUTTON_IMAGELIST biml
= {0};
1769 hbmp
= CreateCompatibleBitmap(hdc
, width
, height
);
1770 ok(hbmp
!= NULL
, "Expect hbmp not null\n");
1772 himl
= pImageList_Create(width
, height
, ILC_COLOR
, 1, 0);
1773 ok(himl
!= NULL
, "Expect himl not null\n");
1774 index
= pImageList_Add(himl
, hbmp
, NULL
);
1775 ok(index
== 0, "Expect index == 0\n");
1779 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1781 hwnd
= create_button(type
, NULL
);
1782 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1784 /* Get imagelist when imagelist is unset yet */
1785 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1786 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1787 ok(biml
.himl
== 0 && IsRectEmpty(&biml
.margin
) && biml
.uAlign
== 0,
1788 "Expect BUTTON_IMAGELIST is empty\n");
1790 /* Set imagelist with himl null */
1792 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1793 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1794 ok(ret
|| broken(!ret
), /* xp or 2003 */
1795 "Expect BCM_SETIMAGELIST return true\n");
1797 /* Set imagelist with uAlign invalid */
1800 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1801 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1803 /* Successful get and set imagelist */
1805 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1806 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1807 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1808 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, (LPARAM
)&biml
);
1809 ok(ret
, "Expect BCM_GETIMAGELIST return true\n");
1810 ok(biml
.himl
== himl
, "Expect himl to be same\n");
1811 ok(biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_CENTER
, "Expect uAlign to be %x\n",
1812 BUTTON_IMAGELIST_ALIGN_CENTER
);
1814 /* BCM_SETIMAGELIST null pointer handling */
1815 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, 0);
1816 ok(!ret
, "Expect BCM_SETIMAGELIST return false\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");
1821 /* BCM_GETIMAGELIST null pointer handling */
1823 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_CENTER
;
1824 ret
= SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
1825 ok(ret
, "Expect BCM_SETIMAGELIST return true\n");
1826 ret
= SendMessageA(hwnd
, BCM_GETIMAGELIST
, 0, 0);
1827 ok(!ret
, "Expect BCM_GETIMAGELIST return false\n");
1829 DestroyWindow(hwnd
);
1832 pImageList_Destroy(himl
);
1835 static void test_get_set_textmargin(void)
1843 SetRect(&margin_in
, 2, 1, 3, 4);
1844 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1846 hwnd
= create_button(type
, NULL
);
1847 ok(hwnd
!= NULL
, "Expect hwnd not null\n");
1849 /* Get text margin when it is unset */
1850 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1851 ok(ret
, "Expect ret to be true\n");
1852 ok(IsRectEmpty(&margin_out
), "Expect margin empty\n");
1854 /* Successful get and set text margin */
1855 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1856 ok(ret
, "Expect ret to be true\n");
1857 SetRectEmpty(&margin_out
);
1858 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1859 ok(ret
, "Expect ret to be true\n");
1860 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1862 /* BCM_SETTEXTMARGIN null pointer handling */
1863 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, 0);
1864 ok(!ret
, "Expect ret to be false\n");
1865 SetRectEmpty(&margin_out
);
1866 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, (LPARAM
)&margin_out
);
1867 ok(ret
, "Expect ret to be true\n");
1868 ok(EqualRect(&margin_in
, &margin_out
), "Expect margins to be equal\n");
1870 /* BCM_GETTEXTMARGIN null pointer handling */
1871 ret
= SendMessageA(hwnd
, BCM_SETTEXTMARGIN
, 0, (LPARAM
)&margin_in
);
1872 ok(ret
, "Expect ret to be true\n");
1873 ret
= SendMessageA(hwnd
, BCM_GETTEXTMARGIN
, 0, 0);
1874 ok(!ret
, "Expect ret to be true\n");
1876 DestroyWindow(hwnd
);
1880 static void test_state(void)
1886 /* Initial button state */
1887 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
1889 hwnd
= create_button(type
, NULL
);
1890 state
= SendMessageA(hwnd
, BM_GETSTATE
, 0, 0);
1891 ok(state
== BST_UNCHECKED
, "Expect state 0x%08x, got 0x%08x\n", BST_UNCHECKED
, state
);
1892 DestroyWindow(hwnd
);
1896 static void test_bcm_get_ideal_size(void)
1898 static const char *button_text2
= "WWWW\nWWWW";
1899 static const char *button_text
= "WWWW";
1900 static const WCHAR button_note_short
[] = { 'W',0 };
1901 static const WCHAR button_note_long
[] = { 'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W',0 };
1902 static const WCHAR button_note_wordy
[] = { 'T','h','i','s',' ','i','s',' ','a',' ','l','o','n','g',' ','n','o','t','e',' ','f','o','r',' ','t','h','e',' ','b','u','t','t','o','n',',',' ',
1903 'w','i','t','h',' ','m','a','n','y',' ','w','o','r','d','s',',',' ','w','h','i','c','h',' ','s','h','o','u','l','d',' ','b','e',' ',
1904 'o','v','e','r','a','l','l',' ','l','o','n','g','e','r',' ','t','h','a','n',' ','t','h','e',' ','t','e','x','t',' ','(','g','i','v','e','n',' ',
1905 't','h','e',' ','s','m','a','l','l','e','r',' ','f','o','n','t',')',' ','a','n','d',' ','t','h','u','s',' ','w','r','a','p','.',0 };
1906 static const DWORD imagelist_aligns
[] = {BUTTON_IMAGELIST_ALIGN_LEFT
, BUTTON_IMAGELIST_ALIGN_RIGHT
,
1907 BUTTON_IMAGELIST_ALIGN_TOP
, BUTTON_IMAGELIST_ALIGN_BOTTOM
,
1908 BUTTON_IMAGELIST_ALIGN_CENTER
};
1909 static const DWORD aligns
[] = {0, BS_TOP
, BS_LEFT
, BS_RIGHT
, BS_BOTTOM
,
1910 BS_CENTER
, BS_VCENTER
, BS_RIGHTBUTTON
, WS_EX_RIGHT
};
1911 DWORD default_style
= WS_TABSTOP
| WS_POPUP
| WS_VISIBLE
;
1912 const LONG client_width
= 400, client_height
= 200, extra_width
= 123, large_height
= 500;
1919 { BS_PUSHBUTTON
, 0 },
1920 { BS_DEFPUSHBUTTON
, 0 },
1921 { BS_SPLITBUTTON
, extra_width
* 2 + GetSystemMetrics(SM_CXEDGE
) },
1922 { BS_DEFSPLITBUTTON
, extra_width
* 2 + GetSystemMetrics(SM_CXEDGE
) }
1924 LONG image_width
= 48, height
= 48, line_count
, text_width
;
1925 HFONT hfont
, prev_font
;
1933 HBITMAP hmask
, hbmp
;
1937 BUTTON_IMAGELIST biml
= {0};
1941 /* Check for NULL pointer handling */
1942 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_PUSHBUTTON
| default_style
, 0, 0, client_width
, client_height
,
1943 NULL
, NULL
, 0, NULL
);
1944 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, 0);
1945 ok(!ret
, "Expect BCM_GETIDEALSIZE message to return false.\n");
1947 /* Set font so that the test is consistent on Wine and Windows */
1948 ZeroMemory(&lf
, sizeof(lf
));
1949 lf
.lfWeight
= FW_NORMAL
;
1951 lstrcpyA(lf
.lfFaceName
, "Tahoma");
1952 hfont
= CreateFontIndirectA(&lf
);
1953 ok(hfont
!= NULL
, "Failed to create test font.\n");
1957 prev_font
= SelectObject(hdc
, hfont
);
1958 GetTextMetricsA(hdc
, &tm
);
1959 SelectObject(hdc
, prev_font
);
1960 DrawTextA(hdc
, button_text
, -1, &rect
, DT_CALCRECT
);
1961 text_width
= rect
.right
- rect
.left
;
1962 ReleaseDC(hwnd
, hdc
);
1963 DestroyWindow(hwnd
);
1965 /* XP and 2003 doesn't support command links, getting ideal size with button having only text returns client size on these platforms. */
1966 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_DEFCOMMANDLINK
| default_style
, 0, 0, client_width
, client_height
, NULL
,
1968 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
1969 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
1970 ZeroMemory(&size
, sizeof(size
));
1971 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
1972 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
1973 if (size
.cx
== client_width
&& size
.cy
== client_height
)
1975 /* on XP and 2003, buttons with image are not supported */
1976 win_skip("Skipping further tests on XP and 2003\n");
1980 /* Tests for image placements */
1981 /* Prepare bitmap */
1983 hmask
= CreateCompatibleBitmap(hdc
, image_width
, height
);
1984 hbmp
= CreateCompatibleBitmap(hdc
, image_width
, height
);
1985 himl
= pImageList_Create(image_width
, height
, ILC_COLOR
, 1, 1);
1986 pImageList_Add(himl
, hbmp
, 0);
1988 #define set_split_info(hwnd) do { \
1989 BUTTON_SPLITINFO _info; \
1991 _info.mask = BCSIF_SIZE; \
1992 _info.size.cx = extra_width; \
1993 _info.size.cy = large_height; \
1994 _ret = SendMessageA(hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&_info); \
1995 ok(_ret == TRUE, "Expected BCM_SETSPLITINFO message to return true\n"); \
1998 for (k
= 0; k
< ARRAY_SIZE(pushtype
); k
++)
2000 /* Only bitmap for push button, ideal size should be enough for image and text */
2001 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2002 client_height
, NULL
, NULL
, 0, NULL
);
2003 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2004 set_split_info(hwnd
);
2005 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2006 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2007 ZeroMemory(&size
, sizeof(size
));
2008 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2009 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2010 /* Ideal size contains text rect even show bitmap only */
2011 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2012 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2013 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2014 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2015 DestroyWindow(hwnd
);
2017 /* Image alignments when button has bitmap and text*/
2018 for (i
= 0; i
< ARRAY_SIZE(aligns
); i
++)
2019 for (j
= 0; j
< ARRAY_SIZE(aligns
); j
++)
2021 style
= pushtype
[k
].style
| default_style
| aligns
[i
] | aligns
[j
];
2022 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2023 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2024 set_split_info(hwnd
);
2025 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2026 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2027 ZeroMemory(&size
, sizeof(size
));
2028 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2029 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2030 if (!(style
& (BS_CENTER
| BS_VCENTER
)) || ((style
& BS_CENTER
) && (style
& BS_CENTER
) != BS_CENTER
)
2031 || !(style
& BS_VCENTER
) || (style
& BS_VCENTER
) == BS_VCENTER
)
2032 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2033 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
2034 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2036 ok(size
.cx
>= max(text_width
, height
) + pushtype
[k
].extra_width
&& size
.cy
>= height
+ tm
.tmHeight
,
2037 "Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style
, size
.cx
,
2038 max(text_width
, height
) + pushtype
[k
].extra_width
, size
.cy
, height
+ tm
.tmHeight
);
2039 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2040 DestroyWindow(hwnd
);
2043 /* Image list alignments */
2045 for (i
= 0; i
< ARRAY_SIZE(imagelist_aligns
); i
++)
2047 biml
.uAlign
= imagelist_aligns
[i
];
2048 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| default_style
, 0, 0, client_width
,
2049 client_height
, NULL
, NULL
, 0, NULL
);
2050 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2051 set_split_info(hwnd
);
2052 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2053 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
2054 ZeroMemory(&size
, sizeof(size
));
2055 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2056 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2057 if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_TOP
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_BOTTOM
)
2058 ok(size
.cx
>= max(text_width
, height
) + pushtype
[k
].extra_width
&& size
.cy
>= height
+ tm
.tmHeight
,
2059 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
2060 max(text_width
, height
) + pushtype
[k
].extra_width
, size
.cy
, height
+ tm
.tmHeight
);
2061 else if (biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_LEFT
|| biml
.uAlign
== BUTTON_IMAGELIST_ALIGN_RIGHT
)
2062 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2063 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml
.uAlign
, size
.cx
,
2064 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2066 ok(size
.cx
>= image_width
+ pushtype
[k
].extra_width
&& size
.cy
>= height
,
2067 "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
2068 biml
.uAlign
, size
.cx
, image_width
+ pushtype
[k
].extra_width
, size
.cy
, height
);
2069 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2070 DestroyWindow(hwnd
);
2074 /* Create icon from bitmap */
2075 ZeroMemory(&icon_info
, sizeof(icon_info
));
2076 icon_info
.fIcon
= TRUE
;
2077 icon_info
.hbmMask
= hmask
;
2078 icon_info
.hbmColor
= hbmp
;
2079 hicon
= CreateIconIndirect(&icon_info
);
2081 /* Only icon, ideal size should be enough for image and text */
2082 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| BS_ICON
| default_style
, 0, 0, client_width
,
2083 client_height
, NULL
, NULL
, 0, NULL
);
2084 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2085 set_split_info(hwnd
);
2086 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
2087 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2088 ZeroMemory(&size
, sizeof(size
));
2089 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2090 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2091 /* Ideal size contains text rect even show icons only */
2092 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2093 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2094 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2095 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2096 DestroyWindow(hwnd
);
2098 /* Show icon and text */
2099 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, pushtype
[k
].style
| default_style
, 0, 0, client_width
,
2100 client_height
, NULL
, NULL
, 0, NULL
);
2101 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2102 set_split_info(hwnd
);
2103 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hicon
);
2104 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2105 ZeroMemory(&size
, sizeof(size
));
2106 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2107 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2108 ok(size
.cx
>= image_width
+ text_width
+ pushtype
[k
].extra_width
&& size
.cy
>= max(height
, tm
.tmHeight
),
2109 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
,
2110 image_width
+ text_width
+ pushtype
[k
].extra_width
, size
.cy
, max(height
, tm
.tmHeight
));
2111 ok(size
.cy
< large_height
, "Expect ideal cy %d < %d\n", size
.cy
, large_height
);
2112 DestroyWindow(hwnd
);
2116 #undef set_split_info
2119 /* Both bitmap and text for checkbox, ideal size is only enough for text because it doesn't support image(but not image list)*/
2120 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| default_style
, 0, 0, client_width
, client_height
,
2121 NULL
, NULL
, 0, NULL
);
2122 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2123 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2124 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2125 ZeroMemory(&size
, sizeof(size
));
2126 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2127 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2128 ok((size
.cx
<= image_width
+ text_width
&& size
.cx
>= text_width
&& size
.cy
<= max(height
, tm
.tmHeight
)
2129 && size
.cy
>= tm
.tmHeight
),
2130 "Expect ideal cx %d within range (%d, %d ) and ideal cy %d within range (%d, %d )\n", size
.cx
,
2131 text_width
, image_width
+ text_width
, size
.cy
, tm
.tmHeight
, max(height
, tm
.tmHeight
));
2132 DestroyWindow(hwnd
);
2134 /* Both image list and text for checkbox, ideal size should have enough for image list and text */
2135 biml
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
2136 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2137 client_height
, NULL
, NULL
, 0, NULL
);
2138 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2139 SendMessageA(hwnd
, BCM_SETIMAGELIST
, 0, (LPARAM
)&biml
);
2140 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2141 ZeroMemory(&size
, sizeof(size
));
2142 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2143 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2144 ok((size
.cx
>= image_width
+ text_width
&& size
.cy
>= max(height
, tm
.tmHeight
)),
2145 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, image_width
+ text_width
, size
.cy
,
2146 max(height
, tm
.tmHeight
));
2147 DestroyWindow(hwnd
);
2149 /* Only bitmap for checkbox, ideal size should have enough for image and text */
2150 hwnd
= CreateWindowA(WC_BUTTONA
, button_text
, BS_AUTOCHECKBOX
| BS_BITMAP
| default_style
, 0, 0, client_width
,
2151 client_height
, NULL
, NULL
, 0, NULL
);
2152 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2153 SendMessageA(hwnd
, BM_SETIMAGE
, (WPARAM
)IMAGE_BITMAP
, (LPARAM
)hbmp
);
2154 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2155 ZeroMemory(&size
, sizeof(size
));
2156 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2157 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2158 ok((size
.cx
>= image_width
+ text_width
&& size
.cy
>= max(height
, tm
.tmHeight
)),
2159 "Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size
.cx
, image_width
+ text_width
, size
.cy
,
2160 max(height
, tm
.tmHeight
));
2161 DestroyWindow(hwnd
);
2163 /* Test button with only text */
2165 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
2167 style
= type
| default_style
;
2168 hwnd
= CreateWindowA(WC_BUTTONA
, "", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2169 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2170 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2172 ZeroMemory(&size
, sizeof(size
));
2173 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2174 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2176 if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
2178 ok((size
.cx
== 0 && size
.cy
> 0), "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n",
2179 style
, size
.cx
, 0, size
.cy
, 0);
2183 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
2184 "Style 0x%08x expect size.cx == %d and size.cy == %d, got size.cx: %d size.cy: %d\n", style
,
2185 client_width
, client_height
, size
.cx
, size
.cy
);
2187 DestroyWindow(hwnd
);
2190 /* Single line and multiple lines text */
2191 for (line_count
= 1; line_count
<= 2; line_count
++)
2193 for (type
= BS_PUSHBUTTON
; type
<= BS_DEFCOMMANDLINK
; type
++)
2195 style
= line_count
> 1 ? type
| BS_MULTILINE
: type
;
2196 style
|= default_style
;
2198 hwnd
= CreateWindowA(WC_BUTTONA
, (line_count
== 2 ? button_text2
: button_text
), style
, 0, 0, client_width
,
2199 client_height
, NULL
, NULL
, 0, NULL
);
2200 ok(hwnd
!= NULL
, "Expect hwnd not NULL\n");
2201 SendMessageA(hwnd
, WM_SETFONT
, (WPARAM
)hfont
, (LPARAM
)TRUE
);
2202 ZeroMemory(&size
, sizeof(size
));
2203 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2204 ok(ret
, "Expect BCM_GETIDEALSIZE message to return true\n");
2206 if (type
== BS_3STATE
|| type
== BS_AUTO3STATE
|| type
== BS_GROUPBOX
|| type
== BS_PUSHBOX
2207 || type
== BS_OWNERDRAW
)
2209 ok(size
.cx
== client_width
&& size
.cy
== client_height
,
2210 "Style 0x%08x expect ideal size (%d,%d), got (%d,%d)\n", style
, client_width
, client_height
, size
.cx
,
2213 else if (type
== BS_COMMANDLINK
|| type
== BS_DEFCOMMANDLINK
)
2215 ok((size
.cx
== 0 && size
.cy
> 0),
2216 "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n", style
, size
.cx
, 0,
2221 height
= line_count
== 2 ? 2 * tm
.tmHeight
: tm
.tmHeight
;
2222 ok(size
.cx
>= 0 && size
.cy
>= height
, "Style 0x%08x expect ideal cx %d >= 0 and ideal cy %d >= %d\n",
2223 style
, size
.cx
, size
.cy
, height
);
2225 DestroyWindow(hwnd
);
2229 /* Command Link with note */
2230 hwnd
= CreateWindowA(WC_BUTTONA
, "a", style
, 0, 0, client_width
, client_height
, NULL
, NULL
, 0, NULL
);
2231 ok(hwnd
!= NULL
, "Expected hwnd not NULL\n");
2232 SendMessageA(hwnd
, BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)hbmp
);
2233 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)button_note_short
);
2234 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2237 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2238 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2239 ok(size
.cx
== 13 && size
.cy
> 0, "Expected ideal cx %d == %d and ideal cy %d > %d\n", size
.cx
, 13, size
.cy
, 0);
2243 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2244 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2245 ok(size
.cx
< 32767, "Expected ideal cx to have been adjusted\n");
2246 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
);
2248 /* Try longer note without word breaks, shouldn't extend height because no word splitting */
2249 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)button_note_long
);
2250 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2253 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2254 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2255 ok(size
.cx
== k
&& size
.cy
== height
, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size
.cx
, k
, size
.cy
, height
);
2257 /* Now let it extend the width */
2260 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2261 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2262 ok(size
.cx
> k
&& size
.cy
== height
, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size
.cx
, k
, size
.cy
, height
);
2264 /* Use a very long note with words and the same width, should extend the height due to word wrap */
2265 ret
= SendMessageA(hwnd
, BCM_SETNOTE
, 0, (LPARAM
)button_note_wordy
);
2266 ok(ret
== TRUE
, "Expected BCM_SETNOTE to return true\n");
2268 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2269 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2270 ok(size
.cx
<= k
&& size
.cy
> height
, "Expected ideal cx %d <= %d and ideal cy %d > %d\n", size
.cx
, k
, size
.cy
, height
);
2272 /* Now try the wordy note with a width smaller than the image itself, which prevents wrapping */
2274 ret
= SendMessageA(hwnd
, BCM_GETIDEALSIZE
, 0, (LPARAM
)&size
);
2275 ok(ret
== TRUE
, "Expected BCM_GETIDEALSIZE message to return true\n");
2276 ok(size
.cx
== 13 && size
.cy
== height
, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size
.cx
, 13, size
.cy
, height
);
2277 DestroyWindow(hwnd
);
2280 pImageList_Destroy(himl
);
2282 DeleteObject(hmask
);
2284 DeleteObject(hfont
);
2289 ULONG_PTR ctx_cookie
;
2292 if (!load_v6_module(&ctx_cookie
, &hCtx
))
2295 register_parent_class();
2298 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2300 test_button_class();
2301 test_button_messages();
2304 test_bm_get_set_image();
2305 test_get_set_imagelist();
2306 test_get_set_textmargin();
2308 test_bcm_get_ideal_size();
2310 unload_v6_module(ctx_cookie
, hCtx
);