1 /* Unit tests for toolbar.
2  *
3  * Copyright 2005 Krzysztof Foltman
4  * Copyright 2007 Mikolaj Zalewski
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "commctrl.h"
30 
31 #include "resources.h"
32 
33 #include "wine/test.h"
34 
35 #include "msg.h"
36 
37 #define PARENT_SEQ_INDEX       0
38 #define NUM_MSG_SEQUENCES      1
39 
40 static HWND (WINAPI *pCreateToolbarEx)(HWND, DWORD, UINT, INT, HINSTANCE, UINT_PTR, const TBBUTTON *,
41     INT, INT, INT, INT, INT, UINT);
42 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
43 static INT (WINAPI *pImageList_GetImageCount)(HIMAGELIST);
44 static BOOL (WINAPI *pImageList_GetIconSize)(HIMAGELIST, int *, int *);
45 static HIMAGELIST (WINAPI *pImageList_LoadImageA)(HINSTANCE, LPCSTR, int, int, COLORREF, UINT, UINT);
46 
47 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
48 
49 static HWND hMainWnd;
50 static BOOL g_fBlockHotItemChange;
51 static BOOL g_fReceivedHotItemChange;
52 static BOOL g_fExpectedHotItemOld;
53 static BOOL g_fExpectedHotItemNew;
54 static DWORD g_dwExpectedDispInfoMask;
55 static BOOL g_ResetDispTextPtr;
56 
57 static const struct message ttgetdispinfo_parent_seq[] = {
58     { WM_NOTIFY, sent|id, 0, 0, TBN_GETINFOTIPA },
59     { WM_NOTIFY, sent|id, 0, 0, TTN_GETDISPINFOA },
60     { 0 }
61 };
62 
63 static const struct message save_parent_seq[] = {
64     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, -1 },
65     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 0 },
66     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 1 },
67     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 2 },
68     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 3 },
69     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 4 },
70     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 5 },
71     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 6 },
72     { 0 }
73 };
74 
75 static const struct message restore_parent_seq[] = {
76     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, -1 },
77     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 0 },
78     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 1 },
79     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 2 },
80     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 3 },
81     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 4 },
82     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 5 },
83     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 6 },
84     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 7 },
85     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 8 },
86     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 9 },
87     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 0xa },
88     { WM_NOTIFY, sent|id, 0, 0, TBN_BEGINADJUST },
89     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 0 },
90     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 1 },
91     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 2 },
92     { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 3 },
93     { WM_NOTIFY, sent|id, 0, 0, TBN_ENDADJUST },
94     { 0 }
95 };
96 
97 #define DEFINE_EXPECT(func) \
98     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
99 
100 #define CHECK_EXPECT2(func) \
101     do { \
102         ok(expect_ ##func, "unexpected call " #func "\n"); \
103         called_ ## func = TRUE; \
104     }while(0)
105 
106 #define CHECK_CALLED(func) \
107     do { \
108         ok(called_ ## func, "expected " #func "\n"); \
109         expect_ ## func = called_ ## func = FALSE; \
110     }while(0)
111 
112 #define SET_EXPECT(func) \
113     expect_ ## func = TRUE
114 
115 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
116 
117 #define check_rect(name, val, exp, ...) ok(EqualRect(&val, &exp), \
118     "invalid rect %s - expected %s - (" name ")\n", \
119     wine_dbgstr_rect(&val), wine_dbgstr_rect(&exp), __VA_ARGS__);
120 
121 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
122 
123 #define check_button_size(handle, width, height, ...) {\
124     LRESULT bsize = SendMessageA(handle, TB_GETBUTTONSIZE, 0, 0);\
125     ok(bsize == MAKELONG(width, height), "Unexpected button size - got size (%d, %d), expected (%d, %d)\n", LOWORD(bsize), HIWORD(bsize), width, height);\
126     }
127 
MakeButton(TBBUTTON * p,int idCommand,int fsStyle,int nString)128 static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
129   p->iBitmap = -2;
130   p->idCommand = idCommand;
131   p->fsState = TBSTATE_ENABLED;
132   p->fsStyle = fsStyle;
133   p->iString = nString;
134 }
135 
136 static void *alloced_str;
137 
parent_wnd_notify(LPARAM lParam)138 static LRESULT parent_wnd_notify(LPARAM lParam)
139 {
140     NMHDR *hdr = (NMHDR *)lParam;
141     NMTBHOTITEM *nmhi;
142     NMTBDISPINFOA *nmdisp;
143     switch (hdr->code)
144     {
145         case TBN_HOTITEMCHANGE:
146             nmhi = (NMTBHOTITEM *)lParam;
147             g_fReceivedHotItemChange = TRUE;
148             if (g_fExpectedHotItemOld != g_fExpectedHotItemNew)
149             {
150                 compare(nmhi->idOld, g_fExpectedHotItemOld, "%d");
151                 compare(nmhi->idNew, g_fExpectedHotItemNew, "%d");
152             }
153             if (g_fBlockHotItemChange)
154                 return 1;
155             break;
156 
157         case TBN_GETDISPINFOA:
158             ok(FALSE, "TBN_GETDISPINFOA received\n");
159             break;
160 
161         case TBN_GETINFOTIPA:
162         case TBN_GETINFOTIPW:
163         {
164             NMTBGETINFOTIPA *tbgit = (NMTBGETINFOTIPA*)lParam;
165 
166             if (g_ResetDispTextPtr)
167             {
168                 tbgit->pszText = NULL;
169                 return 0;
170             }
171             break;
172         }
173         case TBN_GETDISPINFOW:
174             nmdisp = (NMTBDISPINFOA *)lParam;
175 
176             compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x");
177             ok(nmdisp->pszText == NULL, "pszText is not NULL\n");
178         break;
179         case TBN_SAVE:
180         {
181             NMTBSAVE *save = (NMTBSAVE *)lParam;
182             if (save->iItem == -1)
183             {
184                 save->cbData = save->cbData * 2 + 11 * sizeof(DWORD);
185                 save->pData = heap_alloc( save->cbData );
186                 save->pData[0] = 0xcafe;
187                 save->pCurrent = save->pData + 1;
188             }
189             else
190             {
191                 save->pCurrent[0] = 0xcafe0000 + save->iItem;
192                 save->pCurrent++;
193             }
194 
195             /* Add on 5 more pseudo buttons. */
196             if (save->iItem == save->cButtons - 1)
197             {
198                 save->pCurrent[0] = 0xffffffff;
199                 save->pCurrent[1] = 0xcafe0007;
200                 save->pCurrent[2] = 0xfffffffe;
201                 save->pCurrent[3] = 0xcafe0008;
202                 save->pCurrent[4] = 0x80000000;
203                 save->pCurrent[5] = 0xcafe0009;
204                 save->pCurrent[6] = 0x7fffffff;
205                 save->pCurrent[7] = 0xcafe000a;
206                 save->pCurrent[8] = 0x100;
207                 save->pCurrent[9] = 0xcafe000b;
208             }
209 
210             /* Return value is ignored */
211             return 1;
212         }
213         case TBN_RESTORE:
214         {
215             NMTBRESTORE *restore = (NMTBRESTORE *)lParam;
216 
217             if (restore->iItem == -1)
218             {
219                 ok( restore->cButtons == 25, "got %d\n", restore->cButtons );
220                 ok( *restore->pCurrent == 0xcafe, "got %08x\n", *restore->pCurrent );
221                 /* Skip the last one */
222                 restore->cButtons = 11;
223                 restore->pCurrent++;
224                 /* BytesPerRecord is ignored */
225                 restore->cbBytesPerRecord = 10;
226             }
227             else
228             {
229                 ok( *restore->pCurrent == 0xcafe0000 + restore->iItem, "got %08x\n", *restore->pCurrent );
230                 if (restore->iItem < 7 || restore->iItem == 10)
231                 {
232                     ok( restore->tbButton.iBitmap == -1, "got %08x\n", restore->tbButton.iBitmap );
233                     if (restore->iItem < 7)
234                         ok( restore->tbButton.idCommand == restore->iItem * 2 + 1, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand );
235                     else
236                         ok( restore->tbButton.idCommand == 0x7fffffff, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand );
237                     ok( restore->tbButton.fsState == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState );
238                     ok( restore->tbButton.fsStyle == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsStyle );
239                 }
240                 else
241                 {
242                     ok( restore->tbButton.iBitmap == 8, "got %08x\n", restore->tbButton.iBitmap );
243                     ok( restore->tbButton.idCommand == 0, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand );
244                     if (restore->iItem == 7)
245                         ok( restore->tbButton.fsState == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState );
246                     else
247                         ok( restore->tbButton.fsState == TBSTATE_HIDDEN, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState );
248                     ok( restore->tbButton.fsStyle == BTNS_SEP, "%d: got %02x\n", restore->iItem, restore->tbButton.fsStyle );
249                 }
250 
251                 ok( restore->tbButton.dwData == 0, "got %08lx\n", restore->tbButton.dwData );
252                 ok( restore->tbButton.iString == 0, "got %08lx\n", restore->tbButton.iString );
253 
254                 restore->tbButton.iBitmap = 0;
255                 restore->tbButton.fsState = TBSTATE_ENABLED;
256                 restore->tbButton.fsStyle = 0;
257                 restore->tbButton.dwData = restore->iItem;
258 
259                 if (restore->iItem == 0)
260                 {
261                     restore->tbButton.iString = (INT_PTR)heap_alloc_zero( 8 );
262                     strcpy( (char *)restore->tbButton.iString, "foo" );
263                 }
264                 else if (restore->iItem == 1)
265                     restore->tbButton.iString = 2;
266                 else
267                     restore->tbButton.iString = -1;
268 
269                 restore->pCurrent++;
270                 /* Altering cButtons after the 1st call makes no difference. */
271                 restore->cButtons--;
272             }
273 
274             /* Returning non-zero from the 1st call aborts the restore,
275                otherwise the return value is ignored. */
276             if (restore->iItem == -1) return 0;
277             return 1;
278         }
279         case TBN_GETBUTTONINFOA:
280         {
281             NMTOOLBARA *tb = (NMTOOLBARA *)lParam;
282             tb->tbButton.iBitmap = 0;
283             tb->tbButton.fsState = 0;
284             tb->tbButton.fsStyle = 0;
285             tb->tbButton.dwData = 0;
286             ok( tb->cchText == 128, "got %d\n", tb->cchText );
287             switch (tb->iItem)
288             {
289             case 0:
290                 tb->tbButton.idCommand = 7;
291                 alloced_str = heap_alloc_zero( 8 );
292                 strcpy( alloced_str, "foo" );
293                 tb->tbButton.iString = (INT_PTR)alloced_str;
294                 return 1;
295             case 1:
296                 tb->tbButton.idCommand = 9;
297                 tb->tbButton.iString = 0;
298                 /* tb->pszText is ignored */
299                 strcpy( tb->pszText, "foo" );
300                 return 1;
301            case 2:
302                 tb->tbButton.idCommand = 11;
303                 tb->tbButton.iString = 3;
304                 return 1;
305             }
306             return 0;
307         }
308     }
309     return 0;
310 }
311 
parent_wnd_proc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)312 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
313 {
314     static LONG defwndproc_counter = 0;
315     struct message msg;
316     LRESULT ret;
317 
318     msg.message = message;
319     msg.flags = sent|wparam|lparam;
320     if (defwndproc_counter) msg.flags |= defwinproc;
321     msg.wParam = wParam;
322     msg.lParam = lParam;
323     if (message == WM_NOTIFY && lParam)
324     {
325         msg.id = ((NMHDR*)lParam)->code;
326         switch (msg.id)
327         {
328         case TBN_SAVE:
329         {
330             NMTBSAVE *save = (NMTBSAVE *)lParam;
331             msg.stage = save->iItem;
332         }
333         break;
334         case TBN_RESTORE:
335         {
336             NMTBRESTORE *restore = (NMTBRESTORE *)lParam;
337             msg.stage = restore->iItem;
338         }
339         break;
340         case TBN_GETBUTTONINFOA:
341         {
342             NMTOOLBARA *tb = (NMTOOLBARA *)lParam;
343             msg.stage = tb->iItem;
344         }
345         break;
346         }
347     }
348 
349     /* log system messages, except for painting */
350     if (message < WM_USER &&
351         message != WM_PAINT &&
352         message != WM_ERASEBKGND &&
353         message != WM_NCPAINT &&
354         message != WM_NCHITTEST &&
355         message != WM_GETTEXT &&
356         message != WM_GETICON &&
357         message != WM_DEVICECHANGE)
358     {
359         add_message(sequences, PARENT_SEQ_INDEX, &msg);
360     }
361 
362     switch (message)
363     {
364         case WM_NOTIFY:
365             return parent_wnd_notify(lParam);
366     }
367 
368     defwndproc_counter++;
369     ret = DefWindowProcA(hWnd, message, wParam, lParam);
370     defwndproc_counter--;
371 
372     return ret;
373 }
374 
basic_test(void)375 static void basic_test(void)
376 {
377     TBBUTTON buttons[9];
378     HWND hToolbar;
379     int i;
380 
381     for (i=0; i<9; i++)
382         MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
383     MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
384     MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
385 
386     hToolbar = pCreateToolbarEx(hMainWnd,
387         WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
388         WS_CHILD | TBSTYLE_LIST,
389         100,
390         0, NULL, 0,
391         buttons, ARRAY_SIZE(buttons),
392         0, 0, 20, 16, sizeof(TBBUTTON));
393     ok(hToolbar != NULL, "Toolbar creation\n");
394     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
395 
396     /* test for exclusion working inside a separator-separated :-) group */
397     SendMessageA(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
398     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
399     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
400 
401     SendMessageA(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
402     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
403     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
404 
405     SendMessageA(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
406     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
407     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
408 
409     /* test for inter-group crosstalk, i.e. two radio groups interfering with each other */
410     SendMessageA(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
411     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
412     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
413     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
414 
415     SendMessageA(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
416     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
417     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
418     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
419 
420     SendMessageA(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
421     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
422     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
423     ok(!SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
424     ok(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
425 
426     /* tests with invalid index */
427     compare(SendMessageA(hToolbar, TB_ISBUTTONCHECKED, 0xdeadbeef, 0), -1L, "%ld");
428     compare(SendMessageA(hToolbar, TB_ISBUTTONPRESSED, 0xdeadbeef, 0), -1L, "%ld");
429     compare(SendMessageA(hToolbar, TB_ISBUTTONENABLED, 0xdeadbeef, 0), -1L, "%ld");
430     compare(SendMessageA(hToolbar, TB_ISBUTTONINDETERMINATE, 0xdeadbeef, 0), -1L, "%ld");
431     compare(SendMessageA(hToolbar, TB_ISBUTTONHIGHLIGHTED, 0xdeadbeef, 0), -1L, "%ld");
432     compare(SendMessageA(hToolbar, TB_ISBUTTONHIDDEN, 0xdeadbeef, 0), -1L, "%ld");
433 
434     DestroyWindow(hToolbar);
435 }
436 
rebuild_toolbar(HWND * hToolbar)437 static void rebuild_toolbar(HWND *hToolbar)
438 {
439     if (*hToolbar)
440         DestroyWindow(*hToolbar);
441     *hToolbar = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
442         hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
443     ok(*hToolbar != NULL, "Toolbar creation problem\n");
444     ok(SendMessageA(*hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
445     ok(SendMessageA(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
446     ok(SendMessageA(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
447 }
448 
rebuild_toolbar_with_buttons(HWND * hToolbar)449 static void rebuild_toolbar_with_buttons(HWND *hToolbar)
450 {
451     TBBUTTON buttons[5];
452     rebuild_toolbar(hToolbar);
453 
454     ZeroMemory(&buttons, sizeof(buttons));
455     buttons[0].idCommand = 1;
456     buttons[0].fsStyle = BTNS_BUTTON;
457     buttons[0].fsState = TBSTATE_ENABLED;
458     buttons[0].iString = -1;
459     buttons[1].idCommand = 3;
460     buttons[1].fsStyle = BTNS_BUTTON;
461     buttons[1].fsState = TBSTATE_ENABLED;
462     buttons[1].iString = -1;
463     buttons[2].idCommand = 5;
464     buttons[2].fsStyle = BTNS_SEP;
465     buttons[2].fsState = TBSTATE_ENABLED;
466     buttons[2].iString = -1;
467     buttons[3].idCommand = 7;
468     buttons[3].fsStyle = BTNS_BUTTON;
469     buttons[3].fsState = TBSTATE_ENABLED;
470     buttons[3].iString = -1;
471     buttons[4].idCommand = 9;
472     buttons[4].fsStyle = BTNS_BUTTON;
473     buttons[4].fsState = 0;  /* disabled */
474     buttons[4].iString = -1;
475     ok(SendMessageA(*hToolbar, TB_ADDBUTTONSA, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONSA failed\n");
476     ok(SendMessageA(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
477 }
478 
add_128x15_bitmap(HWND hToolbar,int nCmds)479 static void add_128x15_bitmap(HWND hToolbar, int nCmds)
480 {
481     TBADDBITMAP bmp128;
482     bmp128.hInst = GetModuleHandleA(NULL);
483     bmp128.nID = IDB_BITMAP_128x15;
484     ok(SendMessageA(hToolbar, TB_ADDBITMAP, nCmds, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
485 }
486 
487 #define CHECK_IMAGELIST(count, dx, dy) { \
488     int cx, cy; \
489     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
490     ok(himl != NULL, "No image list\n"); \
491     if (himl != NULL) {\
492         ok(pImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, pImageList_GetImageCount(himl)); \
493         pImageList_GetIconSize(himl, &cx, &cy); \
494         ok(cx == dx && cy == dy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
495     } \
496 }
497 
test_add_bitmap(void)498 static void test_add_bitmap(void)
499 {
500     TBADDBITMAP stdsmall, std;
501     HWND hToolbar = NULL;
502     TBADDBITMAP bmp128;
503     TBADDBITMAP bmp80;
504     TBADDBITMAP addbmp;
505     HIMAGELIST himl;
506     INT ret, id;
507 
508     /* Test default bitmaps range */
509     for (id = IDB_STD_SMALL_COLOR; id < IDB_HIST_LARGE_COLOR; id++)
510     {
511         HIMAGELIST himl;
512         int cx, cy, count;
513 
514         rebuild_toolbar(&hToolbar);
515 
516         std.hInst = HINST_COMMCTRL;
517         std.nID = id;
518 
519         ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&std);
520         ok(ret == 0, "Got %d\n", ret);
521 
522         himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0);
523         ok(himl != NULL, "Got %p\n", himl);
524 
525         ret = pImageList_GetIconSize(himl, &cx, &cy);
526         ok(ret, "Got %d\n", ret);
527         ok(cx == cy, "Got %d x %d\n", cx, cy);
528 
529         count = pImageList_GetImageCount(himl);
530 
531         /* Image count */
532         switch (id)
533         {
534         case IDB_STD_SMALL_COLOR:
535         case IDB_STD_LARGE_COLOR:
536         case 2:
537         case 3:
538             ok(count == 15, "got count %d\n", count);
539             break;
540         case IDB_VIEW_SMALL_COLOR:
541         case IDB_VIEW_LARGE_COLOR:
542         case 6:
543         case 7:
544             ok(count == 12, "got count %d\n", count);
545             break;
546         case IDB_HIST_SMALL_COLOR:
547         case IDB_HIST_LARGE_COLOR:
548             ok(count == 5, "got count %d\n", count);
549             break;
550         default:
551             ok(0, "id %d, count %d\n", id, count);
552         }
553 
554         /* Image sizes */
555         switch (id)
556         {
557         case IDB_STD_SMALL_COLOR:
558         case 2:
559         case IDB_VIEW_SMALL_COLOR:
560         case 6:
561         case IDB_HIST_SMALL_COLOR:
562             ok(cx == 16, "got size %d\n", cx);
563             break;
564         case IDB_STD_LARGE_COLOR:
565         case 3:
566         case IDB_VIEW_LARGE_COLOR:
567         case 7:
568         case IDB_HIST_LARGE_COLOR:
569             ok(cx == 24, "got size %d\n", cx);
570             break;
571         default:
572             ok(0, "id %d, size %d\n", id, cx);
573         }
574     }
575 
576     /* empty 128x15 bitmap */
577     bmp128.hInst = GetModuleHandleA(NULL);
578     bmp128.nID = IDB_BITMAP_128x15;
579 
580     /* empty 80x15 bitmap */
581     bmp80.hInst = GetModuleHandleA(NULL);
582     bmp80.nID = IDB_BITMAP_80x15;
583 
584     /* standard bitmap - 240x15 pixels */
585     stdsmall.hInst = HINST_COMMCTRL;
586     stdsmall.nID = IDB_STD_SMALL_COLOR;
587 
588     rebuild_toolbar(&hToolbar);
589     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
590     CHECK_IMAGELIST(8, 16, 16);
591 
592     /* adding more bitmaps */
593     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n");
594     CHECK_IMAGELIST(13, 16, 16);
595     /* adding the same bitmap will simply return the index of the already loaded block */
596     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128);
597     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
598     CHECK_IMAGELIST(13, 16, 16);
599     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
600     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
601     CHECK_IMAGELIST(13, 16, 16);
602     /* even if we increase the wParam */
603     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80);
604     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
605     CHECK_IMAGELIST(13, 16, 16);
606 
607     /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/
608     rebuild_toolbar(&hToolbar);
609     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
610     CHECK_IMAGELIST(8, 16, 16);
611     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
612     ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret);
613     /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */
614     CHECK_IMAGELIST(13, 16, 16);
615 
616     /* the same for negative wParam */
617     rebuild_toolbar(&hToolbar);
618     ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128);
619     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
620     CHECK_IMAGELIST(8, 16, 16);
621     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
622     ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret);
623     CHECK_IMAGELIST(13, 16, 16);
624 
625     /* for zero only one bitmap will be added */
626     rebuild_toolbar(&hToolbar);
627     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80);
628     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
629     CHECK_IMAGELIST(1, 16, 16);
630 
631     /* if wParam is larger than the amount of icons, the list is grown */
632     rebuild_toolbar(&hToolbar);
633     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
634     CHECK_IMAGELIST(100, 16, 16);
635     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128);
636     ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret);
637     CHECK_IMAGELIST(200, 16, 16);
638 
639     /* adding built-in items - the wParam is ignored */
640     rebuild_toolbar(&hToolbar);
641     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
642     CHECK_IMAGELIST(5, 16, 16);
643     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n");
644     CHECK_IMAGELIST(20, 16, 16);
645     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n");
646     CHECK_IMAGELIST(28, 16, 16);
647 
648     /* when we increase the bitmap size, less icons will be created */
649     rebuild_toolbar(&hToolbar);
650     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n");
651     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
652     CHECK_IMAGELIST(6, 20, 20);
653     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
654     ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret);
655     CHECK_IMAGELIST(10, 20, 20);
656     /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */
657     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
658     UpdateWindow(hToolbar);
659     CHECK_IMAGELIST(26, 8, 8);
660     /* loading a standard bitmaps automatically resizes the icons */
661     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n");
662     UpdateWindow(hToolbar);
663     CHECK_IMAGELIST(28, 16, 16);
664 
665     /* two more SETBITMAPSIZE tests */
666     rebuild_toolbar(&hToolbar);
667     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
668     CHECK_IMAGELIST(100, 16, 16);
669     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n");
670     CHECK_IMAGELIST(200, 16, 16);
671     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
672     UpdateWindow(hToolbar);
673     CHECK_IMAGELIST(200, 8, 8);
674     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
675     UpdateWindow(hToolbar);
676     CHECK_IMAGELIST(200, 30, 30);
677     rebuild_toolbar(&hToolbar);
678     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
679     CHECK_IMAGELIST(8, 16, 16);
680     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n");
681     CHECK_IMAGELIST(13, 16, 16);
682     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
683     UpdateWindow(hToolbar);
684     CHECK_IMAGELIST(8, 30, 30);
685     /* when the width or height is zero, set it to 1 */
686     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
687     UpdateWindow(hToolbar);
688     CHECK_IMAGELIST(208, 1, 1);
689     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 5)) == TRUE, "TB_SETBITMAPSIZE failed\n");
690     UpdateWindow(hToolbar);
691     CHECK_IMAGELIST(208, 1, 5);
692     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(5, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
693     UpdateWindow(hToolbar);
694     CHECK_IMAGELIST(41, 5, 1);
695 
696     /* the control can add bitmaps to an existing image list */
697     rebuild_toolbar(&hToolbar);
698     himl = pImageList_LoadImageA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(IDB_BITMAP_80x15),
699                                 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
700     ok(himl != NULL, "failed to create imagelist\n");
701     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
702     CHECK_IMAGELIST(4, 20, 15);
703     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
704     CHECK_IMAGELIST(10, 20, 15);
705     /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change) */
706     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
707     UpdateWindow(hToolbar);
708     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(15, 14), "%x");
709     CHECK_IMAGELIST(10, 20, 15);
710     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n");
711     UpdateWindow(hToolbar);
712     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
713     CHECK_IMAGELIST(22, 20, 15);
714 
715     /* check standard bitmaps */
716     addbmp.hInst = HINST_COMMCTRL;
717     addbmp.nID = IDB_STD_SMALL_COLOR;
718     rebuild_toolbar(&hToolbar);
719     pImageList_Destroy(himl);
720 
721     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
722     CHECK_IMAGELIST(15, 16, 16);
723     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
724     addbmp.nID = IDB_STD_LARGE_COLOR;
725     rebuild_toolbar(&hToolbar);
726     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
727     CHECK_IMAGELIST(15, 24, 24);
728     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(31, 30), "%x");
729 
730     addbmp.nID = IDB_VIEW_SMALL_COLOR;
731     rebuild_toolbar(&hToolbar);
732     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
733     CHECK_IMAGELIST(12, 16, 16);
734     addbmp.nID = IDB_VIEW_LARGE_COLOR;
735     rebuild_toolbar(&hToolbar);
736     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
737     CHECK_IMAGELIST(12, 24, 24);
738 
739     addbmp.nID = IDB_HIST_SMALL_COLOR;
740     rebuild_toolbar(&hToolbar);
741     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
742     CHECK_IMAGELIST(5, 16, 16);
743     addbmp.nID = IDB_HIST_LARGE_COLOR;
744     rebuild_toolbar(&hToolbar);
745     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
746     CHECK_IMAGELIST(5, 24, 24);
747 
748 
749     DestroyWindow(hToolbar);
750 }
751 
752 #define CHECK_STRING_TABLE(count, tab) { \
753         INT _i; \
754         CHAR _buf[260]; \
755         for (_i = 0; _i < (count); _i++) {\
756             ret = SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(260, _i), (LPARAM)_buf); \
757             ok(ret >= 0, "TB_GETSTRINGA - unexpected return %d while checking string %d\n", ret, _i); \
758             if (ret >= 0) \
759                 ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \
760         } \
761         ok(SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \
762             "Too many strings in table\n"); \
763     }
764 
test_add_string(void)765 static void test_add_string(void)
766 {
767     LPCSTR test1 = "a\0b\0";
768     LPCSTR test2 = "|a|b||\0";
769     LPCSTR ret1[] = {"a", "b"};
770     LPCSTR ret2[] = {"a", "b", "|a|b||"};
771     LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"};
772     LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"};
773     LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"};
774     LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"};
775     LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"};
776     HWND hToolbar = NULL;
777     TBBUTTON button;
778     int ret;
779     CHAR buf[260];
780 
781     rebuild_toolbar(&hToolbar);
782     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
783     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
784     ret = SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(260, 1), (LPARAM)buf);
785     if (ret == 0)
786     {
787         win_skip("TB_GETSTRINGA needs 5.80\n");
788         return;
789     }
790     CHECK_STRING_TABLE(2, ret1);
791     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
792     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
793     CHECK_STRING_TABLE(3, ret2);
794 
795     /* null instance handle */
796     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, IDS_TBADD1);
797     ok(ret == -1, "TB_ADDSTRINGA - unexpected return %d\n", ret);
798 
799     /* invalid instance handle */
800     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0xdeadbeef, IDS_TBADD1);
801     ok(ret == -1, "TB_ADDSTRINGA - unexpected return %d\n", ret);
802 
803     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD1);
804     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
805     CHECK_STRING_TABLE(3, ret2);
806     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD2);
807     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
808     CHECK_STRING_TABLE(5, ret3);
809     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD3);
810     ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
811     CHECK_STRING_TABLE(6, ret4);
812     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD4);
813     ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
814     CHECK_STRING_TABLE(8, ret5);
815     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD5);
816     ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
817     CHECK_STRING_TABLE(11, ret6);
818     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandleA(NULL), IDS_TBADD7);
819     ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
820     CHECK_STRING_TABLE(14, ret7);
821 
822     ZeroMemory(&button, sizeof(button));
823     button.iString = (UINT_PTR)"Test";
824     SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
825     CHECK_STRING_TABLE(14, ret7);
826     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
827     CHECK_STRING_TABLE(14, ret7);
828 
829     DestroyWindow(hToolbar);
830 }
831 
expect_hot_notify(int idold,int idnew)832 static void expect_hot_notify(int idold, int idnew)
833 {
834     g_fExpectedHotItemOld = idold;
835     g_fExpectedHotItemNew = idnew;
836     g_fReceivedHotItemChange = FALSE;
837 }
838 
839 #define check_hot_notify() \
840     ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
841     g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
842 
test_hotitem(void)843 static void test_hotitem(void)
844 {
845     HWND hToolbar = NULL;
846     TBBUTTONINFOA tbinfo;
847     LRESULT ret;
848 
849     g_fBlockHotItemChange = FALSE;
850 
851     rebuild_toolbar_with_buttons(&hToolbar);
852     /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
853      * comctl6 doesn't have this requirement even when theme == NULL */
854     SetWindowLongA(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLongA(hToolbar, GWL_STYLE));
855     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
856     ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
857     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 1, 0);
858     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
859     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
860     ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
861     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 2, 0);
862     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
863 
864     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
865     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
866     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
867     ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
868     ret = SendMessageA(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
869     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
870     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
871     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
872 
873     expect_hot_notify(0, 7);
874     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 3, 0);
875     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
876     check_hot_notify();
877     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
878     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
879     g_fBlockHotItemChange = TRUE;
880     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 2, 0);
881     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
882     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
883     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
884     g_fBlockHotItemChange = FALSE;
885 
886     g_fReceivedHotItemChange = FALSE;
887     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
888     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
889     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
890 
891     g_fReceivedHotItemChange = FALSE;
892     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 3, 0);
893     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
894     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
895 
896     expect_hot_notify(7, 0);
897     ret = SendMessageA(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
898     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
899     check_hot_notify();
900     SendMessageA(hToolbar, TB_SETHOTITEM, 3, 0);
901 
902     /* setting disabled buttons will generate a notify with the button id but no button will be hot */
903     expect_hot_notify(7, 9);
904     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 4, 0);
905     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
906     check_hot_notify();
907     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
908     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
909     /* enabling the button won't change that */
910     SendMessageA(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
911     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
912     ok(ret == -1, "TB_GETHOTITEM returned %ld, expected -1\n", ret);
913 
914     /* disabling a hot button works */
915     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 3, 0);
916     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
917     g_fReceivedHotItemChange = FALSE;
918     SendMessageA(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
919     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
920     ok(ret == 3, "TB_GETHOTITEM returned %ld, expected 3\n", ret);
921     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
922 
923     SendMessageA(hToolbar, TB_SETHOTITEM, 1, 0);
924     tbinfo.cbSize = sizeof(TBBUTTONINFOA);
925     tbinfo.dwMask = TBIF_STATE;
926     tbinfo.fsState = 0;  /* disabled */
927     g_fReceivedHotItemChange = FALSE;
928     ok(SendMessageA(hToolbar, TB_SETBUTTONINFOA, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFOA failed\n");
929     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
930     ok(ret == 1, "TB_GETHOTITEM returned %ld, expected 1\n", ret);
931     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
932 
933     /* deleting a button unsets the hot item */
934     ret = SendMessageA(hToolbar, TB_SETHOTITEM, 0, 0);
935     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
936     g_fReceivedHotItemChange = FALSE;
937     ret = SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
938     ok(ret == TRUE, "TB_DELETEBUTTON returned %ld, expected TRUE\n", ret);
939     ret = SendMessageA(hToolbar, TB_GETHOTITEM, 0, 0);
940     ok(ret == -1, "TB_GETHOTITEM returned %ld, expected -1\n", ret);
941     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
942 
943     DestroyWindow(hToolbar);
944 }
945 
946 #if 0  /* use this to generate more tests*/
947 
948 static void dump_sizes(HWND hToolbar)
949 {
950     SIZE sz;
951     RECT r;
952     int count = SendMessageA(hToolbar, TB_BUTTONCOUNT, 0, 0);
953     int i;
954 
955     GetClientRect(hToolbar, &r);
956     SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz);
957     printf("  { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom,
958         sz.cx, sz.cy, count);
959     for (i=0; i<count; i++)
960     {
961         SendMessageA(hToolbar, TB_GETITEMRECT, i, &r);
962         printf("%s{%3d, %3d, %3d, %3d}, ", (i%3==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom);
963     }
964     printf("\n  }, },\n");
965 }
966 
967 #define check_sizes() dump_sizes(hToolbar);
968 #define check_sizes_todo(todomask) dump_sizes(hToolbar);
969 
970 #else
971 
system_font_height(void)972 static int system_font_height(void) {
973     HDC hDC;
974     TEXTMETRICA tm;
975 
976     hDC = CreateCompatibleDC(NULL);
977     GetTextMetricsA(hDC, &tm);
978     DeleteDC(NULL);
979 
980     return tm.tmHeight;
981 }
982 
string_width(const CHAR * s)983 static int string_width(const CHAR *s) {
984     SIZE sz;
985     HDC hdc;
986 
987     hdc = CreateCompatibleDC(NULL);
988     GetTextExtentPoint32A(hdc, s, strlen(s), &sz);
989     DeleteDC(hdc);
990 
991     return sz.cx;
992 }
993 
994 typedef struct
995 {
996     RECT rcClient;
997     SIZE szMin;
998     INT nButtons;
999     RECT *prcButtons;
1000 } tbsize_result_t;
1001 
init_tbsize_result(int nButtonsAlloc,int cleft,int ctop,int cright,int cbottom,int minx,int miny)1002 static tbsize_result_t init_tbsize_result(int nButtonsAlloc, int cleft, int ctop, int cright, int cbottom, int minx, int miny) {
1003     tbsize_result_t ret;
1004 
1005     SetRect(&ret.rcClient, cleft, ctop, cright, cbottom);
1006     ret.szMin.cx = minx;
1007     ret.szMin.cy = miny;
1008     ret.nButtons = 0;
1009     ret.prcButtons = heap_alloc_zero(nButtonsAlloc * sizeof(*ret.prcButtons));
1010 
1011     return ret;
1012 }
1013 
tbsize_addbutton(tbsize_result_t * tbsr,int left,int top,int right,int bottom)1014 static void tbsize_addbutton(tbsize_result_t *tbsr, int left, int top, int right, int bottom) {
1015     SetRect(&tbsr->prcButtons[tbsr->nButtons], left, top, right, bottom);
1016     tbsr->nButtons++;
1017 }
1018 
1019 #define STRING0 "A"
1020 #define STRING1 "MMMMMMMMMMMMM"
1021 #define STRING2 "Tst"
1022 
1023 static tbsize_result_t *tbsize_results;
1024 
1025 #define tbsize_results_num 28
1026 
init_tbsize_results(void)1027 static void init_tbsize_results(void) {
1028     int fontheight = system_font_height();
1029     int buttonwidth;
1030 
1031     tbsize_results = heap_alloc_zero(tbsize_results_num * sizeof(*tbsize_results));
1032 
1033     tbsize_results[0] = init_tbsize_result(5, 0, 0 ,672 ,26, 100 ,22);
1034     tbsize_addbutton(&tbsize_results[0],   0,   2,  23,  24);
1035     tbsize_addbutton(&tbsize_results[0],  23,   2,  46,  24);
1036     tbsize_addbutton(&tbsize_results[0],  46,   2,  54,  24);
1037     tbsize_addbutton(&tbsize_results[0],  54,   2,  77,  24);
1038     tbsize_addbutton(&tbsize_results[0],  77,   2, 100,  24);
1039 
1040     tbsize_results[1] = init_tbsize_result(7, 0, 0, 672, 26, 146, 22);
1041     tbsize_addbutton(&tbsize_results[1],   0,   2,  23,  24);
1042     tbsize_addbutton(&tbsize_results[1],  23,   2,  46,  24);
1043     tbsize_addbutton(&tbsize_results[1],  46,   2,  54,  24);
1044     tbsize_addbutton(&tbsize_results[1],  54,   2,  77,  24);
1045     tbsize_addbutton(&tbsize_results[1],  77,   2, 100,  24);
1046     tbsize_addbutton(&tbsize_results[1], 100,   2, 123,  24);
1047     tbsize_addbutton(&tbsize_results[1],   0,   24, 23,  46);
1048 
1049     tbsize_results[2] = init_tbsize_result(7, 0, 0, 672, 26, 146, 22);
1050     tbsize_addbutton(&tbsize_results[2],   0,   2,  23,  24);
1051     tbsize_addbutton(&tbsize_results[2],  23,   2,  46,  24);
1052     tbsize_addbutton(&tbsize_results[2],  46,   2,  54,  24);
1053     tbsize_addbutton(&tbsize_results[2],  54,   2,  77,  24);
1054     tbsize_addbutton(&tbsize_results[2],  77,   2, 100,  24);
1055     tbsize_addbutton(&tbsize_results[2], 100,   2, 123,  24);
1056     tbsize_addbutton(&tbsize_results[2],   0,   24, 23,  46);
1057 
1058     tbsize_results[3] = init_tbsize_result(7, 0, 0, 672, 26, 146, 22);
1059     tbsize_addbutton(&tbsize_results[3],   0,   2,  23,  24);
1060     tbsize_addbutton(&tbsize_results[3],  23,   2,  46,  24);
1061     tbsize_addbutton(&tbsize_results[3],  46,   2,  54,  24);
1062     tbsize_addbutton(&tbsize_results[3],  54,   2,  77,  24);
1063     tbsize_addbutton(&tbsize_results[3],  77,   2, 100,  24);
1064     tbsize_addbutton(&tbsize_results[3], 100,   2, 123,  24);
1065     tbsize_addbutton(&tbsize_results[3], 123,   2, 146,  24);
1066 
1067     tbsize_results[4] = init_tbsize_result(9, 0, 0, 672, 26, 192, 22);
1068     tbsize_addbutton(&tbsize_results[4],   0,   2,  23,  24);
1069     tbsize_addbutton(&tbsize_results[4],  23,   2,  46,  24);
1070     tbsize_addbutton(&tbsize_results[4],  46,   2,  54,  24);
1071     tbsize_addbutton(&tbsize_results[4],  54,   2,  77,  24);
1072     tbsize_addbutton(&tbsize_results[4],  77,   2, 100,  24);
1073     tbsize_addbutton(&tbsize_results[4], 100,   2, 123,  24);
1074     tbsize_addbutton(&tbsize_results[4], 123,   2, 146,  24);
1075     tbsize_addbutton(&tbsize_results[4], 146,   2, 169,  24);
1076     tbsize_addbutton(&tbsize_results[4], 169,   2, 192,  24);
1077 
1078     tbsize_results[5] = init_tbsize_result(39, 0, 0, 672, 92, 882, 22);
1079     tbsize_addbutton(&tbsize_results[5],   0,   2,  23,  24);
1080     tbsize_addbutton(&tbsize_results[5],  23,   2,  46,  24);
1081     tbsize_addbutton(&tbsize_results[5],   0,   2,   8,  29);
1082     tbsize_addbutton(&tbsize_results[5],   0,  29,  23,  51);
1083     tbsize_addbutton(&tbsize_results[5],  23,  29,  46,  51);
1084     tbsize_addbutton(&tbsize_results[5],  46,  29,  69,  51);
1085     tbsize_addbutton(&tbsize_results[5],  69,  29,  92,  51);
1086     tbsize_addbutton(&tbsize_results[5],  92,  29, 115,  51);
1087     tbsize_addbutton(&tbsize_results[5], 115,  29, 138,  51);
1088     tbsize_addbutton(&tbsize_results[5], 138,  29, 161,  51);
1089     tbsize_addbutton(&tbsize_results[5], 161,  29, 184,  51);
1090     tbsize_addbutton(&tbsize_results[5], 184,  29, 207,  51);
1091     tbsize_addbutton(&tbsize_results[5], 207,  29, 230,  51);
1092     tbsize_addbutton(&tbsize_results[5], 230,  29, 253,  51);
1093     tbsize_addbutton(&tbsize_results[5], 253,  29, 276,  51);
1094     tbsize_addbutton(&tbsize_results[5], 276,  29, 299,  51);
1095     tbsize_addbutton(&tbsize_results[5], 299,  29, 322,  51);
1096     tbsize_addbutton(&tbsize_results[5], 322,  29, 345,  51);
1097     tbsize_addbutton(&tbsize_results[5], 345,  29, 368,  51);
1098     tbsize_addbutton(&tbsize_results[5], 368,  29, 391,  51);
1099     tbsize_addbutton(&tbsize_results[5], 391,  29, 414,  51);
1100     tbsize_addbutton(&tbsize_results[5], 414,  29, 437,  51);
1101     tbsize_addbutton(&tbsize_results[5], 437,  29, 460,  51);
1102     tbsize_addbutton(&tbsize_results[5], 460,  29, 483,  51);
1103     tbsize_addbutton(&tbsize_results[5], 483,  29, 506,  51);
1104     tbsize_addbutton(&tbsize_results[5], 506,  29, 529,  51);
1105     tbsize_addbutton(&tbsize_results[5], 529,  29, 552,  51);
1106     tbsize_addbutton(&tbsize_results[5], 552,  29, 575,  51);
1107     tbsize_addbutton(&tbsize_results[5], 575,  29, 598,  51);
1108     tbsize_addbutton(&tbsize_results[5], 598,  29, 621,  51);
1109     tbsize_addbutton(&tbsize_results[5], 621,  29, 644,  51);
1110     tbsize_addbutton(&tbsize_results[5], 644,  29, 667,  51);
1111     tbsize_addbutton(&tbsize_results[5],   0,  51,  23,  73);
1112     tbsize_addbutton(&tbsize_results[5],  23,  51,  46,  73);
1113     tbsize_addbutton(&tbsize_results[5],  46,  51,  69,  73);
1114     tbsize_addbutton(&tbsize_results[5],  69,  51,  92,  73);
1115     tbsize_addbutton(&tbsize_results[5],  92,  51, 115,  73);
1116     tbsize_addbutton(&tbsize_results[5], 115,  51, 138,  73);
1117     tbsize_addbutton(&tbsize_results[5], 138,  51, 161,  73);
1118 
1119     tbsize_results[6] = init_tbsize_result(7, 0, 0, 48, 226, 23, 140);
1120     tbsize_addbutton(&tbsize_results[6],   0,   2,  23,  24);
1121     tbsize_addbutton(&tbsize_results[6],  23,   2,  46,  24);
1122     tbsize_addbutton(&tbsize_results[6],  46,   2,  94,  24);
1123     tbsize_addbutton(&tbsize_results[6],  94,   2, 117,  24);
1124     tbsize_addbutton(&tbsize_results[6], 117,   2, 140,  24);
1125     tbsize_addbutton(&tbsize_results[6], 140,   2, 163,  24);
1126     tbsize_addbutton(&tbsize_results[6],   0,  24,  23,  46);
1127 
1128     tbsize_results[7] = init_tbsize_result(7, 0, 0, 92, 226, 23, 140);
1129     tbsize_addbutton(&tbsize_results[7],   0,   2,  23,  24);
1130     tbsize_addbutton(&tbsize_results[7],  23,   2,  46,  24);
1131     tbsize_addbutton(&tbsize_results[7],   0,  24,  92,  32);
1132     tbsize_addbutton(&tbsize_results[7],   0,  32,  23,  54);
1133     tbsize_addbutton(&tbsize_results[7],  23,  32,  46,  54);
1134     tbsize_addbutton(&tbsize_results[7],  46,  32,  69,  54);
1135     tbsize_addbutton(&tbsize_results[7],  69,  32,  92,  54);
1136 
1137     tbsize_results[8] = init_tbsize_result(7, 0, 0, 672, 26, 194, 30);
1138     tbsize_addbutton(&tbsize_results[8],   0,   2,  31,  32);
1139     tbsize_addbutton(&tbsize_results[8],  31,   2,  62,  32);
1140     tbsize_addbutton(&tbsize_results[8],  62,   2,  70,  32);
1141     tbsize_addbutton(&tbsize_results[8],  70,   2, 101,  32);
1142     tbsize_addbutton(&tbsize_results[8], 101,   2, 132,  32);
1143     tbsize_addbutton(&tbsize_results[8], 132,   2, 163,  32);
1144     tbsize_addbutton(&tbsize_results[8],   0,  32,  31,  62);
1145 
1146     tbsize_results[9] = init_tbsize_result(7, 0, 0, 672, 64, 194, 30);
1147     tbsize_addbutton(&tbsize_results[9],   0,   2,  31,  32);
1148     tbsize_addbutton(&tbsize_results[9],  31,   2,  62,  32);
1149     tbsize_addbutton(&tbsize_results[9],  62,   2,  70,  32);
1150     tbsize_addbutton(&tbsize_results[9],  70,   2, 101,  32);
1151     tbsize_addbutton(&tbsize_results[9], 101,   2, 132,  32);
1152     tbsize_addbutton(&tbsize_results[9], 132,   2, 163,  32);
1153     tbsize_addbutton(&tbsize_results[9],   0,  32,  31,  62);
1154 
1155     tbsize_results[10] = init_tbsize_result(7, 0, 0, 672, 64, 194, 30);
1156     tbsize_addbutton(&tbsize_results[10],   0,   0,  31,  30);
1157     tbsize_addbutton(&tbsize_results[10],  31,   0,  62,  30);
1158     tbsize_addbutton(&tbsize_results[10],  62,   0,  70,  30);
1159     tbsize_addbutton(&tbsize_results[10],  70,   0, 101,  30);
1160     tbsize_addbutton(&tbsize_results[10], 101,   0, 132,  30);
1161     tbsize_addbutton(&tbsize_results[10], 132,   0, 163,  30);
1162     tbsize_addbutton(&tbsize_results[10],   0,  30,  31,  60);
1163 
1164     tbsize_results[11] = init_tbsize_result(7, 0, 0, 124, 226, 31, 188);
1165     tbsize_addbutton(&tbsize_results[11],   0,    0,  31,  30);
1166     tbsize_addbutton(&tbsize_results[11],  31,    0,  62,  30);
1167     tbsize_addbutton(&tbsize_results[11],   0,   30, 124,  38);
1168     tbsize_addbutton(&tbsize_results[11],   0,   38,  31,  68);
1169     tbsize_addbutton(&tbsize_results[11],  31,   38,  62,  68);
1170     tbsize_addbutton(&tbsize_results[11],  62,   38,  93,  68);
1171     tbsize_addbutton(&tbsize_results[11],  93,   38, 124,  68);
1172 
1173     tbsize_results[12] = init_tbsize_result(7, 0, 0, 672, 26, 146, 22);
1174     tbsize_addbutton(&tbsize_results[12],   0,   2,  23,  24);
1175     tbsize_addbutton(&tbsize_results[12],  23,   2,  46,  24);
1176     tbsize_addbutton(&tbsize_results[12],  46,   2,  54,  24);
1177     tbsize_addbutton(&tbsize_results[12],  54,   2,  77,  24);
1178     tbsize_addbutton(&tbsize_results[12],  77,   2, 100,  24);
1179     tbsize_addbutton(&tbsize_results[12], 100,   2, 123,  24);
1180     tbsize_addbutton(&tbsize_results[12], 123,   2, 146,  24);
1181 
1182     tbsize_results[13] = init_tbsize_result(7, 0, 0, 672, 26, 146, 100);
1183     tbsize_addbutton(&tbsize_results[13],   0,   0,  23, 100);
1184     tbsize_addbutton(&tbsize_results[13],  23,   0,  46, 100);
1185     tbsize_addbutton(&tbsize_results[13],  46,   0,  54, 100);
1186     tbsize_addbutton(&tbsize_results[13],  54,   0,  77, 100);
1187     tbsize_addbutton(&tbsize_results[13],  77,   0, 100, 100);
1188     tbsize_addbutton(&tbsize_results[13], 100,   0, 123, 100);
1189     tbsize_addbutton(&tbsize_results[13], 123,   0, 146, 100);
1190 
1191     tbsize_results[14] = init_tbsize_result(10, 0, 0, 672, 26, 146, 100);
1192     tbsize_addbutton(&tbsize_results[14],   0,   0,  23, 100);
1193     tbsize_addbutton(&tbsize_results[14],  23,   0,  46, 100);
1194     tbsize_addbutton(&tbsize_results[14],  46,   0,  54, 100);
1195     tbsize_addbutton(&tbsize_results[14],  54,   0,  77, 100);
1196     tbsize_addbutton(&tbsize_results[14],  77,   0, 100, 100);
1197     tbsize_addbutton(&tbsize_results[14], 100,   0, 123, 100);
1198     tbsize_addbutton(&tbsize_results[14], 123,   0, 146, 100);
1199     tbsize_addbutton(&tbsize_results[14], 146,   0, 169, 100);
1200     tbsize_addbutton(&tbsize_results[14], 169,   0, 192, 100);
1201     tbsize_addbutton(&tbsize_results[14], 192,   0, 215, 100);
1202 
1203     tbsize_results[15] = init_tbsize_result(11, 0, 0, 672, 26, 238, 39);
1204     tbsize_addbutton(&tbsize_results[15],   0,   0,  23,  23 + fontheight);
1205     tbsize_addbutton(&tbsize_results[15],  23,   0,  46,  23 + fontheight);
1206     tbsize_addbutton(&tbsize_results[15],  46,   0,  54,  23 + fontheight);
1207     tbsize_addbutton(&tbsize_results[15],  54,   0,  77,  23 + fontheight);
1208     tbsize_addbutton(&tbsize_results[15],  77,   0, 100,  23 + fontheight);
1209     tbsize_addbutton(&tbsize_results[15], 100,   0, 123,  23 + fontheight);
1210     tbsize_addbutton(&tbsize_results[15], 123,   0, 146,  23 + fontheight);
1211     tbsize_addbutton(&tbsize_results[15], 146,   0, 169,  23 + fontheight);
1212     tbsize_addbutton(&tbsize_results[15], 169,   0, 192,  23 + fontheight);
1213     tbsize_addbutton(&tbsize_results[15], 192,   0, 215,  23 + fontheight);
1214     tbsize_addbutton(&tbsize_results[15], 215,   0, 238,  23 + fontheight);
1215 
1216     tbsize_results[16] = init_tbsize_result(11, 0, 0, 672, 26, 239, 22);
1217     tbsize_addbutton(&tbsize_results[16],   0,   0,  23,  22);
1218     tbsize_addbutton(&tbsize_results[16],  23,   0,  46,  22);
1219     tbsize_addbutton(&tbsize_results[16],  46,   0,  54,  22);
1220     tbsize_addbutton(&tbsize_results[16],  54,   0,  77,  22);
1221     tbsize_addbutton(&tbsize_results[16],  77,   0, 100,  22);
1222     tbsize_addbutton(&tbsize_results[16], 100,   0, 123,  22);
1223     tbsize_addbutton(&tbsize_results[16], 123,   0, 146,  22);
1224     tbsize_addbutton(&tbsize_results[16], 146,   0, 169,  22);
1225     tbsize_addbutton(&tbsize_results[16], 169,   0, 192,  22);
1226     tbsize_addbutton(&tbsize_results[16], 192,   0, 215,  22);
1227     tbsize_addbutton(&tbsize_results[16], 215,   0, 238,  22);
1228 
1229     buttonwidth = 7 + string_width(STRING1);
1230 
1231     tbsize_results[17] = init_tbsize_result(3, 0, 0, 672, 26, 489, 39);
1232     tbsize_addbutton(&tbsize_results[17],   0,   2, buttonwidth,  25 + fontheight);
1233     tbsize_addbutton(&tbsize_results[17], buttonwidth,   2, 2*buttonwidth + 4,  25 + fontheight);
1234     tbsize_addbutton(&tbsize_results[17], 2*buttonwidth + 4,   2, 3*buttonwidth + 4,  25 + fontheight);
1235 
1236     tbsize_results[18] = init_tbsize_result(6, 0, 0, 672, 104, 978, 24);
1237     tbsize_addbutton(&tbsize_results[18],   0,   2, buttonwidth,  10 + fontheight);
1238     tbsize_addbutton(&tbsize_results[18], buttonwidth,   2, 2*buttonwidth,  10 + fontheight);
1239     tbsize_addbutton(&tbsize_results[18], 2*buttonwidth,   2, 3*buttonwidth,  10 + fontheight);
1240     tbsize_addbutton(&tbsize_results[18], 3*buttonwidth,   2, 4*buttonwidth,  10 + fontheight);
1241     tbsize_addbutton(&tbsize_results[18], 4*buttonwidth,   2, 5*buttonwidth + 4,  10 + fontheight);
1242     tbsize_addbutton(&tbsize_results[18], 5*buttonwidth + 4,   2, 5*buttonwidth + 4 + string_width(STRING2) + 11,  10 + fontheight);
1243 
1244     tbsize_results[19] = init_tbsize_result(6, 0, 0, 672, 28, 978, 38);
1245     tbsize_addbutton(&tbsize_results[19],   0,   0, buttonwidth,  22 + fontheight);
1246     tbsize_addbutton(&tbsize_results[19], buttonwidth,   0, 2*buttonwidth,  22 + fontheight);
1247     tbsize_addbutton(&tbsize_results[19], 2*buttonwidth,   0, 3*buttonwidth,  22 + fontheight);
1248     tbsize_addbutton(&tbsize_results[19], 3*buttonwidth,   0, 4*buttonwidth,  22 + fontheight);
1249     tbsize_addbutton(&tbsize_results[19], 4*buttonwidth,   0, 5*buttonwidth + 4,  22 + fontheight);
1250     tbsize_addbutton(&tbsize_results[19], 5*buttonwidth + 4,   0, 5*buttonwidth + 4 + string_width(STRING2) + 11,  22 + fontheight);
1251 
1252     tbsize_results[20] = init_tbsize_result(3, 0, 0, 672, 100, 239, 102);
1253     tbsize_addbutton(&tbsize_results[20],   0,   2, 100, 102);
1254     tbsize_addbutton(&tbsize_results[20], 100,   2, 139, 102);
1255     tbsize_addbutton(&tbsize_results[20], 139,   2, 239, 102);
1256 
1257     tbsize_results[21] = init_tbsize_result(3, 0, 0, 672, 42, 185, 40);
1258     tbsize_addbutton(&tbsize_results[21],   0,   2,  75,  40);
1259     tbsize_addbutton(&tbsize_results[21],  75,   2, 118,  40);
1260     tbsize_addbutton(&tbsize_results[21], 118,   2, 165 + string_width(STRING2),  40);
1261 
1262     tbsize_results[22] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40);
1263     tbsize_addbutton(&tbsize_results[22],   0,   2,  47 + string_width(STRING2),  40);
1264 
1265     tbsize_results[23] = init_tbsize_result(2, 0, 0, 672, 42, 67, 41);
1266     tbsize_addbutton(&tbsize_results[23],   0,   2, 672,  25 + fontheight);
1267     tbsize_addbutton(&tbsize_results[23],   0,  25 + fontheight, 672,  48 + 2*fontheight);
1268 
1269     tbsize_results[24] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40);
1270     tbsize_addbutton(&tbsize_results[24],   0,   2,  11 + string_width(STRING2),  24);
1271 
1272     tbsize_results[25] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40);
1273     tbsize_addbutton(&tbsize_results[25],   0,   2,  40,  24);
1274 
1275     tbsize_results[26] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40);
1276     tbsize_addbutton(&tbsize_results[26],   0,   2,  40,  24);
1277 
1278     tbsize_results[27] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40);
1279     tbsize_addbutton(&tbsize_results[27],   0,   2,  40,  24);
1280 }
1281 
free_tbsize_results(void)1282 static void free_tbsize_results(void) {
1283     int i;
1284 
1285     for (i = 0; i < tbsize_results_num; i++)
1286         heap_free(tbsize_results[i].prcButtons);
1287     heap_free(tbsize_results);
1288     tbsize_results = NULL;
1289 }
1290 
1291 static int tbsize_numtests = 0;
1292 
1293 typedef struct
1294 {
1295     int test_num;
1296     int rect_index;
1297     RECT rcButton;
1298 } tbsize_alt_result_t;
1299 
1300 static tbsize_alt_result_t tbsize_alt_results[] =
1301 {
1302   { 5, 2, { 0, 24, 8, 29 } },
1303   { 20, 1, { 100, 2, 107, 102 } },
1304   { 20, 2, { 107, 2, 207, 102 } }
1305 };
1306 
1307 static DWORD tbsize_alt_numtests = 0;
1308 
1309 #define check_sizes_todo(todomask) { \
1310         RECT rc; \
1311         int buttonCount, i, mask=(todomask); \
1312         tbsize_result_t *res = &tbsize_results[tbsize_numtests]; \
1313         GetClientRect(hToolbar, &rc); \
1314         /*check_rect("client", rc, res->rcClient);*/ \
1315         buttonCount = SendMessageA(hToolbar, TB_BUTTONCOUNT, 0, 0); \
1316         compare(buttonCount, res->nButtons, "%d"); \
1317         for (i=0; i<min(buttonCount, res->nButtons); i++) { \
1318             ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
1319             if (broken(tbsize_alt_numtests < ARRAY_SIZE(tbsize_alt_results) && \
1320                        EqualRect(&rc, &tbsize_alt_results[tbsize_alt_numtests].rcButton))) { \
1321                 win_skip("Alternate rect found\n"); \
1322                 tbsize_alt_numtests++; \
1323             } else todo_wine_if(mask&1) \
1324                 check_rect("button = %d, tbsize_numtests = %d", rc, res->prcButtons[i], i, tbsize_numtests); \
1325             mask >>= 1; \
1326         } \
1327         tbsize_numtests++; \
1328     }
1329 
1330 #define check_sizes() check_sizes_todo(0)
1331 
1332 #endif
1333 
1334 static TBBUTTON buttons1[] = {
1335     {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1},
1336     {0, 11, 0, 0, {0, }, 0, -1},
1337 };
1338 static TBBUTTON buttons2[] = {
1339     {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1340     {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1341 };
1342 static TBBUTTON buttons3[] = {
1343     {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0},
1344     {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1},
1345     {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1},
1346     {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)STRING2}
1347 };
1348 static TBBUTTON buttons4[] = {
1349     {0, 40, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)STRING2},
1350     {0, 41, TBSTATE_ENABLED, 0, {0, }, 0, (UINT_PTR)STRING2},
1351     {0, 41, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0, }, 0, (UINT_PTR)STRING2}
1352 };
1353 
test_sizes(void)1354 static void test_sizes(void)
1355 {
1356     HWND hToolbar = NULL;
1357     HIMAGELIST himl, himl2;
1358     TBBUTTONINFOA tbinfo;
1359     TBBUTTON button;
1360     int style;
1361     int i;
1362     int fontheight = system_font_height();
1363 
1364     init_tbsize_results();
1365 
1366     rebuild_toolbar_with_buttons(&hToolbar);
1367     style = GetWindowLongA(hToolbar, GWL_STYLE);
1368     ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style);
1369     check_sizes();
1370     /* the TBSTATE_WRAP makes a second row */
1371     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1);
1372     check_sizes();
1373     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1374     check_sizes();
1375     SendMessageA(hToolbar, TB_GETBUTTON, 5, (LPARAM)&button);
1376     ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "got %08x\n", button.fsState);
1377     /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */
1378     SetWindowLongA(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE);
1379     check_sizes();
1380     SendMessageA(hToolbar, TB_GETBUTTON, 5, (LPARAM)&button);
1381     ok(button.fsState == TBSTATE_ENABLED, "got %08x\n", button.fsState);
1382     /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */
1383     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1);
1384     check_sizes();
1385     /* only after adding enough buttons the bar will be wrapped on a
1386      * separator and then on the first button */
1387     for (i=0; i<15; i++)
1388         SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1);
1389     check_sizes_todo(0x4);
1390     SendMessageA(hToolbar, TB_GETBUTTON, 31, (LPARAM)&button);
1391     ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "got %08x\n", button.fsState);
1392     SetWindowLongA(hToolbar, GWL_STYLE, style);
1393     SendMessageA(hToolbar, TB_GETBUTTON, 31, (LPARAM)&button);
1394     ok(button.fsState == TBSTATE_ENABLED, "got %08x\n", button.fsState);
1395 
1396     rebuild_toolbar_with_buttons(&hToolbar);
1397     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1);
1398     /* setting the buttons vertical will only change the window client size */
1399     SetWindowLongA(hToolbar, GWL_STYLE, style | CCS_VERT);
1400     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1401     check_sizes_todo(0x3c);
1402     /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */
1403     SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT);
1404     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1405     check_sizes_todo(0x7c);
1406 
1407     rebuild_toolbar_with_buttons(&hToolbar);
1408     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1);
1409     /* a TB_SETBITMAPSIZE changes button sizes*/
1410     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
1411     check_sizes();
1412 
1413     /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */
1414     SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
1415     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1416     check_sizes();
1417     /* but after a TB_SETBITMAPSIZE the top margins is changed */
1418     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20));
1419     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
1420     check_sizes();
1421     /* some vertical toolbar sizes */
1422     SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT);
1423     check_sizes_todo(0x7c);
1424 
1425     rebuild_toolbar_with_buttons(&hToolbar);
1426     SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
1427     /* newly added buttons will be use the previous margin */
1428     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons2);
1429     check_sizes();
1430     /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */
1431     check_button_size(hToolbar, 23, 22);
1432     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n");
1433     check_button_size(hToolbar, 23, 22);
1434     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
1435     check_button_size(hToolbar, 23, 100);
1436     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n");
1437     check_button_size(hToolbar, 23, 22);
1438     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
1439     check_button_size(hToolbar, 23, 100);
1440     check_sizes();
1441     /* add some buttons with non-default sizes */
1442     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons2);
1443     SendMessageA(hToolbar, TB_INSERTBUTTONA, -1, (LPARAM)&buttons2[0]);
1444     check_sizes();
1445     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[0]);
1446     /* TB_ADDSTRINGA resets the size */
1447     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM) STRING0 "\0" STRING1 "\0");
1448     check_button_size(hToolbar, 23, 23 + fontheight);
1449     check_sizes();
1450     /* TB_SETBUTTONSIZE can be used to crop the text */
1451     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
1452     check_button_size(hToolbar, 23, 22);
1453     check_sizes();
1454     /* the default size is bitmap size + padding */
1455     SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1));
1456     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
1457     check_button_size(hToolbar, 17, 17);
1458     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3));
1459     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
1460     check_button_size(hToolbar, 4, 4);
1461 
1462     rebuild_toolbar(&hToolbar);
1463     /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */
1464     check_button_size(hToolbar, 23, 22);
1465     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15));
1466     check_button_size(hToolbar, 23, 21);
1467     /* -1 in TB_SETBITMAPSIZE is a special code meaning that the coordinate shouldn't be changed */
1468     add_128x15_bitmap(hToolbar, 16);
1469     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(14, -1)), "TB_SETBITMAPSIZE failed\n");
1470     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 21), "%x");
1471     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, 12)), "TB_SETBITMAPSIZE failed\n");
1472     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
1473     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, -1)), "TB_SETBITMAPSIZE failed\n");
1474     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
1475     /* check the imagelist */
1476     InvalidateRect(hToolbar, NULL, TRUE);
1477     UpdateWindow(hToolbar);
1478     CHECK_IMAGELIST(16, 14, 12);
1479 
1480     rebuild_toolbar(&hToolbar);
1481     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)STRING0 "\0" STRING1 "\0");
1482     /* the height is increased after a TB_ADDSTRINGA */
1483     check_button_size(hToolbar, 23, 23 + fontheight);
1484     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
1485     /* if a string is in the pool, even adding a button without a string resets the size */
1486     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons2[0]);
1487     check_button_size(hToolbar, 23, 22);
1488     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
1489     /* an BTNS_AUTOSIZE button is also considered when computing the new size */
1490     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[2]);
1491     check_button_size(hToolbar, 7 + string_width(STRING1), 23 + fontheight);
1492     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[0]);
1493     check_sizes();
1494     /* delete button doesn't change the buttons size */
1495     SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0);
1496     SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
1497     check_button_size(hToolbar, 7 + string_width(STRING1), 23 + fontheight);
1498     /* TB_INSERTBUTTONAS will */
1499     SendMessageA(hToolbar, TB_INSERTBUTTONA, 1, (LPARAM)&buttons2[0]);
1500     check_button_size(hToolbar, 23, 22);
1501 
1502     /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */
1503     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
1504     ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n");
1505     check_button_size(hToolbar, 100, 100);
1506     ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n");
1507     check_button_size(hToolbar, 100, 100);
1508     /* however changing the hidden flag with TB_SETSTATE does */
1509     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n");
1510     check_button_size(hToolbar, 100, 100);
1511     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n");
1512     check_button_size(hToolbar, 23, 22);
1513 
1514     /* TB_SETIMAGELIST always changes the height but the width only if necessary */
1515     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
1516     himl = pImageList_LoadImageA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(IDB_BITMAP_80x15),
1517                                 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
1518     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
1519     check_button_size(hToolbar, 100, 21);
1520     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
1521     check_button_size(hToolbar, 100, 100);
1522     /* But there are no update when we change imagelist, and image sizes are the same */
1523     himl2 = pImageList_LoadImageA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(IDB_BITMAP_128x15),
1524                                  20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
1525     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LRESULT)himl2) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
1526     check_button_size(hToolbar, 100, 100);
1527     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
1528     check_button_size(hToolbar, 27, 21);
1529     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl2, "TB_SETIMAGELIST failed\n");
1530     check_button_size(hToolbar, 27, 7);
1531     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
1532     check_button_size(hToolbar, 8, 7)
1533     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
1534     check_button_size(hToolbar, 27, 21)
1535     /* the text is taken into account */
1536     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)STRING0 "\0" STRING1 "\0");
1537     SendMessageA(hToolbar, TB_ADDBUTTONSA, 4, (LPARAM)buttons3);
1538     check_button_size(hToolbar, 7 + string_width(STRING1), 22 + fontheight);
1539     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
1540     check_button_size(hToolbar, 7 + string_width(STRING1), 8 + fontheight);
1541     /* the style change also comes into effect */
1542     check_sizes();
1543     SetWindowLongA(hToolbar, GWL_STYLE, GetWindowLongA(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
1544     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
1545     check_sizes_todo(0x30);     /* some small problems with BTNS_AUTOSIZE button sizes */
1546 
1547     rebuild_toolbar(&hToolbar);
1548     pImageList_Destroy(himl);
1549     pImageList_Destroy(himl2);
1550 
1551     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]);
1552     check_button_size(hToolbar, 7 + string_width(STRING2), 23 + fontheight);
1553     SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0);
1554     check_button_size(hToolbar, 7 + string_width(STRING2), 23 + fontheight);
1555 
1556     rebuild_toolbar(&hToolbar);
1557 
1558     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
1559     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
1560     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONSA failed\n");
1561     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONSA failed\n");
1562     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[0]) == 1, "TB_ADDBUTTONSA failed\n");
1563     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1564     check_sizes();
1565 
1566     rebuild_toolbar(&hToolbar);
1567     SetWindowLongA(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLongA(hToolbar, GWL_STYLE));
1568     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
1569     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
1570     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONSA failed\n");
1571     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONSA failed\n");
1572     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONSA failed\n");
1573     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1574     check_sizes_todo(0xff);
1575 
1576     rebuild_toolbar(&hToolbar);
1577     SetWindowLongA(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLongA(hToolbar, GWL_STYLE));
1578     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
1579     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
1580     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONSA failed\n");
1581     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1582     check_sizes();
1583 
1584     rebuild_toolbar(&hToolbar);
1585     SetWindowLongA(hToolbar, GWL_STYLE, TBSTYLE_WRAPABLE | GetWindowLongA(hToolbar, GWL_STYLE));
1586     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONSA failed\n");
1587     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONSA failed\n");
1588     tbinfo.cx = 672;
1589     tbinfo.cbSize = sizeof(TBBUTTONINFOA);
1590     tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX;
1591     if (SendMessageA(hToolbar, TB_SETBUTTONINFOA, 0, (LPARAM)&tbinfo))
1592     {
1593         ok(SendMessageA(hToolbar, TB_SETBUTTONINFOA, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFOA failed\n");
1594         SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1595         check_sizes();
1596     }
1597     else  /* TBIF_BYINDEX probably not supported, confirm that this was the reason for the failure */
1598     {
1599         tbinfo.dwMask = TBIF_SIZE;
1600         ok(SendMessageA(hToolbar, TB_SETBUTTONINFOA, 33, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFOA failed\n");
1601         tbsize_numtests++;
1602     }
1603 
1604     /* Single BTNS_AUTOSIZE button with string. */
1605     rebuild_toolbar(&hToolbar);
1606     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[0]) == 1, "TB_ADDBUTTONSA failed\n");
1607     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n");
1608     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1609     check_sizes();
1610 
1611     /* Single non-BTNS_AUTOSIZE button with string. */
1612     rebuild_toolbar(&hToolbar);
1613     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[1]) == 1, "TB_ADDBUTTONSA failed\n");
1614     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n");
1615     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1616     check_sizes();
1617 
1618     /* Single non-BTNS_AUTOSIZE button with string with TBSTYLE_EX_MIXEDBUTTONS set. */
1619     rebuild_toolbar(&hToolbar);
1620     SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1621     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[1]) == 1, "TB_ADDBUTTONSA failed\n");
1622     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n");
1623     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1624     check_sizes();
1625 
1626     /* Single non-BTNS_AUTOSIZE, BTNS_SHOWTEXT button with string with TBSTYLE_EX_MIXEDBUTTONS set. */
1627     rebuild_toolbar(&hToolbar);
1628     SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1629     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[2]) == 1, "TB_ADDBUTTONSA failed\n");
1630     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n");
1631     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
1632     check_sizes();
1633 
1634     free_tbsize_results();
1635     DestroyWindow(hToolbar);
1636 }
1637 
1638 /* Toolbar control has two ways of reacting to a change. We call them a
1639  * relayout and recalc. A recalc forces a recompute of values like button size
1640  * and top margin (the latter in comctl32 <v6), while a relayout uses the cached
1641  * values. This functions creates a flat toolbar with a top margin of a non-flat
1642  * toolbar. We will notice a recalc, as it will recompte the top margin and
1643  * change it to zero*/
prepare_recalc_test(HWND * phToolbar)1644 static void prepare_recalc_test(HWND *phToolbar)
1645 {
1646     RECT rect;
1647     rebuild_toolbar_with_buttons(phToolbar);
1648     SetWindowLongA(*phToolbar, GWL_STYLE,
1649         GetWindowLongA(*phToolbar, GWL_STYLE) | TBSTYLE_FLAT);
1650     SendMessageA(*phToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1651     ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n",
1652         rect.top);
1653 }
1654 
did_recalc(HWND hToolbar)1655 static BOOL did_recalc(HWND hToolbar)
1656 {
1657     RECT rect;
1658     SendMessageA(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1659     ok(rect.top == 2 || rect.top == 0, "Unexpected top margin %d in recalc test\n",
1660         rect.top);
1661     return (rect.top == 0);
1662 }
1663 
1664 /* call after a recalc did happen to return to an unstable state */
restore_recalc_state(HWND hToolbar)1665 static void restore_recalc_state(HWND hToolbar)
1666 {
1667     RECT rect;
1668     /* return to style with a 2px top margin */
1669     SetWindowLongA(hToolbar, GWL_STYLE,
1670                    SendMessageA(hToolbar, TB_GETSTYLE, 0, 0) & ~TBSTYLE_FLAT);
1671     /* recalc */
1672     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]);
1673     /* top margin will be 0px if a recalc occurs */
1674     SetWindowLongA(hToolbar, GWL_STYLE,
1675                    SendMessageA(hToolbar, TB_GETSTYLE, 0, 0) | TBSTYLE_FLAT);
1676     /* safety check */
1677     SendMessageA(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1678     ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n",
1679         rect.top);
1680 }
1681 
test_recalc(void)1682 static void test_recalc(void)
1683 {
1684     HWND hToolbar = NULL;
1685     TBBUTTONINFOA bi;
1686     CHAR test[] = "Test";
1687     const int EX_STYLES_COUNT = 5;
1688     int i;
1689     BOOL recalc;
1690     DWORD style;
1691 
1692     /* Like TB_ADDBUTTONSA tested in test_sized, inserting a button without text
1693      * results in a relayout, while adding one with text forces a recalc */
1694     prepare_recalc_test(&hToolbar);
1695     SendMessageA(hToolbar, TB_INSERTBUTTONA, 1, (LPARAM)&buttons3[0]);
1696     recalc = did_recalc(hToolbar);
1697     ok(!recalc, "Unexpected recalc - adding button without text\n");
1698 
1699     prepare_recalc_test(&hToolbar);
1700     SendMessageA(hToolbar, TB_INSERTBUTTONA, 1, (LPARAM)&buttons3[3]);
1701     recalc = did_recalc(hToolbar);
1702     ok(recalc, "Expected a recalc - adding button with text\n");
1703 
1704     /* TB_SETBUTTONINFOA, even when adding a text, results only in a relayout */
1705     prepare_recalc_test(&hToolbar);
1706     bi.cbSize = sizeof(bi);
1707     bi.dwMask = TBIF_TEXT;
1708     bi.pszText = test;
1709     SendMessageA(hToolbar, TB_SETBUTTONINFOA, 1, (LPARAM)&bi);
1710     recalc = did_recalc(hToolbar);
1711     ok(!recalc, "Unexpected recalc - setting a button text\n");
1712 
1713     /* most extended styled doesn't force a recalc (testing all the bits gives
1714      * the same results, but prints some ERRs while testing) */
1715     for (i = 0; i < EX_STYLES_COUNT; i++)
1716     {
1717         if (i == 1 || i == 3)  /* an undoc style and TBSTYLE_EX_MIXEDBUTTONS */
1718             continue;
1719         prepare_recalc_test(&hToolbar);
1720         expect(0, (int)SendMessageA(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
1721         SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, (1 << i));
1722         recalc = did_recalc(hToolbar);
1723         ok(!recalc, "Unexpected recalc - setting bit %d\n", i);
1724         SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
1725         recalc = did_recalc(hToolbar);
1726         ok(!recalc, "Unexpected recalc - clearing bit %d\n", i);
1727         expect(0, (int)SendMessageA(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
1728     }
1729 
1730     /* TBSTYLE_EX_MIXEDBUTTONS does a recalc on change */
1731     prepare_recalc_test(&hToolbar);
1732     SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1733     recalc = did_recalc(hToolbar);
1734     if (recalc)
1735     {
1736         ok(recalc, "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n");
1737         restore_recalc_state(hToolbar);
1738         SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1739         recalc = did_recalc(hToolbar);
1740         ok(!recalc, "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n");
1741         restore_recalc_state(hToolbar);
1742         SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
1743         recalc = did_recalc(hToolbar);
1744         ok(recalc, "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n");
1745     }
1746     else win_skip( "No recalc on TBSTYLE_EX_MIXEDBUTTONS\n" );
1747 
1748     /* undocumented exstyle 0x2 seems to change the top margin, which
1749      * interferes with these tests */
1750 
1751     /* Show that a change in TBSTYLE_WRAPABLE causes a recalc */
1752     prepare_recalc_test(&hToolbar);
1753     style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0);
1754     SendMessageA(hToolbar, TB_SETSTYLE, 0, style);
1755     recalc = did_recalc(hToolbar);
1756     ok(!recalc, "recalc %d\n", recalc);
1757 
1758     SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | CCS_BOTTOM);
1759     recalc = did_recalc(hToolbar);
1760     ok(!recalc, "recalc %d\n", recalc);
1761 
1762     SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_WRAPABLE);
1763     recalc = did_recalc(hToolbar);
1764     ok(recalc, "recalc %d\n", recalc);
1765     restore_recalc_state(hToolbar);
1766 
1767     SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_WRAPABLE);
1768     recalc = did_recalc(hToolbar);
1769     ok(!recalc, "recalc %d\n", recalc);
1770 
1771     SendMessageA(hToolbar, TB_SETSTYLE, 0, style);
1772     recalc = did_recalc(hToolbar);
1773     ok(recalc, "recalc %d\n", recalc);
1774     restore_recalc_state(hToolbar);
1775 
1776     /* Changing CCS_VERT does not recalc */
1777     SendMessageA(hToolbar, TB_SETSTYLE, 0, style | CCS_VERT);
1778     recalc = did_recalc(hToolbar);
1779     ok(!recalc, "recalc %d\n", recalc);
1780     restore_recalc_state(hToolbar);
1781 
1782     SendMessageA(hToolbar, TB_SETSTYLE, 0, style);
1783     recalc = did_recalc(hToolbar);
1784     ok(!recalc, "recalc %d\n", recalc);
1785     restore_recalc_state(hToolbar);
1786 
1787     /* Setting the window's style directly also causes recalc */
1788     SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE);
1789     recalc = did_recalc(hToolbar);
1790     ok(recalc, "recalc %d\n", recalc);
1791 
1792     DestroyWindow(hToolbar);
1793 }
1794 
test_getbuttoninfo(void)1795 static void test_getbuttoninfo(void)
1796 {
1797     HWND hToolbar = NULL;
1798     TBBUTTONINFOW tbiW;
1799     TBBUTTONINFOA tbi;
1800     int i;
1801 
1802     rebuild_toolbar_with_buttons(&hToolbar);
1803     for (i = 0; i < 128; i++)
1804     {
1805         int ret;
1806 
1807         tbi.cbSize = i;
1808         tbi.dwMask = TBIF_COMMAND;
1809         ret = (int)SendMessageA(hToolbar, TB_GETBUTTONINFOA, 1, (LPARAM)&tbi);
1810         if (i == sizeof(TBBUTTONINFOA)) {
1811             compare(ret, 0, "%d");
1812         } else {
1813             compare(ret, -1, "%d");
1814         }
1815     }
1816 
1817     /* TBIF_TEXT with NULL pszText */
1818     memset(&tbiW, 0, sizeof(tbiW));
1819     tbiW.cbSize = sizeof(tbiW);
1820     tbiW.dwMask = TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_TEXT;
1821     i = SendMessageA(hToolbar, TB_GETBUTTONINFOW, 1, (LPARAM)&tbiW);
1822     ok(i == 1, "Got index %d\n", i);
1823 
1824     DestroyWindow(hToolbar);
1825 }
1826 
test_createtoolbarex(void)1827 static void test_createtoolbarex(void)
1828 {
1829     HWND hToolbar;
1830     TBBUTTON btns[3];
1831     ZeroMemory(&btns, sizeof(btns));
1832 
1833     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1834         3, 20, 20, 16, 16, sizeof(TBBUTTON));
1835     CHECK_IMAGELIST(16, 20, 20);
1836     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x");
1837     DestroyWindow(hToolbar);
1838 
1839     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1840         3, 4, 4, 16, 16, sizeof(TBBUTTON));
1841     CHECK_IMAGELIST(32, 4, 4);
1842     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x");
1843     DestroyWindow(hToolbar);
1844 
1845     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1846         3, 0, 8, 12, 12, sizeof(TBBUTTON));
1847     CHECK_IMAGELIST(16, 12, 12);
1848     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x");
1849     DestroyWindow(hToolbar);
1850 
1851     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1852         3, -1, 8, 12, 12, sizeof(TBBUTTON));
1853     CHECK_IMAGELIST(16, 12, 8);
1854     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x");
1855     DestroyWindow(hToolbar);
1856 
1857     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1858         3, -1, 8, -1, 12, sizeof(TBBUTTON));
1859     CHECK_IMAGELIST(16, 16, 8);
1860     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x");
1861     DestroyWindow(hToolbar);
1862 
1863     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1864         3, 0, 0, 12, -1, sizeof(TBBUTTON));
1865     CHECK_IMAGELIST(16, 12, 16);
1866     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x");
1867     DestroyWindow(hToolbar);
1868 
1869     hToolbar = pCreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandleA(NULL), IDB_BITMAP_128x15, btns,
1870         3, 0, 0, 0, 12, sizeof(TBBUTTON));
1871     CHECK_IMAGELIST(16, 16, 16);
1872     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x");
1873     DestroyWindow(hToolbar);
1874 }
1875 
test_dispinfo(void)1876 static void test_dispinfo(void)
1877 {
1878     HWND hToolbar = NULL;
1879     const TBBUTTON buttons_disp[] = {
1880         {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1881         {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1882     };
1883     BOOL ret;
1884 
1885     rebuild_toolbar(&hToolbar);
1886     SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
1887     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons_disp);
1888     g_dwExpectedDispInfoMask = TBNF_IMAGE;
1889     /* Some TBN_GETDISPINFO tests will be done in MyWnd_Notify function.
1890      * We will receive TBN_GETDISPINFOW even if the control is ANSI */
1891     compare((BOOL)SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0, "%d");
1892     ShowWindow(hToolbar, SW_SHOW);
1893     UpdateWindow(hToolbar);
1894 
1895     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, TRUE, 0);
1896     compare(ret, FALSE, "%d");
1897     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 1L, "%ld");
1898     InvalidateRect(hToolbar, NULL, FALSE);
1899     UpdateWindow(hToolbar);
1900 
1901     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
1902     compare(ret, TRUE, "%d");
1903     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0L, "%ld");
1904     InvalidateRect(hToolbar, NULL, FALSE);
1905     UpdateWindow(hToolbar);
1906 
1907     DestroyWindow(hToolbar);
1908     g_dwExpectedDispInfoMask = 0;
1909 }
1910 
1911 typedef struct
1912 {
1913     int  nRows;
1914     BOOL bLarger;
1915     int  expectedRows;
1916 } tbrows_result_t;
1917 
1918 static tbrows_result_t tbrows_results[] =
1919 {
1920     {1, TRUE,  1}, /* 0: Simple case 9 in a row */
1921     {2, TRUE,  2}, /* 1: Another simple case 5 on one row, 4 on another*/
1922     {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */
1923     {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */
1924     {8, TRUE,  9}, /* 4: 8 lines but grow - should be 9 lines */
1925     {1, TRUE,  1}  /* 5: Back to simple case */
1926 };
1927 
test_setrows(void)1928 static void test_setrows(void)
1929 {
1930     TBBUTTON buttons[9];
1931     HWND hToolbar;
1932     DWORD i;
1933 
1934     for (i=0; i<9; i++)
1935         MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0);
1936 
1937     /* Test 1 - 9 buttons */
1938     hToolbar = pCreateToolbarEx(hMainWnd,
1939         WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN
1940         | CCS_NOMOVEY | CCS_TOP,
1941         0,
1942         0, NULL, 0,
1943         buttons, ARRAY_SIZE(buttons),
1944         20, 20, 0, 0, sizeof(TBBUTTON));
1945     ok(hToolbar != NULL, "Toolbar creation\n");
1946     ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
1947 
1948     /* test setting rows to each of 1-10 with bLarger true and false */
1949     for (i=0; i<ARRAY_SIZE(tbrows_results); i++) {
1950         RECT rc;
1951         int rows;
1952 
1953         memset(&rc, 0xCC, sizeof(rc));
1954         SendMessageA(hToolbar, TB_SETROWS,
1955                      MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger),
1956                      (LPARAM) &rc);
1957 
1958         rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0));
1959         ok(rows == tbrows_results[i].expectedRows,
1960                    "[%d] Unexpected number of rows %d (expected %d)\n", i, rows,
1961                    tbrows_results[i].expectedRows);
1962     }
1963 
1964     DestroyWindow(hToolbar);
1965 }
1966 
test_getstring(void)1967 static void test_getstring(void)
1968 {
1969     HWND hToolbar = NULL;
1970     char str[10];
1971     WCHAR strW[10];
1972     static const char answer[] = "STR";
1973     static const WCHAR answerW[] = { 'S','T','R',0 };
1974     INT r;
1975 
1976     hToolbar = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
1977     ok(hToolbar != NULL, "Toolbar creation problem\n");
1978 
1979     r = SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(0, 0), 0);
1980     if (r == 0)
1981     {
1982         win_skip("TB_GETSTRINGA and TB_GETSTRINGW need 5.80\n");
1983         DestroyWindow(hToolbar);
1984         return;
1985     }
1986     expect(-1, r);
1987     r = SendMessageW(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1988     expect(-1, r);
1989     r = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)answer);
1990     expect(0, r);
1991     r = SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(0, 0), 0);
1992     expect(lstrlenA(answer), r);
1993     r = SendMessageW(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1994     expect(lstrlenA(answer), r);
1995     r = SendMessageA(hToolbar, TB_GETSTRINGA, MAKEWPARAM(sizeof(str), 0), (LPARAM)str);
1996     expect(lstrlenA(answer), r);
1997     expect(0, lstrcmpA(answer, str));
1998     r = SendMessageW(hToolbar, TB_GETSTRINGW, MAKEWPARAM(sizeof(strW), 0), (LPARAM)strW);
1999     expect(lstrlenA(answer), r);
2000     expect(0, lstrcmpW(answerW, strW));
2001 
2002     DestroyWindow(hToolbar);
2003 }
2004 
test_tooltip(void)2005 static void test_tooltip(void)
2006 {
2007     HWND hToolbar = NULL;
2008     const TBBUTTON buttons_disp[] = {
2009         {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
2010         {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
2011     };
2012     NMTTDISPINFOW nmtti;
2013     HWND tooltip;
2014 
2015     rebuild_toolbar(&hToolbar);
2016 
2017     SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons_disp);
2018 
2019     /* W used to get through toolbar code that assumes tooltip is always Unicode */
2020     memset(&nmtti, 0, sizeof(nmtti));
2021     nmtti.hdr.code = TTN_GETDISPINFOW;
2022     nmtti.hdr.idFrom = 20;
2023 
2024     SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
2025 
2026     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2027     SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
2028     ok_sequence(sequences, PARENT_SEQ_INDEX, ttgetdispinfo_parent_seq,
2029                 "dispinfo from tooltip", FALSE);
2030 
2031     g_ResetDispTextPtr = TRUE;
2032     SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
2033     /* Same for TBN_GETINFOTIPW */
2034     SendMessageA(hToolbar, TB_SETUNICODEFORMAT, TRUE, 0);
2035     SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
2036     g_ResetDispTextPtr = FALSE;
2037 
2038     DestroyWindow(hToolbar);
2039 
2040     /* TBSTYLE_TOOLTIPS */
2041     hToolbar = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
2042         hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
2043     tooltip = (HWND)SendMessageA(hToolbar, TB_GETTOOLTIPS, 0, 0);
2044     ok(tooltip == NULL, "got %p\n", tooltip);
2045     DestroyWindow(hToolbar);
2046 }
2047 
test_get_set_style(void)2048 static void test_get_set_style(void)
2049 {
2050     TBBUTTON buttons[9];
2051     DWORD style, style2, ret;
2052     HWND hToolbar;
2053     int i;
2054 
2055     for (i=0; i<9; i++)
2056         MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
2057     MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
2058     MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
2059 
2060     hToolbar = pCreateToolbarEx(hMainWnd,
2061         WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
2062         WS_CHILD | TBSTYLE_LIST,
2063         100,
2064         0, NULL, 0,
2065         buttons, ARRAY_SIZE(buttons),
2066         0, 0, 20, 16, sizeof(TBBUTTON));
2067     ok(hToolbar != NULL, "Toolbar creation\n");
2068     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
2069 
2070     style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0);
2071     style2 = GetWindowLongA(hToolbar, GWL_STYLE);
2072 todo_wine
2073     ok(style == style2, "got 0x%08x, expected 0x%08x\n", style, style2);
2074 
2075     /* try to alter common window bits */
2076     style2 |= WS_BORDER;
2077     ret = SendMessageA(hToolbar, TB_SETSTYLE, 0, style2);
2078     ok(ret == 0, "got %d\n", ret);
2079     style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0);
2080     style2 = GetWindowLongA(hToolbar, GWL_STYLE);
2081     ok((style != style2) && (style == (style2 | WS_BORDER)),
2082         "got 0x%08x, expected 0x%08x\n", style, style2);
2083     ok(style & WS_BORDER, "got 0x%08x\n", style);
2084 
2085     /* now styles are the same, alter window style */
2086     ret = SendMessageA(hToolbar, TB_SETSTYLE, 0, style2);
2087     ok(ret == 0, "got %d\n", ret);
2088     style2 |= WS_BORDER;
2089     SetWindowLongA(hToolbar, GWL_STYLE, style2);
2090     style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0);
2091     ok(style == style2, "got 0x%08x, expected 0x%08x\n", style, style2);
2092 
2093     DestroyWindow(hToolbar);
2094 }
2095 
2096 static HHOOK g_tbhook;
2097 static HWND g_toolbar;
2098 
2099 DEFINE_EXPECT(g_hook_create);
2100 DEFINE_EXPECT(g_hook_WM_NCCREATE);
2101 DEFINE_EXPECT(g_hook_WM_CREATE);
2102 
toolbar_subclass_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)2103 static LRESULT WINAPI toolbar_subclass_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2104 {
2105     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
2106     LRESULT ret;
2107     DWORD style;
2108 
2109     if (msg == WM_NCCREATE)
2110     {
2111         if (g_toolbar == hwnd)
2112         {
2113             CHECK_EXPECT2(g_hook_WM_NCCREATE);
2114             g_toolbar = hwnd;
2115             ret = CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
2116 
2117             /* control is already set up */
2118             style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
2119             ok(style != 0, "got %x\n", style);
2120 
2121             style = GetWindowLongA(hwnd, GWL_STYLE);
2122             ok((style & TBSTYLE_TOOLTIPS) == 0, "got 0x%08x\n", style);
2123             SetWindowLongA(hwnd, GWL_STYLE, style|TBSTYLE_TOOLTIPS);
2124             style = GetWindowLongA(hwnd, GWL_STYLE);
2125             ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
2126 
2127             return ret;
2128         }
2129     }
2130     else if (msg == WM_CREATE)
2131     {
2132         CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
2133 
2134         if (g_toolbar == hwnd)
2135         {
2136             CHECK_EXPECT2(g_hook_WM_CREATE);
2137 
2138             style = GetWindowLongA(hwnd, GWL_STYLE);
2139             ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
2140 
2141             /* test if toolbar-specific messages are already working before WM_CREATE */
2142             style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
2143             ok(style != 0, "got %x\n", style);
2144             ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%x\n", style);
2145             ok((cs->style & TBSTYLE_TOOLTIPS) == 0, "0x%08x\n", cs->style);
2146 
2147             ret = CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
2148 
2149             style = GetWindowLongA(hwnd, GWL_STYLE);
2150             ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
2151 
2152             /* test if toolbar-specific messages are already working before WM_CREATE */
2153             style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
2154             ok(style != 0, "got %x\n", style);
2155             ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%x\n", style);
2156 
2157             return ret;
2158         }
2159     }
2160 
2161     return CallWindowProcA(oldproc, hwnd, msg, wParam, lParam);
2162 }
2163 
cbt_hook_proc(int code,WPARAM wParam,LPARAM lParam)2164 static LRESULT CALLBACK cbt_hook_proc(int code, WPARAM wParam, LPARAM lParam)
2165 {
2166     if (code == HCBT_CREATEWND)
2167     {
2168         HWND hwnd = (HWND)wParam;
2169 
2170         if (!g_toolbar)
2171         {
2172             WNDPROC oldproc;
2173 
2174             CHECK_EXPECT2(g_hook_create);
2175             g_toolbar = hwnd;
2176             /* subclass */
2177             oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)toolbar_subclass_proc);
2178             SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
2179         }
2180         return 0;
2181     }
2182 
2183     return CallNextHookEx(g_tbhook, code, wParam, lParam);
2184 }
2185 
test_create(void)2186 static void test_create(void)
2187 {
2188     HWND hwnd, tooltip;
2189     DWORD style;
2190 
2191     g_tbhook = SetWindowsHookA(WH_CBT, cbt_hook_proc);
2192 
2193     SET_EXPECT(g_hook_create);
2194     SET_EXPECT(g_hook_WM_NCCREATE);
2195     SET_EXPECT(g_hook_WM_CREATE);
2196 
2197     hwnd = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
2198         hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
2199 
2200     CHECK_CALLED(g_hook_create);
2201     CHECK_CALLED(g_hook_WM_NCCREATE);
2202     CHECK_CALLED(g_hook_WM_CREATE);
2203 
2204     style = GetWindowLongA(hwnd, GWL_STYLE);
2205     ok((style & TBSTYLE_TOOLTIPS) == TBSTYLE_TOOLTIPS, "got 0x%08x\n", style);
2206 
2207     tooltip = (HWND)SendMessageA(hwnd, TB_GETTOOLTIPS, 0, 0);
2208     ok(tooltip != NULL, "got %p\n", tooltip);
2209     ok(GetParent(tooltip) == hMainWnd, "got %p, %p\n", hMainWnd, hwnd);
2210 
2211     DestroyWindow(hwnd);
2212     UnhookWindowsHook(WH_CBT, cbt_hook_proc);
2213 
2214     /* TBSTYLE_TRANSPARENT */
2215     hwnd = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL,
2216         WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|TBSTYLE_FLAT|TBSTYLE_TOOLTIPS|TBSTYLE_GROUP,
2217         0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
2218 
2219     style = GetWindowLongA(hwnd, GWL_STYLE);
2220     ok((style & TBSTYLE_TRANSPARENT) == TBSTYLE_TRANSPARENT, "got 0x%08x\n", style);
2221 
2222     style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
2223     ok((style & TBSTYLE_TRANSPARENT) == TBSTYLE_TRANSPARENT, "got 0x%08x\n", style);
2224 
2225     DestroyWindow(hwnd);
2226 }
2227 
2228 typedef struct {
2229     DWORD mask;
2230     DWORD style;
2231     DWORD style_set;
2232 } extended_style_t;
2233 
2234 static const extended_style_t extended_style_test[] = {
2235     {
2236       TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER,
2237       TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER,
2238       TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER
2239     },
2240     {
2241       TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS,
2242       TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS
2243     },
2244 
2245     { 0, TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS },
2246     { 0, 0, 0 },
2247     { 0, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS },
2248     { 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS, TBSTYLE_EX_HIDECLIPPEDBUTTONS },
2249 
2250     { 0, 0, 0 },
2251     { TBSTYLE_EX_HIDECLIPPEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS, 0 },
2252     { TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_HIDECLIPPEDBUTTONS, 0 },
2253     { TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_MIXEDBUTTONS, 0 },
2254 
2255     {
2256       TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS,
2257       TBSTYLE_EX_MIXEDBUTTONS, TBSTYLE_EX_MIXEDBUTTONS
2258     },
2259     {
2260       TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS,
2261       TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_DOUBLEBUFFER
2262     }
2263 };
2264 
test_TB_GET_SET_EXTENDEDSTYLE(void)2265 static void test_TB_GET_SET_EXTENDEDSTYLE(void)
2266 {
2267     DWORD style, oldstyle, oldstyle2;
2268     const extended_style_t *ptr;
2269     HWND hwnd = NULL;
2270     int i;
2271 
2272     rebuild_toolbar(&hwnd);
2273 
2274     SendMessageA(hwnd, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_MIXEDBUTTONS);
2275     style = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
2276     if (style == TBSTYLE_EX_MIXEDBUTTONS)
2277     {
2278         win_skip("Some extended style bits are not supported\n");
2279         DestroyWindow(hwnd);
2280         return;
2281     }
2282 
2283     for (i = 0; i < ARRAY_SIZE(extended_style_test); i++)
2284     {
2285         ptr = &extended_style_test[i];
2286 
2287         oldstyle2 = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
2288 
2289         oldstyle = SendMessageA(hwnd, TB_SETEXTENDEDSTYLE, ptr->mask, ptr->style);
2290         ok(oldstyle == oldstyle2, "%d: got old style 0x%08x, expected 0x%08x\n", i, oldstyle, oldstyle2);
2291         style = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
2292         ok(style == ptr->style_set, "%d: got style 0x%08x, expected 0x%08x\n", i, style, ptr->style_set);
2293     }
2294 
2295     /* Windows sets CCS_VERT when TB_GETEXTENDEDSTYLE is set */
2296     oldstyle2 = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
2297     oldstyle = SendMessageA(hwnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_VERTICAL);
2298     ok(oldstyle == oldstyle2, "got old style 0x%08x, expected 0x%08x\n", oldstyle, oldstyle2);
2299     style = SendMessageA(hwnd, TB_GETEXTENDEDSTYLE, 0, 0);
2300     ok(style == TBSTYLE_EX_VERTICAL, "got style 0x%08x, expected 0x%08x\n", style, TBSTYLE_EX_VERTICAL);
2301     style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0);
2302  todo_wine
2303     ok(style == CCS_VERT, "got style 0x%08x, expected CCS_VERT\n", style);
2304 
2305     DestroyWindow(hwnd);
2306 }
2307 
test_noresize(void)2308 static void test_noresize(void)
2309 {
2310     HWND wnd;
2311     int i;
2312     TBBUTTON button = {0, 10, TBSTATE_ENABLED, 0, {0, }, 0, -1};
2313 
2314     wnd = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE | TBSTYLE_WRAPABLE, 0, 0, 100, 20,
2315                           hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL);
2316     SendMessageA(wnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
2317 
2318     for (i=0; i<30; i++)
2319     {
2320         button.idCommand = 10 + i;
2321         SendMessageA(wnd, TB_ADDBUTTONSA, 1, (LPARAM)&button);
2322     }
2323 
2324     SendMessageA(wnd, TB_SETSTATE, 10, TBSTATE_WRAP|TBSTATE_ENABLED);
2325 
2326     /* autosize clears the wrap on button 0 */
2327     SendMessageA(wnd, TB_AUTOSIZE, 0, 0);
2328     for (i=0; i<30; i++)
2329     {
2330         SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button);
2331         if (i % 4 == 3)
2332             ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState);
2333         else
2334             ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState);
2335     }
2336 
2337     /* changing the parent doesn't do anything */
2338     MoveWindow(hMainWnd, 0,0, 400, 200, FALSE);
2339     for (i=0; i<30; i++)
2340     {
2341         SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button);
2342         if (i % 4 == 3)
2343             ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState);
2344         else
2345             ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState);
2346     }
2347 
2348     /* again nothing here */
2349     SendMessageA(wnd, TB_AUTOSIZE, 0, 0);
2350     for (i=0; i<30; i++)
2351     {
2352         SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button);
2353         if (i % 4 == 3)
2354             ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState);
2355         else
2356             ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState);
2357     }
2358 
2359     DestroyWindow(wnd);
2360 
2361 }
2362 
test_save(void)2363 static void test_save(void)
2364 {
2365     HWND wnd = NULL;
2366     TBSAVEPARAMSW params;
2367     static const WCHAR subkey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
2368                                    'W','i','n','e','T','e','s','t',0};
2369     static const WCHAR value[] = {'t','o','o','l','b','a','r','t','e','s','t',0};
2370     LONG res;
2371     HKEY key;
2372     BYTE data[100];
2373     DWORD size = sizeof(data), type, i, count;
2374     TBBUTTON tb;
2375     static const TBBUTTON more_btns[2] =
2376         {
2377             {0, 11, TBSTATE_HIDDEN, BTNS_BUTTON, {0}, 0, -1},
2378             {0, 13, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, -1}
2379         };
2380     static const DWORD expect[] = {0xcafe, 1, 0xcafe0000, 3, 0xcafe0001, 5, 0xcafe0002, 7, 0xcafe0003,
2381                                    9, 0xcafe0004, 11, 0xcafe0005, 13, 0xcafe0006, 0xffffffff, 0xcafe0007,
2382                                    0xfffffffe, 0xcafe0008, 0x80000000, 0xcafe0009, 0x7fffffff, 0xcafe000a,
2383                                    0x100, 0xcafe000b};
2384     static const TBBUTTON expect_btns[] =
2385     {
2386         {0, 1, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
2387         {0, 3, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 1, 2},
2388         {0, 5, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 2, 0},
2389         {0, 7, 0, BTNS_BUTTON, {0}, 0, (INT_PTR)"foo"},
2390         {0, 9, 0, BTNS_BUTTON, {0}, 0, 0},
2391         {0, 11, 0, BTNS_BUTTON, {0}, 0, 3},
2392         {0, 13, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 6, 0},
2393         {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 7, 0},
2394         {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 8, 0},
2395         {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 9, 0},
2396         {0, 0x7fffffff, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0xa, 0},
2397     };
2398 
2399     params.hkr = HKEY_CURRENT_USER;
2400     params.pszSubKey = subkey;
2401     params.pszValueName = value;
2402 
2403     rebuild_toolbar_with_buttons( &wnd );
2404     SendMessageW(wnd, TB_ADDBUTTONSW, ARRAY_SIZE(more_btns), (LPARAM)more_btns);
2405 
2406     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2407     res = SendMessageW( wnd, TB_SAVERESTOREW, TRUE, (LPARAM)&params );
2408     ok( res, "saving failed\n" );
2409     ok_sequence(sequences, PARENT_SEQ_INDEX, save_parent_seq, "save", FALSE);
2410     DestroyWindow( wnd );
2411 
2412     res = RegOpenKeyW( HKEY_CURRENT_USER, subkey, &key );
2413     ok( !res, "got %08x\n", res );
2414     res = RegQueryValueExW( key, value, NULL, &type, data, &size );
2415     ok( !res, "got %08x\n", res );
2416     ok( type == REG_BINARY, "got %08x\n", type );
2417     ok( size == sizeof(expect), "got %08x\n", size );
2418     ok( !memcmp( data, expect, size ), "mismatch\n" );
2419 
2420     RegCloseKey( key );
2421 
2422     wnd = NULL;
2423     rebuild_toolbar( &wnd );
2424 
2425     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2426     res = SendMessageW( wnd, TB_SAVERESTOREW, FALSE, (LPARAM)&params );
2427     ok( res, "restoring failed\n" );
2428     ok_sequence(sequences, PARENT_SEQ_INDEX, restore_parent_seq, "restore", FALSE);
2429     count = SendMessageW( wnd, TB_BUTTONCOUNT, 0, 0 );
2430     ok( count == ARRAY_SIZE(expect_btns), "got %d\n", count );
2431 
2432     for (i = 0; i < count; i++)
2433     {
2434         res = SendMessageW( wnd, TB_GETBUTTON, i, (LPARAM)&tb );
2435         ok( res, "got %d\n", res );
2436 
2437         ok( tb.iBitmap == expect_btns[i].iBitmap, "%d: got %d\n", i, tb.iBitmap );
2438         ok( tb.idCommand == expect_btns[i].idCommand, "%d: got %d\n", i, tb.idCommand );
2439         ok( tb.fsState == expect_btns[i].fsState, "%d: got %02x\n", i, tb.fsState );
2440         ok( tb.fsStyle == expect_btns[i].fsStyle, "%d: got %02x\n", i, tb.fsStyle );
2441         ok( tb.dwData == expect_btns[i].dwData, "%d: got %lx\n", i, tb.dwData );
2442         if (IS_INTRESOURCE(expect_btns[i].iString))
2443             ok( tb.iString == expect_btns[i].iString, "%d: got %lx\n", i, tb.iString );
2444         else
2445             ok( !strcmp( (char *)tb.iString, (char *)expect_btns[i].iString ),
2446                 "%d: got %s\n", i, (char *)tb.iString );
2447 
2448         /* In fact the ptr value set in TBN_GETBUTTONINFOA is simply copied */
2449         if (tb.idCommand == 7)
2450             ok( tb.iString == (INT_PTR)alloced_str, "string not set\n");
2451     }
2452 
2453     DestroyWindow( wnd );
2454     RegOpenKeyW( HKEY_CURRENT_USER, subkey, &key );
2455     RegDeleteValueW( key, value );
2456     RegCloseKey( key );
2457 }
2458 
test_drawtext_flags(void)2459 static void test_drawtext_flags(void)
2460 {
2461     HWND hwnd = NULL;
2462     UINT flags;
2463 
2464     rebuild_toolbar(&hwnd);
2465 
2466     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, 0, 0);
2467 todo_wine
2468     ok(flags == 0, "Unexpected draw text flags %#x\n", flags);
2469 
2470     /* zero mask, flags are retained */
2471     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, 0, DT_BOTTOM);
2472 todo_wine
2473     ok(flags == 0, "Unexpected draw text flags %#x\n", flags);
2474     ok(!(flags & DT_BOTTOM), "Unexpected DT_BOTTOM style\n");
2475 
2476     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, 0, 0);
2477 todo_wine
2478     ok(flags == 0, "Unexpected draw text flags %#x\n", flags);
2479     ok(!(flags & DT_BOTTOM), "Unexpected DT_BOTTOM style\n");
2480 
2481     /* set/remove */
2482     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, DT_BOTTOM, DT_BOTTOM);
2483 todo_wine
2484     ok(flags == 0, "Unexpected draw text flags %#x\n", flags);
2485     ok(!(flags & DT_BOTTOM), "Unexpected DT_BOTTOM style\n");
2486 
2487     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, DT_BOTTOM, 0);
2488 todo_wine
2489     ok(flags == DT_BOTTOM, "Unexpected draw text flags %#x\n", flags);
2490     ok(flags & DT_BOTTOM, "Expected DT_BOTTOM style, %#x\n", flags);
2491 
2492     flags = SendMessageA(hwnd, TB_SETDRAWTEXTFLAGS, DT_BOTTOM, 0);
2493 todo_wine
2494     ok(flags == 0, "Unexpected draw text flags %#x\n", flags);
2495     ok(!(flags & DT_BOTTOM), "Unexpected DT_BOTTOM style\n");
2496 
2497     DestroyWindow(hwnd);
2498 }
2499 
test_imagelist(void)2500 static void test_imagelist(void)
2501 {
2502     HIMAGELIST imagelist;
2503     HWND hwnd = NULL;
2504     int ret;
2505 
2506     rebuild_toolbar(&hwnd);
2507 
2508     imagelist = (HIMAGELIST)SendMessageA(hwnd, TB_GETIMAGELIST, 0, 0);
2509     ok(imagelist == NULL, "got %p\n", imagelist);
2510 
2511     ret = SendMessageA(hwnd, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
2512     ok(ret, "got %d\n", ret);
2513 
2514     imagelist = (HIMAGELIST)SendMessageA(hwnd, TB_GETIMAGELIST, 0, 0);
2515     ok(imagelist == NULL, "got %p\n", imagelist);
2516 
2517     DestroyWindow(hwnd);
2518 }
2519 
init_functions(void)2520 static void init_functions(void)
2521 {
2522     HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
2523 
2524 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
2525     X(CreateToolbarEx);
2526     X(ImageList_GetIconSize);
2527     X(ImageList_GetImageCount);
2528     X(ImageList_LoadImageA);
2529     X(ImageList_Destroy);
2530 #undef X
2531 }
2532 
START_TEST(toolbar)2533 START_TEST(toolbar)
2534 {
2535     WNDCLASSA wc;
2536     MSG msg;
2537     RECT rc;
2538 
2539     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2540     init_functions();
2541 
2542     wc.style = CS_HREDRAW | CS_VREDRAW;
2543     wc.cbClsExtra = 0;
2544     wc.cbWndExtra = 0;
2545     wc.hInstance = GetModuleHandleA(NULL);
2546     wc.hIcon = NULL;
2547     wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_IBEAM);
2548     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2549     wc.lpszMenuName = NULL;
2550     wc.lpszClassName = "Toolbar test parent";
2551     wc.lpfnWndProc = parent_wnd_proc;
2552     RegisterClassA(&wc);
2553 
2554     hMainWnd = CreateWindowExA(0, "Toolbar test parent", "Blah", WS_OVERLAPPEDWINDOW,
2555       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
2556     GetClientRect(hMainWnd, &rc);
2557     ShowWindow(hMainWnd, SW_SHOW);
2558 
2559     basic_test();
2560     test_add_bitmap();
2561     test_add_string();
2562     test_hotitem();
2563     test_sizes();
2564     test_recalc();
2565     test_getbuttoninfo();
2566     test_createtoolbarex();
2567     test_dispinfo();
2568     test_setrows();
2569     test_getstring();
2570     test_tooltip();
2571     test_get_set_style();
2572     test_create();
2573     test_TB_GET_SET_EXTENDEDSTYLE();
2574     test_noresize();
2575     test_save();
2576     test_drawtext_flags();
2577     test_imagelist();
2578 
2579     PostQuitMessage(0);
2580     while(GetMessageA(&msg,0,0,0)) {
2581         TranslateMessage(&msg);
2582         DispatchMessageA(&msg);
2583     }
2584     DestroyWindow(hMainWnd);
2585 }
2586