mshtml: Print wine_gecko version in load_wine_gecko.
[wine] / dlls / comctl32 / tests / toolbar.c
1 /* Unit tests for treeview.
2  *
3  * Copyright 2005 Krzysztof Foltman
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "commctrl.h" 
30
31 #include "resources.h"
32
33 #include "wine/test.h"
34
35 HWND hMainWnd;
36 BOOL g_fBlockHotItemChange;
37 BOOL g_fReceivedHotItemChange;
38 BOOL g_fExpectedHotItemOld;
39 BOOL g_fExpectedHotItemNew;
40  
41 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
42
43 static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
44   p->iBitmap = -2;
45   p->idCommand = idCommand;
46   p->fsState = TBSTATE_ENABLED;
47   p->fsStyle = fsStyle;
48   p->iString = nString;
49 }
50
51 static LRESULT MyWnd_Notify(LPARAM lParam)
52 {
53     NMHDR *hdr = (NMHDR *)lParam;
54     NMTBHOTITEM *nmhi;
55     switch (hdr->code)
56     {
57         case TBN_HOTITEMCHANGE:
58             nmhi = (NMTBHOTITEM *)lParam;
59             g_fReceivedHotItemChange = TRUE;
60             if (g_fExpectedHotItemOld != g_fExpectedHotItemNew)
61             {
62                 compare(nmhi->idOld, g_fExpectedHotItemOld, "%d");
63                 compare(nmhi->idNew, g_fExpectedHotItemNew, "%d");
64             }
65             if (g_fBlockHotItemChange)
66                 return 1;
67             break;
68     }
69     return 0;
70 }
71
72 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
73 {
74     switch (msg)
75     {
76         case WM_NOTIFY:
77             return MyWnd_Notify(lParam);
78     }
79     return DefWindowProcA(hWnd, msg, wParam, lParam);
80 }
81
82 static void basic_test(void)
83 {
84     TBBUTTON buttons[9];
85     HWND hToolbar;
86     int i;
87     for (i=0; i<9; i++)
88         MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
89     MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
90     MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
91
92     hToolbar = CreateToolbarEx(hMainWnd,
93         WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
94         WS_CHILD | TBSTYLE_LIST,
95         100,
96         0, NULL, (UINT)0,
97         buttons, sizeof(buttons)/sizeof(buttons[0]),
98         0, 0, 20, 16, sizeof(TBBUTTON));
99     ok(hToolbar != NULL, "Toolbar creation\n");
100     SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
101
102     /* test for exclusion working inside a separator-separated :-) group */
103     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
104     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
105     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
106
107     SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
108     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
109     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
110
111     SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
112     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
113     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
114
115     /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
116     SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
117     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
118     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
119     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
120
121     SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
122     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
123     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
124     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
125
126     SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
127     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
128     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
129     ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
130     ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
131     DestroyWindow(hToolbar);
132 }
133
134 static void rebuild_toolbar(HWND *hToolbar)
135 {
136     if (*hToolbar != NULL)
137         DestroyWindow(*hToolbar);
138     *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
139         hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
140     ok(*hToolbar != NULL, "Toolbar creation problem\n");
141     ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
142     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
143 }
144
145 void rebuild_toolbar_with_buttons(HWND *hToolbar)
146 {
147     TBBUTTON buttons[5];
148     rebuild_toolbar(hToolbar);
149     
150     ZeroMemory(&buttons, sizeof(buttons));
151     buttons[0].idCommand = 1;
152     buttons[0].fsStyle = BTNS_BUTTON;
153     buttons[0].fsState = TBSTATE_ENABLED;
154     buttons[1].idCommand = 3;
155     buttons[1].fsStyle = BTNS_BUTTON;
156     buttons[1].fsState = TBSTATE_ENABLED;
157     buttons[2].idCommand = 5;
158     buttons[2].fsStyle = BTNS_SEP;
159     buttons[2].fsState = TBSTATE_ENABLED;
160     buttons[3].idCommand = 7;
161     buttons[3].fsStyle = BTNS_BUTTON;
162     buttons[3].fsState = TBSTATE_ENABLED;
163     buttons[4].idCommand = 9;
164     buttons[4].fsStyle = BTNS_BUTTON;
165     buttons[4].fsState = 0;  /* disabled */
166     ok(SendMessage(*hToolbar, TB_ADDBUTTONS, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONS failed\n");
167     ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
168 }
169
170
171 #define CHECK_IMAGELIST(count, dx, dy) { \
172     int cx, cy; \
173     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
174     ok(himl != NULL, "No image list\n"); \
175     if (himl != NULL) {\
176         ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
177         ImageList_GetIconSize(himl, &cx, &cy); \
178         ok(cx == dx && cy == cy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
179     } \
180 }
181
182 #define CHECK_IMAGELIST_TODO_COUNT(count, dx, dy) { \
183     int cx, cy; \
184     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
185     ok(himl != NULL, "No image list\n"); \
186     if (himl != NULL) {\
187         todo_wine ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
188         ImageList_GetIconSize(himl, &cx, &cy); \
189         ok(cx == dx && cy == cy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
190     } \
191 }
192
193 #define CHECK_IMAGELIST_TODO_COUNT_SIZE(count, dx, dy) { \
194     int cx, cy; \
195     HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
196     ok(himl != NULL, "No image list\n"); \
197     if (himl != NULL) {\
198         todo_wine ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
199         ImageList_GetIconSize(himl, &cx, &cy); \
200         todo_wine ok(cx == dx && cy == cy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
201     } \
202 }
203
204 static void test_add_bitmap(void)
205 {
206     HWND hToolbar = NULL;
207     TBADDBITMAP bmp128;
208     TBADDBITMAP bmp80;
209     TBADDBITMAP stdsmall;
210     TBADDBITMAP addbmp;
211     HIMAGELIST himl;
212     INT ret;
213
214     /* empty 128x15 bitmap */
215     bmp128.hInst = GetModuleHandle(NULL);
216     bmp128.nID = IDB_BITMAP_128x15;
217
218     /* empty 80x15 bitmap */
219     bmp80.hInst = GetModuleHandle(NULL);
220     bmp80.nID = IDB_BITMAP_80x15;
221
222     /* standard bitmap - 240x15 pixels */
223     stdsmall.hInst = HINST_COMMCTRL;
224     stdsmall.nID = IDB_STD_SMALL_COLOR;
225
226     rebuild_toolbar(&hToolbar);
227     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
228     CHECK_IMAGELIST(8, 16, 15);
229     
230     /* adding more bitmaps */
231     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n");
232     CHECK_IMAGELIST(13, 16, 15);
233     /* adding the same bitmap will simply return the index of the already loaded block */
234     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128);
235     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
236     CHECK_IMAGELIST(13, 16, 15);
237     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
238     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
239     CHECK_IMAGELIST(13, 16, 15);
240     /* even if we increase the wParam */
241     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80);
242     ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
243     CHECK_IMAGELIST(13, 16, 15);
244
245     /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/
246     rebuild_toolbar(&hToolbar);
247     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
248     CHECK_IMAGELIST(8, 16, 15);
249     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
250     ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret);
251     /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */
252     CHECK_IMAGELIST(13, 16, 15);
253
254     /* the same for negative wParam */
255     rebuild_toolbar(&hToolbar);
256     ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128);
257     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
258     CHECK_IMAGELIST(8, 16, 15);
259     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
260     ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret);
261     CHECK_IMAGELIST(13, 16, 15);
262
263     /* for zero only one bitmap will be added */
264     rebuild_toolbar(&hToolbar);
265     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80);
266     ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
267     CHECK_IMAGELIST(1, 16, 15);
268
269     /* if wParam is larger than the amount of icons, the list is grown */
270     rebuild_toolbar(&hToolbar);
271     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
272     CHECK_IMAGELIST(100, 16, 15);
273     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128);
274     ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret);
275     CHECK_IMAGELIST(200, 16, 15);
276
277     /* adding built-in items - the wParam is ignored */
278     rebuild_toolbar(&hToolbar);
279     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
280     CHECK_IMAGELIST(5, 16, 15);
281     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n");
282     CHECK_IMAGELIST(20, 16, 15);
283     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n");
284     CHECK_IMAGELIST(28, 16, 15);
285
286     /* when we increase the bitmap size, less icons will be created */
287     rebuild_toolbar(&hToolbar);
288     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n");
289     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
290     CHECK_IMAGELIST(6, 20, 20);
291     ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
292     ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret);
293     CHECK_IMAGELIST(10, 20, 20);
294     /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */
295     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
296     UpdateWindow(hToolbar);
297     CHECK_IMAGELIST(26, 8, 8);
298     /* loading a standard bitmaps automatically resizes the icons */
299     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n");
300     UpdateWindow(hToolbar);
301     CHECK_IMAGELIST(28, 16, 15);
302
303     /* two more SETBITMAPSIZE tests */
304     rebuild_toolbar(&hToolbar);
305     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
306     CHECK_IMAGELIST(100, 16, 15);
307     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n");
308     CHECK_IMAGELIST(200, 16, 15);
309     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
310     UpdateWindow(hToolbar);
311     CHECK_IMAGELIST(200, 8, 8);
312     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
313     UpdateWindow(hToolbar);
314     CHECK_IMAGELIST(200, 30, 30);
315     rebuild_toolbar(&hToolbar);
316     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
317     CHECK_IMAGELIST(8, 16, 15);
318     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n");
319     CHECK_IMAGELIST(13, 16, 15);
320     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
321     UpdateWindow(hToolbar);
322     CHECK_IMAGELIST(8, 30, 30);
323
324     /* the control can add bitmaps to an existing image list */
325     rebuild_toolbar(&hToolbar);
326     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
327     ok(himl != NULL, "failed to create imagelist\n");
328     ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
329     CHECK_IMAGELIST(4, 20, 15);
330     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
331     CHECK_IMAGELIST(10, 20, 15);
332     /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change!) */
333     ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
334     UpdateWindow(hToolbar);
335     CHECK_IMAGELIST(10, 20, 15);
336     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n");
337     UpdateWindow(hToolbar);
338     CHECK_IMAGELIST_TODO_COUNT(22, 20, 15);
339
340     /* check standard bitmaps */
341     addbmp.hInst = HINST_COMMCTRL;
342     addbmp.nID = IDB_STD_SMALL_COLOR;
343     rebuild_toolbar(&hToolbar);
344     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
345     CHECK_IMAGELIST(15, 16, 15);
346     addbmp.nID = IDB_STD_LARGE_COLOR;
347     rebuild_toolbar(&hToolbar);
348     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
349     CHECK_IMAGELIST(15, 24, 24);
350
351     addbmp.nID = IDB_VIEW_SMALL_COLOR;
352     rebuild_toolbar(&hToolbar);
353     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
354     CHECK_IMAGELIST(12, 16, 15);
355     addbmp.nID = IDB_VIEW_LARGE_COLOR;
356     rebuild_toolbar(&hToolbar);
357     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
358     CHECK_IMAGELIST(12, 24, 24);
359
360     addbmp.nID = IDB_HIST_SMALL_COLOR;
361     rebuild_toolbar(&hToolbar);
362     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
363     CHECK_IMAGELIST(5, 16, 15);
364     addbmp.nID = IDB_HIST_LARGE_COLOR;
365     rebuild_toolbar(&hToolbar);
366     ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
367     CHECK_IMAGELIST(5, 24, 24);
368
369
370     DestroyWindow(hToolbar);
371 }
372
373 #define CHECK_STRING_TABLE(count, tab) { \
374         INT _i; \
375         CHAR _buf[260]; \
376         for (_i = 0; _i < (count); _i++) {\
377             ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, _i), (LPARAM)_buf); \
378             ok(ret >= 0, "TB_GETSTRING - unexpected return %d while checking string %d\n", ret, _i); \
379             if (ret >= 0) \
380                 ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \
381         } \
382         ok(SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \
383             "Too many string in table\n"); \
384     }
385
386 void test_add_string()
387 {
388     LPCSTR test1 = "a\0b\0";
389     LPCSTR test2 = "|a|b||\0";
390     LPCSTR ret1[] = {"a", "b"};
391     LPCSTR ret2[] = {"a", "b", "|a|b||"};
392     LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"};
393     LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"};
394     LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"};
395     LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"};
396     LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"};
397     HWND hToolbar = NULL;
398     TBBUTTON button;
399     int ret;
400
401     rebuild_toolbar(&hToolbar);
402     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
403     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
404     CHECK_STRING_TABLE(2, ret1);
405     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
406     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
407     CHECK_STRING_TABLE(3, ret2);
408
409     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1);
410     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
411     CHECK_STRING_TABLE(3, ret2);
412     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2);
413     ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
414     CHECK_STRING_TABLE(5, ret3);
415     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3);
416     ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
417     CHECK_STRING_TABLE(6, ret4);
418     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4);
419     ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
420     CHECK_STRING_TABLE(8, ret5);
421     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5);
422     ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
423     CHECK_STRING_TABLE(11, ret6);
424     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7);
425     ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
426     CHECK_STRING_TABLE(14, ret7);
427
428     ZeroMemory(&button, sizeof(button));
429     button.iString = (UINT_PTR)"Test";
430     SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
431     CHECK_STRING_TABLE(14, ret7);
432     SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
433     CHECK_STRING_TABLE(14, ret7);
434 }
435
436 static void expect_hot_notify(int idold, int idnew)
437 {
438     g_fExpectedHotItemOld = idold;
439     g_fExpectedHotItemNew = idnew;
440     g_fReceivedHotItemChange = FALSE;
441 }
442
443 #define check_hot_notify() \
444     ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
445     g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
446
447 void test_hotitem()
448 {
449     HWND hToolbar = NULL;
450     TBBUTTONINFO tbinfo;
451     LRESULT ret;
452
453     g_fBlockHotItemChange = FALSE;
454
455     rebuild_toolbar_with_buttons(&hToolbar);
456     /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
457      * comctl6 doesn't have this requirement even when theme == NULL */
458     SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE));
459     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
460     ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
461     ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
462     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
463     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
464     ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
465     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
466     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
467
468     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
469     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
470     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
471     ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
472     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
473     ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
474     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
475     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
476
477     expect_hot_notify(0, 7);
478     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
479     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
480     check_hot_notify();
481     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
482     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
483     g_fBlockHotItemChange = TRUE;
484     ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
485     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
486     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
487     ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
488     g_fBlockHotItemChange = FALSE;
489
490     g_fReceivedHotItemChange = FALSE;
491     ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
492     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
493     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
494
495     g_fReceivedHotItemChange = FALSE;
496     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
497     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
498     ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
499
500     expect_hot_notify(7, 0);
501     ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
502     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
503     check_hot_notify();
504     SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
505
506     /* setting disabled buttons will generate a notify with the button id but no button will be hot */
507     expect_hot_notify(7, 9);
508     ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0);
509     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
510     check_hot_notify();
511     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
512     ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
513     /* enabling the button won't change that */
514     SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
515     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
516     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
517
518     /* disabling a hot button works */
519     ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
520     ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
521     g_fReceivedHotItemChange = FALSE;
522     SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
523     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
524     ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
525     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
526
527     SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
528     tbinfo.cbSize = sizeof(TBBUTTONINFO);
529     tbinfo.dwMask = TBIF_STATE;
530     tbinfo.fsState = 0;  /* disabled */
531     g_fReceivedHotItemChange = FALSE;
532     ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n");
533     ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
534     ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
535     ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
536
537 }
538
539 START_TEST(toolbar)
540 {
541     WNDCLASSA wc;
542     MSG msg;
543     RECT rc;
544   
545     InitCommonControls();
546   
547     wc.style = CS_HREDRAW | CS_VREDRAW;
548     wc.cbClsExtra = 0;
549     wc.cbWndExtra = 0;
550     wc.hInstance = GetModuleHandleA(NULL);
551     wc.hIcon = NULL;
552     wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
553     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
554     wc.lpszMenuName = NULL;
555     wc.lpszClassName = "MyTestWnd";
556     wc.lpfnWndProc = MyWndProc;
557     RegisterClassA(&wc);
558     
559     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
560       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
561     GetClientRect(hMainWnd, &rc);
562     ShowWindow(hMainWnd, SW_SHOW);
563
564     basic_test();
565     test_add_bitmap();
566     test_add_string();
567     test_hotitem();
568
569     PostQuitMessage(0);
570     while(GetMessageA(&msg,0,0,0)) {
571         TranslateMessage(&msg);
572         DispatchMessageA(&msg);
573     }
574     DestroyWindow(hMainWnd);
575 }