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