comctl32/treeview: Correct define name.
[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 strings 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     CHAR buf[260];
436
437     rebuild_toolbar(&hToolbar);
438     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
439     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
440     ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, 1), (LPARAM)buf);
441     if (ret == 0)
442     {
443         win_skip("TB_GETSTRING needs 5.80\n");
444         return;
445     }
446     CHECK_STRING_TABLE(2, ret1);
447     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
448     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
449     CHECK_STRING_TABLE(3, ret2);
450
451     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1);
452     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
453     CHECK_STRING_TABLE(3, ret2);
454     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2);
455     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
456     CHECK_STRING_TABLE(5, ret3);
457     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3);
458     ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
459     CHECK_STRING_TABLE(6, ret4);
460     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4);
461     ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
462     CHECK_STRING_TABLE(8, ret5);
463     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5);
464     ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
465     CHECK_STRING_TABLE(11, ret6);
466     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7);
467     ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
468     CHECK_STRING_TABLE(14, ret7);
469
470     ZeroMemory(&button, sizeof(button));
471     button.iString = (UINT_PTR)"Test";
472     SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
473     CHECK_STRING_TABLE(14, ret7);
474     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
475     CHECK_STRING_TABLE(14, ret7);
476
477     DestroyWindow(hToolbar);
478 }
479
480 static void expect_hot_notify(int idold, int idnew)
481 {
482     g_fExpectedHotItemOld = idold;
483     g_fExpectedHotItemNew = idnew;
484     g_fReceivedHotItemChange = FALSE;
485 }
486
487 #define check_hot_notify() \
488     ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
489     g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
490
491 static void test_hotitem(void)
492 {
493     HWND hToolbar = NULL;
494     TBBUTTONINFO tbinfo;
495     LRESULT ret;
496
497     g_fBlockHotItemChange = FALSE;
498
499     rebuild_toolbar_with_buttons(&hToolbar);
500     /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
501      * comctl6 doesn't have this requirement even when theme == NULL */
502     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE));
503     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
504     ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
505     ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
506     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
507     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
508     ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
509     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
510     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
511
512     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
513     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
514     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
515     ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
516     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
517     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
518     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
519     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
520
521     expect_hot_notify(0, 7);
522     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
523     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
524     check_hot_notify();
525     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
526     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
527     g_fBlockHotItemChange = TRUE;
528     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
529     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
530     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
531     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
532     g_fBlockHotItemChange = FALSE;
533
534     g_fReceivedHotItemChange = FALSE;
535     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
536     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
537     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
538
539     g_fReceivedHotItemChange = FALSE;
540     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
541     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
542     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
543
544     expect_hot_notify(7, 0);
545     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
546     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
547     check_hot_notify();
548     SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
549
550     /* setting disabled buttons will generate a notify with the button id but no button will be hot */
551     expect_hot_notify(7, 9);
552     ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0);
553     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
554     check_hot_notify();
555     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
556     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
557     /* enabling the button won't change that */
558     SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
559     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
560     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
561
562     /* disabling a hot button works */
563     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
564     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
565     g_fReceivedHotItemChange = FALSE;
566     SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
567     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
568     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
569     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
570
571     SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
572     tbinfo.cbSize = sizeof(TBBUTTONINFO);
573     tbinfo.dwMask = TBIF_STATE;
574     tbinfo.fsState = 0;  /* disabled */
575     g_fReceivedHotItemChange = FALSE;
576     ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n");
577     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
578     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
579     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
580
581     DestroyWindow(hToolbar);
582 }
583
584 #if 0  /* use this to generate more tests*/
585
586 static void dump_sizes(HWND hToolbar)
587 {
588     SIZE sz;
589     RECT r;
590     int count = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
591     int i;
592
593     GetClientRect(hToolbar, &r);
594     SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz);
595     printf("  { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom,
596         sz.cx, sz.cy, count);
597     for (i=0; i<count; i++)
598     {
599         SendMessageA(hToolbar, TB_GETITEMRECT, i, &r);
600         printf("%s{%3d, %3d, %3d, %3d}, ", (i%3==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom);
601     }
602     printf("\n  }, },\n");
603 }
604
605 #define check_sizes() dump_sizes(hToolbar);
606 #define check_sizes_todo(todomask) dump_sizes(hToolbar);
607
608 #else
609
610 typedef struct
611 {
612     RECT rcClient;
613     SIZE szMin;
614     INT nButtons;
615     RECT rcButtons[100];
616 } tbsize_result_t;
617
618 static tbsize_result_t tbsize_results[] =
619 {
620   { {0, 0, 672, 26}, {100, 22}, 5, {
621     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
622     { 54,   2,  77,  24}, { 77,   2, 100,  24},
623   }, },
624   { {0, 0, 672, 26}, {146, 22}, 7, {
625     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
626     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
627     {  0,  24,  23,  46},
628   }, },
629   { {0, 0, 672, 48}, {146, 22}, 7, {
630     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
631     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
632     {  0,  24,  23,  46},
633   }, },
634   { {0, 0, 672, 26}, {146, 22}, 7, {
635     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
636     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
637     {123,   2, 146,  24},
638   }, },
639   { {0, 0, 672, 26}, {192, 22}, 9, {
640     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
641     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
642     {123,   2, 146,  24}, {146,   2, 169,  24}, {169,   2, 192,  24},
643   }, },
644   { {0, 0, 672, 92}, {882, 22}, 39, {
645     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,   2,   8,  29},
646     {  0,  29,  23,  51}, { 23,  29,  46,  51}, { 46,  29,  69,  51},
647     { 69,  29,  92,  51}, { 92,  29, 115,  51}, {115,  29, 138,  51},
648     {138,  29, 161,  51}, {161,  29, 184,  51}, {184,  29, 207,  51},
649     {207,  29, 230,  51}, {230,  29, 253,  51}, {253,  29, 276,  51},
650     {276,  29, 299,  51}, {299,  29, 322,  51}, {322,  29, 345,  51},
651     {345,  29, 368,  51}, {368,  29, 391,  51}, {391,  29, 414,  51},
652     {414,  29, 437,  51}, {437,  29, 460,  51}, {460,  29, 483,  51},
653     {483,  29, 506,  51}, {506,  29, 529,  51}, {529,  29, 552,  51},
654     {552,  29, 575,  51}, {575,  29, 598,  51}, {598,  29, 621,  51},
655     {621,  29, 644,  51}, {644,  29, 667,  51}, {  0,  51,  23,  73},
656     { 23,  51,  46,  73}, { 46,  51,  69,  73}, { 69,  51,  92,  73},
657     { 92,  51, 115,  73}, {115,  51, 138,  73}, {138,  51, 161,  73},
658   }, },
659   { {0, 0, 48, 226}, {23, 140}, 7, {
660     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  94,  24},
661     { 94,   2, 117,  24}, {117,   2, 140,  24}, {140,   2, 163,  24},
662     {  0,  24,  23,  46},
663   }, },
664   { {0, 0, 92, 226}, {23, 140}, 7, {
665     {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,  24,  92,  32},
666     {  0,  32,  23,  54}, { 23,  32,  46,  54}, { 46,  32,  69,  54},
667     { 69,  32,  92,  54},
668   }, },
669   { {0, 0, 672, 26}, {194, 30}, 7, {
670     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
671     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
672     {  0,  32,  31,  62},
673   }, },
674   { {0, 0, 672, 64}, {194, 30}, 7, {
675     {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
676     { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
677     {  0,  32,  31,  62},
678   }, },
679   { {0, 0, 672, 64}, {194, 30}, 7, {
680     {  0,   0,  31,  30}, { 31,   0,  62,  30}, { 62,   0,  70,  30},
681     { 70,   0, 101,  30}, {101,   0, 132,  30}, {132,   0, 163,  30},
682     {  0,  30,  31,  60},
683   }, },
684   { {0, 0, 124, 226}, {31, 188}, 7, {
685     {  0,   0,  31,  30}, { 31,   0,  62,  30}, {  0,  30, 124,  38},
686     {  0,  38,  31,  68}, { 31,  38,  62,  68}, { 62,  38,  93,  68},
687     { 93,  38, 124,  68},
688   }, },
689   { {0, 0, 672, 26}, {146, 22}, 7, {
690     {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
691     { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
692     {123,   2, 146,  24},
693   }, },
694   { {0, 0, 672, 26}, {146, 100}, 7, {
695     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
696     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
697     {123,   0, 146, 100},
698   }, },
699   { {0, 0, 672, 26}, {215, 100}, 10, {
700     {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
701     { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
702     {123,   0, 146, 100}, {146,   0, 169, 100}, {169,   0, 192, 100},
703     {192,   0, 215, 100},
704   }, },
705   { {0, 0, 672, 26}, {238, 39}, 11, {
706     {  0,   0,  23,  39}, { 23,   0,  46,  39}, { 46,   0,  54,  39},
707     { 54,   0,  77,  39}, { 77,   0, 100,  39}, {100,   0, 123,  39},
708     {123,   0, 146,  39}, {146,   0, 169,  39}, {169,   0, 192,  39},
709     {192,   0, 215,  39}, {215,   0, 238,  39},
710   }, },
711   { {0, 0, 672, 26}, {238, 22}, 11, {
712     {  0,   0,  23,  22}, { 23,   0,  46,  22}, { 46,   0,  54,  22},
713     { 54,   0,  77,  22}, { 77,   0, 100,  22}, {100,   0, 123,  22},
714     {123,   0, 146,  22}, {146,   0, 169,  22}, {169,   0, 192,  22},
715     {192,   0, 215,  22}, {215,   0, 238,  22},
716   }, },
717   { {0, 0, 672, 26}, {489, 39}, 3, {
718     {  0,   2, 163,  41}, {163,   2, 330,  41}, {330,   2, 493,  41},
719   }, },
720   { {0, 0, 672, 104}, {978, 24}, 6, {
721     {  0,   2, 163,  26}, {163,   2, 326,  26}, {326,   2, 489,  26},
722     {489,   2, 652,  26}, {652,   2, 819,  26}, {819,   2, 850,  26},
723   }, },
724   { {0, 0, 672, 28}, {978, 38}, 6, {
725     {  0,   0, 163,  38}, {163,   0, 326,  38}, {326,   0, 489,  38},
726     {489,   0, 652,  38}, {652,   0, 819,  38}, {819,   0, 850,  38},
727   }, },
728   { {0, 0, 672, 100}, {239, 102}, 3, {
729     {  0,   2, 100,  102}, {100,   2, 139,  102}, {139, 2, 239,  102},
730   }, },
731   { {0, 0, 672, 42}, {185, 40}, 3, {
732       {  0,   2,  75,  40}, {75,   2, 118, 40}, {118, 2, 185, 40},
733   }, },
734   { {0, 0, 672, 42}, {67, 40}, 1, {
735       {  0,   2,  67,  40},
736   }, },
737   { {0, 0, 672, 42}, {67, 41}, 2, {
738       {  0,   2,  672,  41}, {  0,   41,  672,  80},
739   }, },
740 };
741
742 static int tbsize_numtests = 0;
743
744 #define check_sizes_todo(todomask) { \
745         RECT rc; \
746         int buttonCount, i, mask=(todomask); \
747         tbsize_result_t *res = &tbsize_results[tbsize_numtests]; \
748         assert(tbsize_numtests < sizeof(tbsize_results)/sizeof(tbsize_results[0])); \
749         GetClientRect(hToolbar, &rc); \
750         /*check_rect("client", rc, res->rcClient);*/ \
751         buttonCount = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0); \
752         compare(buttonCount, res->nButtons, "%d"); \
753         for (i=0; i<min(buttonCount, res->nButtons); i++) { \
754             ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
755             if (!(mask&1)) { \
756                 check_rect("button", rc, res->rcButtons[i]); \
757             } else {\
758                 todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
759             } \
760             mask >>= 1; \
761         } \
762         tbsize_numtests++; \
763     }
764
765 #define check_sizes() check_sizes_todo(0)
766
767 #endif
768
769 static TBBUTTON buttons1[] = {
770     {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1},
771     {0, 11, 0, 0, {0, }, 0, -1},
772 };
773 static TBBUTTON buttons2[] = {
774     {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
775     {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
776 };
777 static TBBUTTON buttons3[] = {
778     {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0},
779     {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1},
780     {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1},
781     {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)"Tst"}
782 };
783
784 static void test_sizes(void)
785 {
786     HWND hToolbar = NULL;
787     HIMAGELIST himl, himl2;
788     TBBUTTONINFO tbinfo;
789     int style;
790     int i;
791
792     rebuild_toolbar_with_buttons(&hToolbar);
793     style = GetWindowLong(hToolbar, GWL_STYLE);
794     ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style);
795     check_sizes();
796     /* the TBSTATE_WRAP makes a second row */
797     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
798     check_sizes();
799     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
800     check_sizes();
801     /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */
802     SetWindowLong(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE);
803     check_sizes();
804     /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */
805     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
806     check_sizes();
807     /* only after adding enough buttons the bar will be wrapped on a
808      * separator and then on the first button */
809     for (i=0; i<15; i++)
810         SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
811     check_sizes_todo(0x4);
812
813     rebuild_toolbar_with_buttons(&hToolbar);
814     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
815     /* setting the buttons vertical will only change the window client size */
816     SetWindowLong(hToolbar, GWL_STYLE, style | CCS_VERT);
817     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
818     check_sizes_todo(0x3c);
819     /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */
820     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT);
821     SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
822     check_sizes_todo(0x7c);
823
824     rebuild_toolbar_with_buttons(&hToolbar);
825     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
826     /* a TB_SETBITMAPSIZE changes button sizes*/
827     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
828     check_sizes();
829
830     /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */
831     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
832     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
833     check_sizes();
834     /* but after a TB_SETBITMAPSIZE the top margins is changed */
835     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20));
836     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
837     check_sizes();
838     /* some vertical toolbar sizes */
839     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT);
840     check_sizes_todo(0x7c);
841
842     rebuild_toolbar_with_buttons(&hToolbar);
843     SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
844     /* newly added buttons will be use the previous margin */
845     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
846     check_sizes();
847     /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */
848     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
849     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n");
850     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
851     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
852     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
853     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n");
854     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
855     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
856     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
857     check_sizes();
858     /* add some buttons with non-default sizes */
859     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
860     SendMessageA(hToolbar, TB_INSERTBUTTON, -1, (LPARAM)&buttons2[0]);
861     check_sizes();
862     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
863     /* TB_ADDSTRING resets the size */
864     SendMessageA(hToolbar, TB_ADDSTRING, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
865     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
866     check_sizes();
867     /* TB_SETBUTTONSIZE can be used to crop the text */
868     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
869     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
870     check_sizes();
871     /* the default size is bitmap size + padding */
872     SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1));
873     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
874     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(17, 17), "Unexpected button size\n");
875     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3));
876     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
877     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(4, 4), "Unexpected button size\n");
878
879     rebuild_toolbar(&hToolbar);
880     /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */
881     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
882     SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15));
883     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n");
884     /* -1 in TB_SETBITMAPSIZE is a special code meaning that the coordinate shouldn't be changed */
885     add_128x15_bitmap(hToolbar, 16);
886     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(14, -1)), "TB_SETBITMAPSIZE failed\n");
887     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 21), "%x");
888     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, 12)), "TB_SETBITMAPSIZE failed\n");
889     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
890     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, -1)), "TB_SETBITMAPSIZE failed\n");
891     compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x");
892     /* check the imagelist */
893     InvalidateRect(hToolbar, NULL, TRUE);
894     UpdateWindow(hToolbar);
895     CHECK_IMAGELIST(16, 14, 12);
896
897     rebuild_toolbar(&hToolbar);
898     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
899     /* the height is increased after a TB_ADDSTRING */
900     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
901     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
902     /* if a string is in the pool, even adding a button without a string resets the size */
903     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]);
904     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
905     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
906     /* an BTNS_AUTOSIZE button is also considered when computing the new size */
907     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]);
908     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
909     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
910     check_sizes();
911     /* delete button doesn't change the buttons size */
912     SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0);
913     SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
914     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
915     /* TB_INSERTBUTTONS will */
916     SendMessageA(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons2[0]);
917     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
918
919     /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */
920     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
921     ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n");
922     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
923     ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n");
924     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
925     /* however changing the hidden flag with TB_SETSTATE does */
926     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n");
927     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
928     ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n");
929     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
930
931     /* TB_SETIMAGELIST always changes the height but the width only if necessary */
932     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
933     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
934     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
935     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n");
936     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
937     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
938     /* But there are no update when we change imagelist, and image sizes are the same */
939     himl2 = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_128x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
940     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LRESULT)himl2) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
941     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
942     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
943     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
944     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl2, "TB_SETIMAGELIST failed\n");
945     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n");
946     SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
947     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n");
948     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
949     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
950     /* the text is taken into account */
951     SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
952     SendMessageA(hToolbar, TB_ADDBUTTONS, 4, (LPARAM)buttons3);
953     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 38), "Unexpected button size\n");
954     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
955     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 24), "Unexpected button size\n");
956     /* the style change also comes into effect */
957     check_sizes();
958     SetWindowLong(hToolbar, GWL_STYLE, GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
959     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
960     check_sizes_todo(0x30);     /* some small problems with BTNS_AUTOSIZE button sizes */
961
962     rebuild_toolbar(&hToolbar);
963     ImageList_Destroy(himl);
964
965     SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
966     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
967     SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0);
968     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
969
970     rebuild_toolbar(&hToolbar);
971
972     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
973     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
974     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n");
975     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n");
976     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]) == 1, "TB_ADDBUTTONS failed\n");
977     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
978     check_sizes();
979
980     rebuild_toolbar(&hToolbar);
981     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE));
982     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
983     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
984     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n");
985     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n");
986     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
987     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
988     check_sizes_todo(0xff);
989
990     rebuild_toolbar(&hToolbar);
991     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE));
992     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n");
993     ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n");
994     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
995     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 );
996     check_sizes();
997
998     rebuild_toolbar(&hToolbar);
999     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_WRAPABLE | GetWindowLong(hToolbar, GWL_STYLE));
1000     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
1001     ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n");
1002     tbinfo.cx = 672;
1003     tbinfo.cbSize = sizeof(TBBUTTONINFO);
1004     tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX;
1005     ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
1006     ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
1007     SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
1008     check_sizes();
1009
1010     DestroyWindow(hToolbar);
1011 }
1012
1013 /* Toolbar control has two ways of reacting to a change. We call them a
1014  * relayout and recalc. A recalc forces a recompute of values like button size
1015  * and top margin (the latter in comctl32 <v6), while a relayout uses the cached
1016  * values. This functions creates a flat toolbar with a top margin of a non-flat
1017  * toolbar. We will notice a recalc, as it will recompte the top margin and
1018  * change it to zero*/
1019 static void prepare_recalc_test(HWND *phToolbar)
1020 {
1021     RECT rect;
1022     rebuild_toolbar_with_buttons(phToolbar);
1023     SetWindowLong(*phToolbar, GWL_STYLE,
1024         GetWindowLong(*phToolbar, GWL_STYLE) | TBSTYLE_FLAT);
1025     SendMessage(*phToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1026     ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n",
1027         rect.top);
1028 }
1029
1030 static BOOL did_recalc(HWND hToolbar)
1031 {
1032     RECT rect;
1033     SendMessage(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1034     ok(rect.top == 2 || rect.top == 0, "Unexpected top margin %d in recalc test\n",
1035         rect.top);
1036     return (rect.top == 0);
1037 }
1038
1039 /* call after a recalc did happen to return to an unstable state */
1040 static void restore_recalc_state(HWND hToolbar)
1041 {
1042     RECT rect;
1043     /* return to style with a 2px top margin */
1044     SetWindowLong(hToolbar, GWL_STYLE,
1045         GetWindowLong(hToolbar, GWL_STYLE) & ~TBSTYLE_FLAT);
1046     /* recalc */
1047     SendMessage(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
1048     /* top margin will be 0px if a recalc occurs */
1049     SetWindowLong(hToolbar, GWL_STYLE,
1050         GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
1051     /* safety check */
1052     SendMessage(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect);
1053     ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n",
1054         rect.top);
1055 }
1056
1057 static void test_recalc(void)
1058 {
1059     HWND hToolbar;
1060     TBBUTTONINFO bi;
1061     CHAR test[] = "Test";
1062     const int EX_STYLES_COUNT = 5;
1063     int i;
1064
1065     /* Like TB_ADDBUTTONS tested in test_sized, inserting a button without text
1066      * results in a relayout, while adding one with text forces a recalc */
1067     prepare_recalc_test(&hToolbar);
1068     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[0]);
1069     ok(!did_recalc(hToolbar), "Unexpected recalc - adding button without text\n");
1070
1071     prepare_recalc_test(&hToolbar);
1072     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[3]);
1073     ok(did_recalc(hToolbar), "Expected a recalc - adding button with text\n");
1074
1075     /* TB_SETBUTTONINFO, even when adding a text, results only in a relayout */
1076     prepare_recalc_test(&hToolbar);
1077     bi.cbSize = sizeof(bi);
1078     bi.dwMask = TBIF_TEXT;
1079     bi.pszText = test;
1080     SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&bi);
1081     ok(!did_recalc(hToolbar), "Unexpected recalc - setting a button text\n");
1082
1083     /* most extended styled doesn't force a recalc (testing all the bits gives
1084      * the same results, but prints some ERRs while testing) */
1085     for (i = 0; i < EX_STYLES_COUNT; i++)
1086     {
1087         if (i == 1 || i == 3)  /* an undoc style and TBSTYLE_EX_MIXEDBUTTONS */
1088             continue;
1089         prepare_recalc_test(&hToolbar);
1090         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
1091         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, (1 << i));
1092         ok(!did_recalc(hToolbar), "Unexpected recalc - setting bit %d\n", i);
1093         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
1094         ok(!did_recalc(hToolbar), "Unexpected recalc - clearing bit %d\n", i);
1095         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
1096     }
1097
1098     /* TBSTYLE_EX_MIXEDBUTTONS does a recalc on change */
1099     prepare_recalc_test(&hToolbar);
1100     SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1101     ok(did_recalc(hToolbar), "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n");
1102     restore_recalc_state(hToolbar);
1103     SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
1104     ok(!did_recalc(hToolbar), "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n");
1105     restore_recalc_state(hToolbar);
1106     SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
1107     ok(did_recalc(hToolbar), "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n");
1108
1109     /* undocumented exstyle 0x2 seems to changes the top margin, what
1110      * interferes with these tests */
1111
1112     DestroyWindow(hToolbar);
1113 }
1114
1115 static void test_getbuttoninfo(void)
1116 {
1117     HWND hToolbar = NULL;
1118     int i;
1119
1120     rebuild_toolbar_with_buttons(&hToolbar);
1121     for (i = 0; i < 128; i++)
1122     {
1123         TBBUTTONINFO tbi;
1124         int ret;
1125
1126         tbi.cbSize = i;
1127         tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
1128         ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi);
1129         if (i == sizeof(TBBUTTONINFO)) {
1130             compare(ret, 0, "%d");
1131         } else {
1132             compare(ret, -1, "%d");
1133         }
1134     }
1135     DestroyWindow(hToolbar);
1136 }
1137
1138 static void test_createtoolbarex(void)
1139 {
1140     HWND hToolbar;
1141     TBBUTTON btns[3];
1142     ZeroMemory(&btns, sizeof(btns));
1143
1144     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1145         3, 20, 20, 16, 16, sizeof(TBBUTTON));
1146     CHECK_IMAGELIST(16, 20, 20);
1147     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x");
1148     DestroyWindow(hToolbar);
1149
1150     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1151         3, 4, 4, 16, 16, sizeof(TBBUTTON));
1152     CHECK_IMAGELIST(32, 4, 4);
1153     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x");
1154     DestroyWindow(hToolbar);
1155
1156     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1157         3, 0, 8, 12, 12, sizeof(TBBUTTON));
1158     CHECK_IMAGELIST(16, 12, 12);
1159     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x");
1160     DestroyWindow(hToolbar);
1161
1162     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1163         3, -1, 8, 12, 12, sizeof(TBBUTTON));
1164     CHECK_IMAGELIST(16, 12, 8);
1165     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x");
1166     DestroyWindow(hToolbar);
1167
1168     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1169         3, -1, 8, -1, 12, sizeof(TBBUTTON));
1170     CHECK_IMAGELIST(16, 16, 8);
1171     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x");
1172     DestroyWindow(hToolbar);
1173
1174     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1175         3, 0, 0, 12, -1, sizeof(TBBUTTON));
1176     CHECK_IMAGELIST(16, 12, 16);
1177     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x");
1178     DestroyWindow(hToolbar);
1179
1180     hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
1181         3, 0, 0, 0, 12, sizeof(TBBUTTON));
1182     CHECK_IMAGELIST(16, 16, 16);
1183     compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x");
1184     DestroyWindow(hToolbar);
1185 }
1186
1187 static void test_dispinfo(void)
1188 {
1189     HWND hToolbar = NULL;
1190     const TBBUTTON buttons_disp[] = {
1191         {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1192         {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
1193     };
1194     BOOL ret;
1195
1196     rebuild_toolbar(&hToolbar);
1197     SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
1198     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp);
1199     g_dwExpectedDispInfoMask = 1;
1200     /* Some TBN_GETDISPINFO tests will be done in MyWnd_Notify function.
1201      * We will receive TBN_GETDISPINFOW even if the control is ANSI */
1202     compare((BOOL)SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0, "%d");
1203     ShowWindow(hToolbar, SW_SHOW);
1204     UpdateWindow(hToolbar);
1205
1206     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, TRUE, 0);
1207     compare(ret, FALSE, "%d");
1208     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 1L, "%ld");
1209     InvalidateRect(hToolbar, NULL, FALSE);
1210     UpdateWindow(hToolbar);
1211
1212     ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
1213     compare(ret, TRUE, "%d");
1214     compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0L, "%ld");
1215     InvalidateRect(hToolbar, NULL, FALSE);
1216     UpdateWindow(hToolbar);
1217
1218     DestroyWindow(hToolbar);
1219     g_dwExpectedDispInfoMask = 0;
1220 }
1221
1222 typedef struct
1223 {
1224     int  nRows;
1225     BOOL bLarger;
1226     int  expectedRows;
1227 } tbrows_result_t;
1228
1229 static tbrows_result_t tbrows_results[] =
1230 {
1231     {1, TRUE,  1}, /* 0: Simple case 9 in a row */
1232     {2, TRUE,  2}, /* 1: Another simple case 5 on one row, 4 on another*/
1233     {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */
1234     {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */
1235     {8, TRUE,  9}, /* 4: 8 lines but grow - should be 9 lines */
1236     {1, TRUE,  1}  /* 5: Back to simple case */
1237 };
1238
1239 static void test_setrows(void)
1240 {
1241     TBBUTTON buttons[9];
1242     HWND hToolbar;
1243     int i;
1244
1245     for (i=0; i<9; i++)
1246         MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0);
1247
1248     /* Test 1 - 9 buttons */
1249     hToolbar = CreateToolbarEx(hMainWnd,
1250         WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN
1251         | CCS_NOMOVEY | CCS_TOP,
1252         0,
1253         0, NULL, 0,
1254         buttons, sizeof(buttons)/sizeof(buttons[0]),
1255         20, 20, 0, 0, sizeof(TBBUTTON));
1256     ok(hToolbar != NULL, "Toolbar creation\n");
1257     ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
1258
1259     /* test setting rows to each of 1-10 with bLarger true and false */
1260     for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) {
1261         RECT rc;
1262         int rows;
1263
1264         memset(&rc, 0xCC, sizeof(rc));
1265         SendMessageA(hToolbar, TB_SETROWS,
1266                      MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger),
1267                      (LPARAM) &rc);
1268
1269         rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0));
1270         ok(rows == tbrows_results[i].expectedRows,
1271                    "[%d] Unexpected number of rows %d (expected %d)\n", i, rows,
1272                    tbrows_results[i].expectedRows);
1273     }
1274
1275     DestroyWindow(hToolbar);
1276 }
1277
1278 static void test_getstring(void)
1279 {
1280     HWND hToolbar = NULL;
1281     char str[10];
1282     WCHAR strW[10];
1283     static const char answer[] = "STR";
1284     static const WCHAR answerW[] = { 'S','T','R',0 };
1285     INT r;
1286
1287     hToolbar = CreateWindowExA(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
1288     ok(hToolbar != NULL, "Toolbar creation problem\n");
1289
1290     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
1291     if (r == 0)
1292     {
1293         win_skip("TB_GETSTRING and TB_GETSTRINGW need 5.80\n");
1294         DestroyWindow(hToolbar);
1295         return;
1296     }
1297     expect(-1, r);
1298     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1299     expect(-1, r);
1300     r = SendMessage(hToolbar, TB_ADDSTRING, 0, (LPARAM)answer);
1301     expect(0, r);
1302     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
1303     expect(lstrlenA(answer), r);
1304     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
1305     expect(lstrlenA(answer), r);
1306     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(sizeof(str), 0), (LPARAM)str);
1307     expect(lstrlenA(answer), r);
1308     expect(0, lstrcmp(answer, str));
1309     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(sizeof(strW), 0), (LPARAM)strW);
1310     expect(lstrlenA(answer), r);
1311     expect(0, lstrcmpW(answerW, strW));
1312
1313     DestroyWindow(hToolbar);
1314 }
1315
1316 START_TEST(toolbar)
1317 {
1318     WNDCLASSA wc;
1319     MSG msg;
1320     RECT rc;
1321   
1322     InitCommonControls();
1323   
1324     wc.style = CS_HREDRAW | CS_VREDRAW;
1325     wc.cbClsExtra = 0;
1326     wc.cbWndExtra = 0;
1327     wc.hInstance = GetModuleHandleA(NULL);
1328     wc.hIcon = NULL;
1329     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
1330     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1331     wc.lpszMenuName = NULL;
1332     wc.lpszClassName = "MyTestWnd";
1333     wc.lpfnWndProc = MyWndProc;
1334     RegisterClassA(&wc);
1335     
1336     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
1337       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
1338     GetClientRect(hMainWnd, &rc);
1339     ShowWindow(hMainWnd, SW_SHOW);
1340
1341     basic_test();
1342     test_add_bitmap();
1343     test_add_string();
1344     test_hotitem();
1345     test_sizes();
1346     test_recalc();
1347     test_getbuttoninfo();
1348     test_createtoolbarex();
1349     test_dispinfo();
1350     test_setrows();
1351     test_getstring();
1352
1353     PostQuitMessage(0);
1354     while(GetMessageA(&msg,0,0,0)) {
1355         TranslateMessage(&msg);
1356         DispatchMessageA(&msg);
1357     }
1358     DestroyWindow(hMainWnd);
1359 }