comctl32: toolbar: TB_SETBUTTONINFO should do a relayout instead of a recalc.
[wine] / dlls / comctl32 / tests / toolbar.c
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 <assert.h>
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "commctrl.h" 
31
32 #include "resources.h"
33
34 #include "wine/test.h"
35
36 static HWND hMainWnd;
37 static BOOL g_fBlockHotItemChange;
38 static BOOL g_fReceivedHotItemChange;
39 static BOOL g_fExpectedHotItemOld;
40 static BOOL g_fExpectedHotItemNew;
41 static DWORD g_dwExpectedDispInfoMask;
42
43 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
44
45 #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
46     val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
47     val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
48  
49 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
50
51 static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
52   p->iBitmap = -2;
53   p->idCommand = idCommand;
54   p->fsState = TBSTATE_ENABLED;
55   p->fsStyle = fsStyle;
56   p->iString = nString;
57 }
58
59 static LRESULT MyWnd_Notify(LPARAM lParam)
60 {
61     NMHDR *hdr = (NMHDR *)lParam;
62     NMTBHOTITEM *nmhi;
63     NMTBDISPINFO *nmdisp;
64     switch (hdr->code)
65     {
66         case TBN_HOTITEMCHANGE:
67             nmhi = (NMTBHOTITEM *)lParam;
68             g_fReceivedHotItemChange = TRUE;
69             if (g_fExpectedHotItemOld != g_fExpectedHotItemNew)
70             {
71                 compare(nmhi->idOld, g_fExpectedHotItemOld, "%d");
72                 compare(nmhi->idNew, g_fExpectedHotItemNew, "%d");
73             }
74             if (g_fBlockHotItemChange)
75                 return 1;
76             break;
77
78         case TBN_GETDISPINFOA:
79             ok(FALSE, "TBN_GETDISPINFOA received\n");
80             break;
81
82         case TBN_GETDISPINFOW:
83             nmdisp = (NMTBDISPINFOA *)lParam;
84
85             compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x");
86             compare(nmdisp->iImage, -1, "%d");
87             ok(nmdisp->pszText == NULL, "pszText is not NULL\n");
88         break;
89     }
90     return 0;
91 }
92
93 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
94 {
95     switch (msg)
96     {
97         case WM_NOTIFY:
98             return MyWnd_Notify(lParam);
99     }
100     return DefWindowProcA(hWnd, msg, wParam, lParam);
101 }
102
103 static void basic_test(void)
104 {
105     TBBUTTON buttons[9];
106     HWND hToolbar;
107     int i;
108     for (i=0; i<9; i++)
109         MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
110     MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
111     MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
112
113     hToolbar = CreateToolbarEx(hMainWnd,
114         WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
115         WS_CHILD | TBSTYLE_LIST,
116         100,
117         0, NULL, 0,
118         buttons, sizeof(buttons)/sizeof(buttons[0]),
119         0, 0, 20, 16, sizeof(TBBUTTON));
120     ok(hToolbar != NULL, "Toolbar creation\n");
121     SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
122
123     /* test for exclusion working inside a separator-separated :-) group */
124     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
125     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
126     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
127
128     SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
129     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
130     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
131
132     SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
133     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
134     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
135
136     /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
137     SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
138     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
139     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
140     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
141
142     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
143     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
144     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
145     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
146
147     SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
148     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
149     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
150     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
151     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
152
153     /* tests with invalid index */
154     compare(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 0xdeadbeef, 0), -1L, "%ld");
155     compare(SendMessage(hToolbar, TB_ISBUTTONPRESSED, 0xdeadbeef, 0), -1L, "%ld");
156     compare(SendMessage(hToolbar, TB_ISBUTTONENABLED, 0xdeadbeef, 0), -1L, "%ld");
157     compare(SendMessage(hToolbar, TB_ISBUTTONINDETERMINATE, 0xdeadbeef, 0), -1L, "%ld");
158     compare(SendMessage(hToolbar, TB_ISBUTTONHIGHLIGHTED, 0xdeadbeef, 0), -1L, "%ld");
159     compare(SendMessage(hToolbar, TB_ISBUTTONHIDDEN, 0xdeadbeef, 0), -1L, "%ld");
160
161     DestroyWindow(hToolbar);
162 }
163
164 static void rebuild_toolbar(HWND *hToolbar)
165 {
166     if (*hToolbar != NULL)
167         DestroyWindow(*hToolbar);
168     *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
169         hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
170     ok(*hToolbar != NULL, "Toolbar creation problem\n");
171     ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
172     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
173     ok(SendMessage(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
174 }
175
176 static void rebuild_toolbar_with_buttons(HWND *hToolbar)
177 {
178     TBBUTTON buttons[5];
179     rebuild_toolbar(hToolbar);
180     
181     ZeroMemory(&buttons, sizeof(buttons));
182     buttons[0].idCommand = 1;
183     buttons[0].fsStyle = BTNS_BUTTON;
184     buttons[0].fsState = TBSTATE_ENABLED;
185     buttons[0].iString = -1;
186     buttons[1].idCommand = 3;
187     buttons[1].fsStyle = BTNS_BUTTON;
188     buttons[1].fsState = TBSTATE_ENABLED;
189     buttons[1].iString = -1;
190     buttons[2].idCommand = 5;
191     buttons[2].fsStyle = BTNS_SEP;
192     buttons[2].fsState = TBSTATE_ENABLED;
193     buttons[2].iString = -1;
194     buttons[3].idCommand = 7;
195     buttons[3].fsStyle = BTNS_BUTTON;
196     buttons[3].fsState = TBSTATE_ENABLED;
197     buttons[3].iString = -1;
198     buttons[4].idCommand = 9;
199     buttons[4].fsStyle = BTNS_BUTTON;
200     buttons[4].fsState = 0;  /* disabled */
201     buttons[4].iString = -1;
202     ok(SendMessage(*hToolbar, TB_ADDBUTTONS, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONS failed\n");
203     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
204 }
205
206 static void add_128x15_bitmap(HWND hToolbar, int nCmds)
207 {
208     TBADDBITMAP bmp128;
209     bmp128.hInst = GetModuleHandle(NULL);
210     bmp128.nID = IDB_BITMAP_128x15;
211     ok(SendMessageA(hToolbar, TB_ADDBITMAP, nCmds, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
212 }
213
214 #define CHECK_IMAGELIST(count, dx, dy) { \
215     int cx, cy; \
216     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
217     ok(himl != NULL, "No image list\n"); \
218     if (himl != NULL) {\
219         ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
220         ImageList_GetIconSize(himl, &cx, &cy); \
221         ok(cx == dx && cy == dy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
222     } \
223 }
224
225 static void test_add_bitmap(void)
226 {
227     HWND hToolbar = NULL;
228     TBADDBITMAP bmp128;
229     TBADDBITMAP bmp80;
230     TBADDBITMAP stdsmall;
231     TBADDBITMAP addbmp;
232     HIMAGELIST himl;
233     INT ret;
234
235     /* empty 128x15 bitmap */
236     bmp128.hInst = GetModuleHandle(NULL);
237     bmp128.nID = IDB_BITMAP_128x15;
238
239     /* empty 80x15 bitmap */
240     bmp80.hInst = GetModuleHandle(NULL);
241     bmp80.nID = IDB_BITMAP_80x15;
242
243     /* standard bitmap - 240x15 pixels */
244     stdsmall.hInst = HINST_COMMCTRL;
245     stdsmall.nID = IDB_STD_SMALL_COLOR;
246
247     rebuild_toolbar(&hToolbar);
248     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
249     CHECK_IMAGELIST(8, 16, 16);
250     
251     /* adding more bitmaps */
252     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n");
253     CHECK_IMAGELIST(13, 16, 16);
254     /* adding the same bitmap will simply return the index of the already loaded block */
255     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128);
256     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
257     CHECK_IMAGELIST(13, 16, 16);
258     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
259     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
260     CHECK_IMAGELIST(13, 16, 16);
261     /* even if we increase the wParam */
262     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80);
263     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
264     CHECK_IMAGELIST(13, 16, 16);
265
266     /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/
267     rebuild_toolbar(&hToolbar);
268     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
269     CHECK_IMAGELIST(8, 16, 16);
270     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
271     ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret);
272     /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */
273     CHECK_IMAGELIST(13, 16, 16);
274
275     /* the same for negative wParam */
276     rebuild_toolbar(&hToolbar);
277     ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128);
278     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
279     CHECK_IMAGELIST(8, 16, 16);
280     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
281     ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret);
282     CHECK_IMAGELIST(13, 16, 16);
283
284     /* for zero only one bitmap will be added */
285     rebuild_toolbar(&hToolbar);
286     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80);
287     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
288     CHECK_IMAGELIST(1, 16, 16);
289
290     /* if wParam is larger than the amount of icons, the list is grown */
291     rebuild_toolbar(&hToolbar);
292     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
293     CHECK_IMAGELIST(100, 16, 16);
294     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128);
295     ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret);
296     CHECK_IMAGELIST(200, 16, 16);
297
298     /* adding built-in items - the wParam is ignored */
299     rebuild_toolbar(&hToolbar);
300     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
301     CHECK_IMAGELIST(5, 16, 16);
302     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n");
303     CHECK_IMAGELIST(20, 16, 16);
304     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n");
305     CHECK_IMAGELIST(28, 16, 16);
306
307     /* when we increase the bitmap size, less icons will be created */
308     rebuild_toolbar(&hToolbar);
309     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n");
310     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
311     CHECK_IMAGELIST(6, 20, 20);
312     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
313     ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret);
314     CHECK_IMAGELIST(10, 20, 20);
315     /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */
316     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
317     UpdateWindow(hToolbar);
318     CHECK_IMAGELIST(26, 8, 8);
319     /* loading a standard bitmaps automatically resizes the icons */
320     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n");
321     UpdateWindow(hToolbar);
322     CHECK_IMAGELIST(28, 16, 16);
323
324     /* two more SETBITMAPSIZE tests */
325     rebuild_toolbar(&hToolbar);
326     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
327     CHECK_IMAGELIST(100, 16, 16);
328     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n");
329     CHECK_IMAGELIST(200, 16, 16);
330     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
331     UpdateWindow(hToolbar);
332     CHECK_IMAGELIST(200, 8, 8);
333     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
334     UpdateWindow(hToolbar);
335     CHECK_IMAGELIST(200, 30, 30);
336     rebuild_toolbar(&hToolbar);
337     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
338     CHECK_IMAGELIST(8, 16, 16);
339     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n");
340     CHECK_IMAGELIST(13, 16, 16);
341     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
342     UpdateWindow(hToolbar);
343     CHECK_IMAGELIST(8, 30, 30);
344     /* when the width or height is zero, set it to 1 */
345     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
346     UpdateWindow(hToolbar);
347     CHECK_IMAGELIST(208, 1, 1);
348     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 5)) == TRUE, "TB_SETBITMAPSIZE failed\n");
349     UpdateWindow(hToolbar);
350     CHECK_IMAGELIST(208, 1, 5);
351     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(5, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
352     UpdateWindow(hToolbar);
353     CHECK_IMAGELIST(41, 5, 1);
354
355     /* the control can add bitmaps to an existing image list */
356     rebuild_toolbar(&hToolbar);
357     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
358     ok(himl != NULL, "failed to create imagelist\n");
359     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
360     CHECK_IMAGELIST(4, 20, 15);
361     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
362     CHECK_IMAGELIST(10, 20, 15);
363     /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change) */
364     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
365     UpdateWindow(hToolbar);
366     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(15, 14), "%x");
367     CHECK_IMAGELIST(10, 20, 15);
368     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n");
369     UpdateWindow(hToolbar);
370     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
371     CHECK_IMAGELIST(22, 20, 15);
372
373     /* check standard bitmaps */
374     addbmp.hInst = HINST_COMMCTRL;
375     addbmp.nID = IDB_STD_SMALL_COLOR;
376     rebuild_toolbar(&hToolbar);
377     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
378     CHECK_IMAGELIST(15, 16, 16);
379     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
380     addbmp.nID = IDB_STD_LARGE_COLOR;
381     rebuild_toolbar(&hToolbar);
382     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
383     CHECK_IMAGELIST(15, 24, 24);
384     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(31, 30), "%x");
385
386     addbmp.nID = IDB_VIEW_SMALL_COLOR;
387     rebuild_toolbar(&hToolbar);
388     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
389     CHECK_IMAGELIST(12, 16, 16);
390     addbmp.nID = IDB_VIEW_LARGE_COLOR;
391     rebuild_toolbar(&hToolbar);
392     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
393     CHECK_IMAGELIST(12, 24, 24);
394
395     addbmp.nID = IDB_HIST_SMALL_COLOR;
396     rebuild_toolbar(&hToolbar);
397     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
398     CHECK_IMAGELIST(5, 16, 16);
399     addbmp.nID = IDB_HIST_LARGE_COLOR;
400     rebuild_toolbar(&hToolbar);
401     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
402     CHECK_IMAGELIST(5, 24, 24);
403
404
405     DestroyWindow(hToolbar);
406 }
407
408 #define CHECK_STRING_TABLE(count, tab) { \
409         INT _i; \
410         CHAR _buf[260]; \
411         for (_i = 0; _i < (count); _i++) {\
412             ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, _i), (LPARAM)_buf); \
413             ok(ret >= 0, "TB_GETSTRING - unexpected return %d while checking string %d\n", ret, _i); \
414             if (ret >= 0) \
415                 ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \
416         } \
417         ok(SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \
418             "Too many string in table\n"); \
419     }
420
421 static void test_add_string(void)
422 {
423     LPCSTR test1 = "a\0b\0";
424     LPCSTR test2 = "|a|b||\0";
425     LPCSTR ret1[] = {"a", "b"};
426     LPCSTR ret2[] = {"a", "b", "|a|b||"};
427     LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"};
428     LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"};
429     LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"};
430     LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"};
431     LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"};
432     HWND hToolbar = NULL;
433     TBBUTTON button;
434     int ret;
435
436     rebuild_toolbar(&hToolbar);
437     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
438     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
439     CHECK_STRING_TABLE(2, ret1);
440     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
441     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
442     CHECK_STRING_TABLE(3, ret2);
443
444     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1);
445     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
446     CHECK_STRING_TABLE(3, ret2);
447     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2);
448     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
449     CHECK_STRING_TABLE(5, ret3);
450     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3);
451     ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
452     CHECK_STRING_TABLE(6, ret4);
453     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4);
454     ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
455     CHECK_STRING_TABLE(8, ret5);
456     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5);
457     ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
458     CHECK_STRING_TABLE(11, ret6);
459     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7);
460     ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
461     CHECK_STRING_TABLE(14, ret7);
462
463     ZeroMemory(&button, sizeof(button));
464     button.iString = (UINT_PTR)"Test";
465     SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
466     CHECK_STRING_TABLE(14, ret7);
467     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
468     CHECK_STRING_TABLE(14, ret7);
469
470     DestroyWindow(hToolbar);
471 }
472
473 static void expect_hot_notify(int idold, int idnew)
474 {
475     g_fExpectedHotItemOld = idold;
476     g_fExpectedHotItemNew = idnew;
477     g_fReceivedHotItemChange = FALSE;
478 }
479
480 #define check_hot_notify() \
481     ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
482     g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
483
484 static void test_hotitem(void)
485 {
486     HWND hToolbar = NULL;
487     TBBUTTONINFO tbinfo;
488     LRESULT ret;
489
490     g_fBlockHotItemChange = FALSE;
491
492     rebuild_toolbar_with_buttons(&hToolbar);
493     /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
494      * comctl6 doesn't have this requirement even when theme == NULL */
495     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE));
496     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
497     ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
498     ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
499     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
500     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
501     ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
502     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
503     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
504
505     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
506     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
507     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
508     ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
509     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
510     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
511     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
512     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
513
514     expect_hot_notify(0, 7);
515     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
516     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
517     check_hot_notify();
518     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
519     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
520     g_fBlockHotItemChange = TRUE;
521     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
522     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
523     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
524     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
525     g_fBlockHotItemChange = FALSE;
526
527     g_fReceivedHotItemChange = FALSE;
528     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
529     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
530     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
531
532     g_fReceivedHotItemChange = FALSE;
533     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
534     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
535     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
536
537     expect_hot_notify(7, 0);
538     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
539     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
540     check_hot_notify();
541     SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
542
543     /* setting disabled buttons will generate a notify with the button id but no button will be hot */
544     expect_hot_notify(7, 9);
545     ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0);
546     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
547     check_hot_notify();
548     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
549     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
550     /* enabling the button won't change that */
551     SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
552     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
553     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
554
555     /* disabling a hot button works */
556     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
557     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
558     g_fReceivedHotItemChange = FALSE;
559     SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
560     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
561     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
562     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
563
564     SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
565     tbinfo.cbSize = sizeof(TBBUTTONINFO);
566     tbinfo.dwMask = TBIF_STATE;
567     tbinfo.fsState = 0;  /* disabled */
568     g_fReceivedHotItemChange = FALSE;
569     ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n");
570     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
571     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
572     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
573
574     DestroyWindow(hToolbar);
575 }
576
577 #if 0  /* use this to generate more tests*/
578
579 static void dump_sizes(HWND hToolbar)
580 {
581     SIZE sz;
582     RECT r;
583     int count = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
584     int i;
585
586     GetClientRect(hToolbar, &r);
587     SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz);
588     printf("  { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom,
589         sz.cx, sz.cy, count);
590     for (i=0; i<count; i++)
591     {
592         SendMessageA(hToolbar, TB_GETITEMRECT, i, &r);
593         printf("%s{%3d, %3d, %3d, %3d}, ", (i%3==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom);
594     }
595     printf("\n  }, }, \n");
596 }
597
598 #define check_sizes() dump_sizes(hToolbar);
599 #define check_sizes_todo(todomask) dump_sizes(hToolbar);
600
601 #else
602
603 typedef struct
604 {
605     RECT rcClient;
606     SIZE szMin;
607     INT nButtons;
608     RECT rcButtons[100];
609 } tbsize_result_t;
610
611 static tbsize_result_t tbsize_results[] =
612 {
613   { {0, 0, 672, 26}, {100, 22}, 5, {
614     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
615     { 54,   2,  77,  24}, { 77,   2, 100,  24},
616   }, },
617   { {0, 0, 672, 26}, {146, 22}, 7, {
618     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
619     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
620     {  0,  24,  23,  46},
621   }, },
622   { {0, 0, 672, 48}, {146, 22}, 7, {
623     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
624     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
625     {  0,  24,  23,  46},
626   }, },
627   { {0, 0, 672, 26}, {146, 22}, 7, {
628     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
629     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
630     {123,   2, 146,  24},
631   }, },
632   { {0, 0, 672, 26}, {192, 22}, 9, {
633     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
634     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
635     {123,   2, 146,  24}, {146,   2, 169,  24}, {169,   2, 192,  24},
636   }, },
637   { {0, 0, 672, 92}, {882, 22}, 39, {
638     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,   2,   8,  29},
639     {  0,  29,  23,  51}, { 23,  29,  46,  51}, { 46,  29,  69,  51},
640     { 69,  29,  92,  51}, { 92,  29, 115,  51}, {115,  29, 138,  51},
641     {138,  29, 161,  51}, {161,  29, 184,  51}, {184,  29, 207,  51},
642     {207,  29, 230,  51}, {230,  29, 253,  51}, {253,  29, 276,  51},
643     {276,  29, 299,  51}, {299,  29, 322,  51}, {322,  29, 345,  51},
644     {345,  29, 368,  51}, {368,  29, 391,  51}, {391,  29, 414,  51},
645     {414,  29, 437,  51}, {437,  29, 460,  51}, {460,  29, 483,  51},
646     {483,  29, 506,  51}, {506,  29, 529,  51}, {529,  29, 552,  51},
647     {552,  29, 575,  51}, {575,  29, 598,  51}, {598,  29, 621,  51},
648     {621,  29, 644,  51}, {644,  29, 667,  51}, {  0,  51,  23,  73},
649     { 23,  51,  46,  73}, { 46,  51,  69,  73}, { 69,  51,  92,  73},
650     { 92,  51, 115,  73}, {115,  51, 138,  73}, {138,  51, 161,  73},
651   }, },
652   { {0, 0, 48, 226}, {23, 140}, 7, {
653     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  94,  24},
654     { 94,   2, 117,  24}, {117,   2, 140,  24}, {140,   2, 163,  24},
655     {  0,  24,  23,  46},
656   }, },
657   { {0, 0, 92, 226}, {23, 140}, 7, {
658     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,  24,  92,  32},
659     {  0,  32,  23,  54}, { 23,  32,  46,  54}, { 46,  32,  69,  54},
660     { 69,  32,  92,  54},
661   }, },
662   { {0, 0, 672, 26}, {194, 30}, 7, {
663     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
664     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
665     {  0,  32,  31,  62},
666   }, },
667   { {0, 0, 672, 64}, {194, 30}, 7, {
668     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
669     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
670     {  0,  32,  31,  62},
671   }, },
672   { {0, 0, 672, 64}, {194, 30}, 7, {
673     {  0,   0,  31,  30}, { 31,   0,  62,  30}, { 62,   0,  70,  30},
674     { 70,   0, 101,  30}, {101,   0, 132,  30}, {132,   0, 163,  30},
675     {  0,  30,  31,  60},
676   }, },
677   { {0, 0, 124, 226}, {31, 188}, 7, {
678     {  0,   0,  31,  30}, { 31,   0,  62,  30}, {  0,  30, 124,  38},
679     {  0,  38,  31,  68}, { 31,  38,  62,  68}, { 62,  38,  93,  68},
680     { 93,  38, 124,  68},
681   }, },
682   { {0, 0, 672, 26}, {146, 22}, 7, {
683     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
684     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
685     {123,   2, 146,  24},
686   }, },
687   { {0, 0, 672, 26}, {146, 100}, 7, {
688     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
689     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
690     {123,   0, 146, 100},
691   }, },
692   { {0, 0, 672, 26}, {215, 100}, 10, {
693     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
694     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
695     {123,   0, 146, 100}, {146,   0, 169, 100}, {169,   0, 192, 100},
696     {192,   0, 215, 100},
697   }, },
698   { {0, 0, 672, 26}, {238, 39}, 11, {
699     {  0,   0,  23,  39}, { 23,   0,  46,  39}, { 46,   0,  54,  39},
700     { 54,   0,  77,  39}, { 77,   0, 100,  39}, {100,   0, 123,  39},
701     {123,   0, 146,  39}, {146,   0, 169,  39}, {169,   0, 192,  39},
702     {192,   0, 215,  39}, {215,   0, 238,  39},
703   }, },
704   { {0, 0, 672, 26}, {238, 22}, 11, {
705     {  0,   0,  23,  22}, { 23,   0,  46,  22}, { 46,   0,  54,  22},
706     { 54,   0,  77,  22}, { 77,   0, 100,  22}, {100,   0, 123,  22},
707     {123,   0, 146,  22}, {146,   0, 169,  22}, {169,   0, 192,  22},
708     {192,   0, 215,  22}, {215,   0, 238,  22},
709   }, },
710   { {0, 0, 672, 26}, {489, 39}, 3, {
711     {  0,   2, 163,  41}, {163,   2, 330,  41}, {330,   2, 493,  41},
712   }, },
713   { {0, 0, 672, 104}, {978, 24}, 6, {
714     {  0,   2, 163,  26}, {163,   2, 326,  26}, {326,   2, 489,  26},
715     {489,   2, 652,  26}, {652,   2, 819,  26}, {819,   2, 850,  26},
716   }, },
717   { {0, 0, 672, 28}, {978, 38}, 6, {
718     {  0,   0, 163,  38}, {163,   0, 326,  38}, {326,   0, 489,  38},
719     {489,   0, 652,  38}, {652,   0, 819,  38}, {819,   0, 850,  38},
720   }, },
721   { {0, 0, 672, 100}, {239, 102}, 3, {
722     {  0,   2, 100,  102}, {100,   2, 139,  102}, {139, 2, 239,  102},
723   }, },
724   { {0, 0, 672, 42}, {185, 40}, 3, {
725       {  0,   2,  75,  40}, {75,   2, 118, 40}, {118, 2, 185, 40},
726   }, },
727   { {0, 0, 672, 42}, {67, 40}, 1, {
728       {  0,   2,  67,  40},
729   }, },
730   { {0, 0, 672, 42}, {67, 41}, 2, {
731       {  0,   2,  672,  41}, {  0,   41,  672,  80},
732   }, },
733 };
734
735 static int tbsize_numtests = 0;
736
737 #define check_sizes_todo(todomask) { \
738         RECT rc; \
739         int buttonCount, i, mask=(todomask); \
740         tbsize_result_t *res = &tbsize_results[tbsize_numtests]; \
741         assert(tbsize_numtests < sizeof(tbsize_results)/sizeof(tbsize_results[0])); \
742         GetClientRect(hToolbar, &rc); \
743         /*check_rect("client", rc, res->rcClient);*/ \
744         buttonCount = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0); \
745         compare(buttonCount, res->nButtons, "%d"); \
746         for (i=0; i<min(buttonCount, res->nButtons); i++) { \
747             ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
748             if (!(mask&1)) { \
749                 check_rect("button", rc, res->rcButtons[i]); \
750             } else {\
751                 todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
752             } \
753             mask >>= 1; \
754         } \
755         tbsize_numtests++; \
756     }
757
758 #define check_sizes() check_sizes_todo(0)
759
760 #endif
761
762 static TBBUTTON buttons1[] = {
763     {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1},
764     {0, 11, 0, 0, {0, }, 0, -1},
765 };
766 static TBBUTTON buttons2[] = {
767     {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
768     {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
769 };
770 static TBBUTTON buttons3[] = {
771     {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0},
772     {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1},
773     {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1},
774     {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)"Tst"}
775 };
776
777 static void test_sizes(void)
778 {
779     HWND hToolbar = NULL;
780     HIMAGELIST himl;
781     TBBUTTONINFO tbinfo;
782     int style;
783     int i;
784
785     rebuild_toolbar_with_buttons(&hToolbar);
786     style = GetWindowLong(hToolbar, GWL_STYLE);
787     ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style);
788     check_sizes();
789     /* the TBSTATE_WRAP makes a second row */
790     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
791     check_sizes();
792     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
793     check_sizes();
794     /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */
795     SetWindowLong(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE);
796     check_sizes();
797     /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */
798     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
799     check_sizes();
800     /* only after adding enough buttons the bar will be wrapped on a
801      * separator and then on the first button */
802     for (i=0; i<15; i++)
803         SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
804     check_sizes_todo(0x4);
805
806     rebuild_toolbar_with_buttons(&hToolbar);
807     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
808     /* setting the buttons vertical will only change the window client size */
809     SetWindowLong(hToolbar, GWL_STYLE, style | CCS_VERT);
810     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
811     check_sizes_todo(0x3c);
812     /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */
813     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT);
814     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
815     check_sizes_todo(0x7c);
816
817     rebuild_toolbar_with_buttons(&hToolbar);
818     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
819     /* a TB_SETBITMAPSIZE changes button sizes*/
820     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
821     check_sizes();
822
823     /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */
824     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
825     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
826     check_sizes();
827     /* but after a TB_SETBITMAPSIZE the top margins is changed */
828     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20));
829     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
830     check_sizes();
831     /* some vertical toolbar sizes */
832     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT);
833     check_sizes_todo(0x7c);
834
835     rebuild_toolbar_with_buttons(&hToolbar);
836     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
837     /* newly added buttons will be use the previous margin */
838     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
839     check_sizes();
840     /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */
841     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
842     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n");
843     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
844     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
845     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
846     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n");
847     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
848     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
849     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
850     check_sizes();
851     /* add some buttons with non-default sizes */
852     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
853     SendMessageA(hToolbar, TB_INSERTBUTTON, -1, (LPARAM)&buttons2[0]);
854     check_sizes();
855     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
856     /* TB_ADDSTRING resets the size */
857     SendMessageA(hToolbar, TB_ADDSTRING, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
858     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
859     check_sizes();
860     /* TB_SETBUTTONSIZE can be used to crop the text */
861     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
862     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
863     check_sizes();
864     /* the default size is bitmap size + padding */
865     SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1));
866     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
867     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(17, 17), "Unexpected button size\n");
868     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3));
869     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
870     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(4, 4), "Unexpected button size\n");
871
872     rebuild_toolbar(&hToolbar);
873     /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */
874     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
875     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15));
876     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n");
877     /* -1 in TB_SETBITMAPSIZE is a special code meaning that the coordinate shouldn't be changed */
878     add_128x15_bitmap(hToolbar, 16);
879     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(14, -1)), "TB_SETBITMAPSIZE failed\n");
880     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 21), "%x");
881     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, 12)), "TB_SETBITMAPSIZE failed\n");
882     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
883     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, -1)), "TB_SETBITMAPSIZE failed\n");
884     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
885     /* check the imagelist */
886     InvalidateRect(hToolbar, NULL, TRUE);
887     UpdateWindow(hToolbar);
888     CHECK_IMAGELIST(16, 14, 12);
889
890     rebuild_toolbar(&hToolbar);
891     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
892     /* the height is increased after a TB_ADDSTRING */
893     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
894     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
895     /* if a string is in the pool, even adding a button without a string resets the size */
896     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]);
897     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
898     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
899     /* an BTNS_AUTOSIZE button is also considered when computing the new size */
900     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]);
901     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
902     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
903     check_sizes();
904     /* delete button doesn't change the buttons size */
905     SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0);
906     SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
907     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
908     /* TB_INSERTBUTTONS will */
909     SendMessageA(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons2[0]);
910     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
911
912     /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */
913     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
914     ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n");
915     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
916     ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n");
917     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
918     /* however changing the hidden flag with TB_SETSTATE does */
919     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n");
920     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
921     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n");
922     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
923
924     /* TB_SETIMAGELIST always changes the height but the width only if necessary */
925     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
926     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
927     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
928     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n");
929     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
930     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
931     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
932     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
933     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
934     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n");
935     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
936     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n");
937     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
938     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
939     /* the text is taken into account */
940     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
941     SendMessageA(hToolbar, TB_ADDBUTTONS, 4, (LPARAM)buttons3);
942     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 38), "Unexpected button size\n");
943     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
944     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 24), "Unexpected button size\n");
945     /* the style change also comes into effect */
946     check_sizes();
947     SetWindowLong(hToolbar, GWL_STYLE, GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
948     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
949     check_sizes_todo(0x30);     /* some small problems with BTNS_AUTOSIZE button sizes */
950
951     rebuild_toolbar(&hToolbar);
952     ImageList_Destroy(himl);
953
954     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
955     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
956     SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0);
957     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
958
959     rebuild_toolbar(&hToolbar);
960
961     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
962     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
963     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n");
964     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n");
965     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]) == 1, "TB_ADDBUTTONS failed\n");
966     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
967     check_sizes();
968
969     rebuild_toolbar(&hToolbar);
970     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE));
971     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
972     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
973     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n");
974     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n");
975     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
976     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
977     check_sizes_todo(0xff);
978
979     rebuild_toolbar(&hToolbar);
980     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE));
981     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
982     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
983     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
984     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
985     check_sizes();
986
987     rebuild_toolbar(&hToolbar);
988     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_WRAPABLE | GetWindowLong(hToolbar, GWL_STYLE));
989     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
990     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
991     tbinfo.cx = 672;
992     tbinfo.cbSize = sizeof(TBBUTTONINFO);
993     tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX;
994     ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
995     ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
996     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
997     check_sizes();
998
999     DestroyWindow(hToolbar);
1000 }
1001
1002 /* Toolbar control has two ways of reacting to a change. We call them a
1003  * relayout and recalc. A recalc forces a recompute of values like button size
1004  * and top margin (the latter in comctl32 <v6), while a relayout uses the cached
1005  * values. This functions creates a flat toolbar with a top margin of a non-flat
1006  * toolbar. We will notice a recalc, as it will recompte the top margin and
1007  * change it to zero*/
1008 static void prepare_recalc_test(HWND *phToolbar)
1009 {
1010     RECT rect;
1011     rebuild_toolbar_with_buttons(phToolbar);
1012     SetWindowLong(*phToolbar, GWL_STYLE,
1013         GetWindowLong(*phToolbar, GWL_STYLE) | TBSTYLE_FLAT);
1014     SendMessage(*phToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1015     ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n",
1016         rect.top);
1017 }
1018
1019 static BOOL did_recalc(HWND hToolbar)
1020 {
1021     RECT rect;
1022     SendMessage(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1023     ok(rect.top == 2 || rect.top == 0, "Unexpected top margin %d in recalc test\n",
1024         rect.top);
1025     return (rect.top == 0);
1026 }
1027
1028 static void test_recalc(void)
1029 {
1030     HWND hToolbar;
1031     TBBUTTONINFO bi;
1032     CHAR test[] = "Test";
1033
1034     /* Like TB_ADDBUTTONS tested in test_sized, inserting a button without text
1035      * results in a relayout, while adding one with text forces a recalc */
1036     prepare_recalc_test(&hToolbar);
1037     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[0]);
1038     ok(!did_recalc(hToolbar), "Unexpected recalc - adding button without text\n");
1039
1040     prepare_recalc_test(&hToolbar);
1041     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[3]);
1042     ok(did_recalc(hToolbar), "Expected a recalc - adding button with text\n");
1043
1044     /* TB_SETBUTTONINFO, even when adding a text, results only in a relayout */
1045     prepare_recalc_test(&hToolbar);
1046     bi.cbSize = sizeof(bi);
1047     bi.dwMask = TBIF_TEXT;
1048     bi.pszText = test;
1049     SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&bi);
1050     ok(!did_recalc(hToolbar), "Unexpected recalc - setting a button text\n");
1051
1052     DestroyWindow(hToolbar);
1053 }
1054
1055 static void test_getbuttoninfo(void)
1056 {
1057     HWND hToolbar = NULL;
1058     int i;
1059
1060     rebuild_toolbar_with_buttons(&hToolbar);
1061     for (i = 0; i < 128; i++)
1062     {
1063         TBBUTTONINFO tbi;
1064         int ret;
1065
1066         tbi.cbSize = i;
1067         tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
1068         ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi);
1069         if (i == sizeof(TBBUTTONINFO)) {
1070             compare(ret, 0, "%d");
1071         } else {
1072             compare(ret, -1, "%d");
1073         }
1074     }
1075     DestroyWindow(hToolbar);
1076 }
1077
1078 static void test_createtoolbarex(void)
1079 {
1080     HWND hToolbar;
1081     TBBUTTON btns[3];
1082     ZeroMemory(&btns, sizeof(btns));
1083
1084     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1085         3, 20, 20, 16, 16, sizeof(TBBUTTON));
1086     CHECK_IMAGELIST(16, 20, 20);
1087     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x");
1088     DestroyWindow(hToolbar);
1089
1090     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1091         3, 4, 4, 16, 16, sizeof(TBBUTTON));
1092     CHECK_IMAGELIST(32, 4, 4);
1093     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x");
1094     DestroyWindow(hToolbar);
1095
1096     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1097         3, 0, 8, 12, 12, sizeof(TBBUTTON));
1098     CHECK_IMAGELIST(16, 12, 12);
1099     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x");
1100     DestroyWindow(hToolbar);
1101
1102     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1103         3, -1, 8, 12, 12, sizeof(TBBUTTON));
1104     CHECK_IMAGELIST(16, 12, 8);
1105     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x");
1106     DestroyWindow(hToolbar);
1107
1108     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1109         3, -1, 8, -1, 12, sizeof(TBBUTTON));
1110     CHECK_IMAGELIST(16, 16, 8);
1111     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x");
1112     DestroyWindow(hToolbar);
1113
1114     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1115         3, 0, 0, 12, -1, sizeof(TBBUTTON));
1116     CHECK_IMAGELIST(16, 12, 16);
1117     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x");
1118     DestroyWindow(hToolbar);
1119
1120     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1121         3, 0, 0, 0, 12, sizeof(TBBUTTON));
1122     CHECK_IMAGELIST(16, 16, 16);
1123     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x");
1124     DestroyWindow(hToolbar);
1125 }
1126
1127 static void test_dispinfo(void)
1128 {
1129     HWND hToolbar = NULL;
1130     const TBBUTTON buttons_disp[] = {
1131         {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1132         {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1133     };
1134     BOOL ret;
1135
1136     rebuild_toolbar(&hToolbar);
1137     SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
1138     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp);
1139     g_dwExpectedDispInfoMask = 1;
1140     /* Some TBN_GETDISPINFO tests will be done in MyWnd_Notify function.
1141      * We will receive TBN_GETDISPINFOW even if the control is ANSI */
1142     compare((BOOL)SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0, "%d");
1143     ShowWindow(hToolbar, SW_SHOW);
1144     UpdateWindow(hToolbar);
1145
1146     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, TRUE, 0);
1147     compare(ret, FALSE, "%d");
1148     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 1L, "%ld");
1149     InvalidateRect(hToolbar, NULL, FALSE);
1150     UpdateWindow(hToolbar);
1151
1152     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
1153     compare(ret, TRUE, "%d");
1154     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0L, "%ld");
1155     InvalidateRect(hToolbar, NULL, FALSE);
1156     UpdateWindow(hToolbar);
1157
1158     DestroyWindow(hToolbar);
1159     g_dwExpectedDispInfoMask = 0;
1160 }
1161
1162 typedef struct
1163 {
1164     int  nRows;
1165     BOOL bLarger;
1166     int  expectedRows;
1167 } tbrows_result_t;
1168
1169 static tbrows_result_t tbrows_results[] =
1170 {
1171     {1, TRUE,  1}, /* 0: Simple case 9 in a row */
1172     {2, TRUE,  2}, /* 1: Another simple case 5 on one row, 4 on another*/
1173     {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */
1174     {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */
1175     {8, TRUE,  9}, /* 4: 8 lines but grow - should be 9 lines */
1176     {1, TRUE,  1}  /* 5: Back to simple case */
1177 };
1178
1179 static void test_setrows(void)
1180 {
1181     TBBUTTON buttons[9];
1182     HWND hToolbar;
1183     int i;
1184
1185     for (i=0; i<9; i++)
1186         MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0);
1187
1188     /* Test 1 - 9 buttons */
1189     hToolbar = CreateToolbarEx(hMainWnd,
1190         WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN
1191         | CCS_NOMOVEY | CCS_TOP,
1192         0,
1193         0, NULL, 0,
1194         buttons, sizeof(buttons)/sizeof(buttons[0]),
1195         20, 20, 0, 0, sizeof(TBBUTTON));
1196     ok(hToolbar != NULL, "Toolbar creation\n");
1197     ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
1198
1199     /* test setting rows to each of 1-10 with bLarger true and false */
1200     for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) {
1201         RECT rc;
1202         int rows;
1203
1204         memset(&rc, 0xCC, sizeof(rc));
1205         SendMessageA(hToolbar, TB_SETROWS,
1206                      MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger),
1207                      (LPARAM) &rc);
1208
1209         rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0));
1210         ok(rows == tbrows_results[i].expectedRows,
1211                    "[%d] Unexpected number of rows %d (expected %d)\n", i, rows,
1212                    tbrows_results[i].expectedRows);
1213     }
1214
1215     DestroyWindow(hToolbar);
1216 }
1217
1218 static void test_getstring(void)
1219 {
1220     HWND hToolbar = NULL;
1221     char str[10];
1222     WCHAR strW[10];
1223     static const char answer[] = "STR";
1224     static const WCHAR answerW[] = { 'S','T','R',0 };
1225     INT r;
1226
1227     hToolbar = CreateWindowExA(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
1228     ok(hToolbar != NULL, "Toolbar creation problem\n");
1229
1230     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
1231     expect(-1, r);
1232     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1233     expect(-1, r);
1234     r = SendMessage(hToolbar, TB_ADDSTRING, 0, (LPARAM)answer);
1235     expect(0, r);
1236     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
1237     expect(lstrlenA(answer), r);
1238     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1239     expect(lstrlenA(answer), r);
1240     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(sizeof(str), 0), (LPARAM)str);
1241     expect(lstrlenA(answer), r);
1242     expect(0, lstrcmp(answer, str));
1243     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(sizeof(strW), 0), (LPARAM)strW);
1244     expect(lstrlenA(answer), r);
1245     expect(0, lstrcmpW(answerW, strW));
1246
1247     DestroyWindow(hToolbar);
1248 }
1249
1250 START_TEST(toolbar)
1251 {
1252     WNDCLASSA wc;
1253     MSG msg;
1254     RECT rc;
1255   
1256     InitCommonControls();
1257   
1258     wc.style = CS_HREDRAW | CS_VREDRAW;
1259     wc.cbClsExtra = 0;
1260     wc.cbWndExtra = 0;
1261     wc.hInstance = GetModuleHandleA(NULL);
1262     wc.hIcon = NULL;
1263     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
1264     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1265     wc.lpszMenuName = NULL;
1266     wc.lpszClassName = "MyTestWnd";
1267     wc.lpfnWndProc = MyWndProc;
1268     RegisterClassA(&wc);
1269     
1270     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
1271       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
1272     GetClientRect(hMainWnd, &rc);
1273     ShowWindow(hMainWnd, SW_SHOW);
1274
1275     basic_test();
1276     test_add_bitmap();
1277     test_add_string();
1278     test_hotitem();
1279     test_sizes();
1280     test_recalc();
1281     test_getbuttoninfo();
1282     test_createtoolbarex();
1283     test_dispinfo();
1284     test_setrows();
1285     test_getstring();
1286
1287     PostQuitMessage(0);
1288     while(GetMessageA(&msg,0,0,0)) {
1289         TranslateMessage(&msg);
1290         DispatchMessageA(&msg);
1291     }
1292     DestroyWindow(hMainWnd);
1293 }