1 /* Unit tests for rebar.
2  *
3  * Copyright 2007 Mikolaj Zalewski
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 /* make sure the structures work with a comctl32 v5.x */
21 #ifndef __REACTOS__
22 #define _WIN32_WINNT 0x500
23 #define _WIN32_IE 0x500
24 #endif
25 
26 #include <assert.h>
27 #include <stdarg.h>
28 
29 #include <windows.h>
30 #include <commctrl.h>
31 #include <uxtheme.h>
32 
33 #include "wine/heap.h"
34 #include "wine/test.h"
35 
36 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
37 static HIMAGELIST (WINAPI *pImageList_LoadImageA)(HINSTANCE, LPCSTR, int, int, COLORREF, UINT, UINT);
38 
39 static RECT height_change_notify_rect;
40 static HWND hMainWnd;
41 static int system_font_height;
42 
43 
44 #define check_rect(name, val, exp) ok(EqualRect(&val, &exp), \
45     "invalid rect (" name ") %s - expected %s\n", wine_dbgstr_rect(&val), wine_dbgstr_rect(&exp));
46 
47 #define check_rect_no_top(name, val, exp) { \
48         ok((val.bottom - val.top == exp.bottom - exp.top) && \
49             val.left == exp.left && val.right == exp.right, \
50             "invalid rect (" name ") %s - expected %s, ignoring top\n", \
51             wine_dbgstr_rect(&val), wine_dbgstr_rect(&exp)); }
52 
53 #define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
54 
55 #define expect_eq(line, expr, value, type, format) { type ret = expr;\
56         ok((value) == ret, #expr " expected " format "  got " format " from line %d\n", (value), (ret), line); }
57 
58 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
59 {
60     return 0;
61 }
62 
63 static BOOL is_font_installed(const char *name)
64 {
65     HDC hdc = GetDC(0);
66     BOOL ret = FALSE;
67 
68     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
69         ret = TRUE;
70 
71     ReleaseDC(0, hdc);
72     return ret;
73 }
74 
75 static void init_system_font_height(void) {
76     HDC hDC;
77     TEXTMETRICA tm;
78 
79     hDC = CreateCompatibleDC(NULL);
80     GetTextMetricsA(hDC, &tm);
81     DeleteDC(NULL);
82 
83     system_font_height = tm.tmHeight;
84 }
85 
86 static HWND create_rebar_control(void)
87 {
88     HWND hwnd;
89 
90     hwnd = CreateWindowA(REBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
91         hMainWnd, (HMENU)17, GetModuleHandleA(NULL), NULL);
92     ok(hwnd != NULL, "Failed to create Rebar\n");
93 
94     SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
95 
96     return hwnd;
97 }
98 
99 static HWND build_toolbar(int nr, HWND hParent)
100 {
101     TBBUTTON btns[8];
102     HWND hToolbar = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE, 0, 0, 0, 0,
103         hParent, (HMENU)5, GetModuleHandleA(NULL), NULL);
104     int iBitmapId = 0;
105     int i;
106 
107     ok(hToolbar != NULL, "Toolbar creation problem\n");
108     ok(SendMessageA(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
109     ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
110     ok(SendMessageA(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
111 
112     for (i=0; i<5+nr; i++)
113     {
114         btns[i].iBitmap = i;
115         btns[i].idCommand = i;
116         btns[i].fsStyle = BTNS_BUTTON;
117         btns[i].fsState = TBSTATE_ENABLED;
118         btns[i].iString = 0;
119     }
120 
121     switch (nr)
122     {
123         case 0: iBitmapId = IDB_HIST_SMALL_COLOR; break;
124         case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break;
125         case 2: iBitmapId = IDB_STD_SMALL_COLOR; break;
126     }
127     ok(SendMessageA(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGES failed\n");
128     ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 5+nr, (LPARAM)btns), "TB_ADDBUTTONSA failed\n");
129     return hToolbar;
130 }
131 
132 static int g_parent_measureitem;
133 
134 static LRESULT CALLBACK parent_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
135 {
136     switch (msg)
137     {
138         case WM_NOTIFY:
139             {
140                 NMHDR *lpnm = (NMHDR *)lParam;
141                 if (lpnm->code == RBN_HEIGHTCHANGE)
142                     GetClientRect(lpnm->hwndFrom, &height_change_notify_rect);
143             }
144             break;
145         case WM_MEASUREITEM:
146             g_parent_measureitem++;
147             break;
148     }
149     return DefWindowProcA(hWnd, msg, wParam, lParam);
150 }
151 
152 #if 0  /* use this to generate more tests*/
153 
154 static void dump_sizes(HWND hRebar)
155 {
156     SIZE sz;
157     RECT r;
158     int count;
159     int i, h;
160 
161     GetClientRect(hRebar, &r);
162     count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0);
163     printf("  { {%d, %d, %d, %d}, %d, %d, {", r.left, r.top, r.right, r.bottom,
164         SendMessageA(hRebar, RB_GETBARHEIGHT, 0, 0), count);
165     if (count == 0)
166         printf("0, ");
167     for (i = 0; i < count; i++)  /* rows */
168         printf("%d, ", SendMessageA(hRebar, RB_GETROWHEIGHT, i, 0));
169     printf("}, ");
170 
171     count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0);
172     printf("%d, {", count);
173     if (count == 0)
174         printf("{{0, 0, 0, 0}, 0, 0},");
175     for (i=0; i<count; i++)
176     {
177         REBARBANDINFOA rbi;
178         rbi.cbSize = REBARBANDINFOA_V6_SIZE;
179         rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE;
180         ok(SendMessageA(hRebar, RB_GETBANDINFOA, i, (LPARAM)&rbi), "RB_GETBANDINFOA failed\n");
181         ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&r), "RB_GETRECT failed\n");
182         printf("%s{ {%3d, %3d, %3d, %3d}, 0x%02x, %d}, ", (i%2==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom,
183             rbi.fStyle, rbi.cx);
184     }
185     printf("\n  }, },\n");
186 }
187 
188 #define check_sizes() dump_sizes(hRebar);
189 #define check_sizes_todo(todomask) dump_sizes(hRebar);
190 
191 #else
192 
193 static int string_width(const CHAR *s) {
194     SIZE sz;
195     HDC hdc;
196 
197     hdc = CreateCompatibleDC(NULL);
198     GetTextExtentPoint32A(hdc, s, strlen(s), &sz);
199     DeleteDC(hdc);
200 
201     return sz.cx;
202 }
203 
204 typedef struct {
205     RECT rc;
206     DWORD fStyle;
207     UINT cx;
208 } rbband_result_t;
209 
210 typedef struct {
211     RECT rcClient;
212     int cyBarHeight;
213     int nRows;
214     int *cyRowHeights;
215     int nBands;
216     rbband_result_t *bands;
217 } rbsize_result_t;
218 
219 static rbsize_result_t rbsize_init(int cleft, int ctop, int cright, int cbottom, int cyBarHeight, int nRows, int nBands)
220 {
221     rbsize_result_t ret;
222 
223     SetRect(&ret.rcClient, cleft, ctop, cright, cbottom);
224     ret.cyBarHeight = cyBarHeight;
225     ret.nRows = 0;
226     ret.cyRowHeights = heap_alloc_zero(nRows * sizeof(int));
227     ret.nBands = 0;
228     ret.bands = heap_alloc_zero(nBands * sizeof(*ret.bands));
229 
230     return ret;
231 }
232 
233 static void rbsize_add_row(rbsize_result_t *rbsr, int rowHeight) {
234     rbsr->cyRowHeights[rbsr->nRows] = rowHeight;
235     rbsr->nRows++;
236 }
237 
238 static void rbsize_add_band(rbsize_result_t *rbsr, int left, int top, int right, int bottom, DWORD fStyle, UINT cx)
239 {
240     SetRect(&(rbsr->bands[rbsr->nBands].rc), left, top, right, bottom);
241     rbsr->bands[rbsr->nBands].fStyle = fStyle;
242     rbsr->bands[rbsr->nBands].cx = cx;
243     rbsr->nBands++;
244 }
245 
246 static rbsize_result_t *rbsize_results;
247 
248 #define rbsize_results_num 27
249 
250 static void rbsize_results_init(void)
251 {
252     rbsize_results = heap_alloc(rbsize_results_num * sizeof(*rbsize_results));
253 
254     rbsize_results[0] = rbsize_init(0, 0, 672, 0, 0, 0, 0);
255 
256     rbsize_results[1] = rbsize_init(0, 0, 672, 4, 4, 1, 1);
257     rbsize_add_row(&rbsize_results[1], 4);
258     rbsize_add_band(&rbsize_results[1], 0, 0, 672, 4, 0x00, 200);
259 
260     rbsize_results[2] = rbsize_init(0, 0, 672, 4, 4, 1, 2);
261     rbsize_add_row(&rbsize_results[2], 4);
262     rbsize_add_band(&rbsize_results[2], 0, 0, 200, 4, 0x00, 200);
263     rbsize_add_band(&rbsize_results[2], 200, 0, 672, 4, 0x04, 200);
264 
265     rbsize_results[3] = rbsize_init(0, 0, 672, 30, 30, 1, 3);
266     rbsize_add_row(&rbsize_results[3], 30);
267     rbsize_add_band(&rbsize_results[3], 0, 0, 200, 30, 0x00, 200);
268     rbsize_add_band(&rbsize_results[3], 200, 0, 400, 30, 0x04, 200);
269     rbsize_add_band(&rbsize_results[3], 400, 0, 672, 30, 0x00, 200);
270 
271     rbsize_results[4] = rbsize_init(0, 0, 672, 34, 34, 1, 4);
272     rbsize_add_row(&rbsize_results[4], 34);
273     rbsize_add_band(&rbsize_results[4], 0, 0, 200, 34, 0x00, 200);
274     rbsize_add_band(&rbsize_results[4], 200, 0, 400, 34, 0x04, 200);
275     rbsize_add_band(&rbsize_results[4], 400, 0, 604, 34, 0x00, 200);
276     rbsize_add_band(&rbsize_results[4], 604, 0, 672, 34, 0x04, 68);
277 
278     rbsize_results[5] = rbsize_init(0, 0, 672, 34, 34, 1, 4);
279     rbsize_add_row(&rbsize_results[5], 34);
280     rbsize_add_band(&rbsize_results[5], 0, 0, 200, 34, 0x00, 200);
281     rbsize_add_band(&rbsize_results[5], 200, 0, 400, 34, 0x04, 200);
282     rbsize_add_band(&rbsize_results[5], 400, 0, 604, 34, 0x00, 200);
283     rbsize_add_band(&rbsize_results[5], 604, 0, 672, 34, 0x04, 68);
284 
285     rbsize_results[6] = rbsize_init(0, 0, 672, 34, 34, 1, 4);
286     rbsize_add_row(&rbsize_results[6], 34);
287     rbsize_add_band(&rbsize_results[6], 0, 0, 200, 34, 0x00, 200);
288     rbsize_add_band(&rbsize_results[6], 202, 0, 402, 34, 0x04, 200);
289     rbsize_add_band(&rbsize_results[6], 404, 0, 604, 34, 0x00, 200);
290     rbsize_add_band(&rbsize_results[6], 606, 0, 672, 34, 0x04, 66);
291 
292     rbsize_results[7] = rbsize_init(0, 0, 672, 70, 70, 2, 5);
293     rbsize_add_row(&rbsize_results[7], 34);
294     rbsize_add_row(&rbsize_results[7], 34);
295     rbsize_add_band(&rbsize_results[7], 0, 0, 142, 34, 0x00, 200);
296     rbsize_add_band(&rbsize_results[7], 144, 0, 557, 34, 0x00, 200);
297     rbsize_add_band(&rbsize_results[7], 559, 0, 672, 34, 0x04, 200);
298     rbsize_add_band(&rbsize_results[7], 0, 36, 200, 70, 0x00, 200);
299     rbsize_add_band(&rbsize_results[7], 202, 36, 672, 70, 0x04, 66);
300 
301     rbsize_results[8] = rbsize_init(0, 0, 672, 34, 34, 1, 5);
302     rbsize_add_row(&rbsize_results[8], 34);
303     rbsize_add_band(&rbsize_results[8], 0, 0, 167, 34, 0x00, 200);
304     rbsize_add_band(&rbsize_results[8], 169, 0, 582, 34, 0x00, 200);
305     rbsize_add_band(&rbsize_results[8], 559, 0, 759, 34, 0x08, 200);
306     rbsize_add_band(&rbsize_results[8], 584, 0, 627, 34, 0x00, 200);
307     rbsize_add_band(&rbsize_results[8], 629, 0, 672, 34, 0x04, 66);
308 
309     rbsize_results[9] = rbsize_init(0, 0, 672, 34, 34, 1, 4);
310     rbsize_add_row(&rbsize_results[9], 34);
311     rbsize_add_band(&rbsize_results[9], 0, 0, 167, 34, 0x00, 200);
312     rbsize_add_band(&rbsize_results[9], 169, 0, 582, 34, 0x00, 200);
313     rbsize_add_band(&rbsize_results[9], 584, 0, 627, 34, 0x00, 200);
314     rbsize_add_band(&rbsize_results[9], 629, 0, 672, 34, 0x04, 66);
315 
316     rbsize_results[10] = rbsize_init(0, 0, 672, 34, 34, 1, 3);
317     rbsize_add_row(&rbsize_results[10], 34);
318     rbsize_add_band(&rbsize_results[10], 0, 0, 413, 34, 0x00, 200);
319     rbsize_add_band(&rbsize_results[10], 415, 0, 615, 34, 0x00, 200);
320     rbsize_add_band(&rbsize_results[10], 617, 0, 672, 34, 0x04, 66);
321 
322     rbsize_results[11] = rbsize_init(0, 0, 672, 34, 34, 1, 2);
323     rbsize_add_row(&rbsize_results[11], 34);
324     rbsize_add_band(&rbsize_results[11], 0, 0, 604, 34, 0x00, 200);
325     rbsize_add_band(&rbsize_results[11], 606, 0, 672, 34, 0x04, 66);
326 
327     rbsize_results[12] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
328     rbsize_add_row(&rbsize_results[12], 4 + system_font_height);
329     rbsize_add_row(&rbsize_results[12], 4 + system_font_height);
330     rbsize_add_band(&rbsize_results[12], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
331     rbsize_add_band(&rbsize_results[12], 87 + string_width("ABC"), 0, 157 + string_width("ABC"), 4 + system_font_height, 0x00, 70);
332     rbsize_add_band(&rbsize_results[12], 157 + string_width("ABC"), 0, 397 + string_width("ABC"), 4 + system_font_height, 0x00, 240);
333     rbsize_add_band(&rbsize_results[12], 397 + string_width("ABC"), 0, 672, 4 + system_font_height, 0x00, 60);
334     rbsize_add_band(&rbsize_results[12], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
335 
336     rbsize_results[13] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
337     rbsize_add_row(&rbsize_results[13], 4 + system_font_height);
338     rbsize_add_row(&rbsize_results[13], 4 + system_font_height);
339     rbsize_add_band(&rbsize_results[13], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
340     rbsize_add_band(&rbsize_results[13], 87 + string_width("ABC"), 0, 200 + string_width("ABC"), 4 + system_font_height, 0x00, 113);
341     rbsize_add_band(&rbsize_results[13], 200 + string_width("ABC"), 0, 397 + string_width("ABC"), 4 + system_font_height, 0x00, 197);
342     rbsize_add_band(&rbsize_results[13], 397 + string_width("ABC"), 0, 672, 4 + system_font_height, 0x00, 60);
343     rbsize_add_band(&rbsize_results[13], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
344 
345     rbsize_results[14] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
346     rbsize_add_row(&rbsize_results[14], 4 + system_font_height);
347     rbsize_add_row(&rbsize_results[14], 4 + system_font_height);
348     rbsize_add_band(&rbsize_results[14], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
349     rbsize_add_band(&rbsize_results[14], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
350     rbsize_add_band(&rbsize_results[14], 412 - string_width("MMMMMMM"), 0, 595 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 183);
351     rbsize_add_band(&rbsize_results[14], 595 - string_width("MMMMMMM"), 0, 672, 4 + system_font_height, 0x00, 77 + string_width("MMMMMMM"));
352     rbsize_add_band(&rbsize_results[14], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
353 
354     rbsize_results[15] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
355     rbsize_add_row(&rbsize_results[15], 4 + system_font_height);
356     rbsize_add_row(&rbsize_results[15], 4 + system_font_height);
357     rbsize_add_band(&rbsize_results[15], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
358     rbsize_add_band(&rbsize_results[15], 87 + string_width("ABC"), 0, 140 + string_width("ABC"), 4 + system_font_height, 0x00, 53);
359     rbsize_add_band(&rbsize_results[15], 140 + string_width("ABC"), 0, 595 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 455 - string_width("MMMMMMM") - string_width("ABC"));
360     rbsize_add_band(&rbsize_results[15], 595 - string_width("MMMMMMM"), 0, 672, 4 + system_font_height, 0x00, 77 + string_width("MMMMMMM"));
361     rbsize_add_band(&rbsize_results[15], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
362 
363     rbsize_results[16] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
364     rbsize_add_row(&rbsize_results[16], 4 + system_font_height);
365     rbsize_add_row(&rbsize_results[16], 4 + system_font_height);
366     rbsize_add_band(&rbsize_results[16], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
367     rbsize_add_band(&rbsize_results[16], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
368     rbsize_add_band(&rbsize_results[16], 412 - string_width("MMMMMMM"), 0, 595 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 183);
369     rbsize_add_band(&rbsize_results[16], 595 - string_width("MMMMMMM"), 0, 672, 4 + system_font_height, 0x00, 77 + string_width("MMMMMMM"));
370     rbsize_add_band(&rbsize_results[16], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
371 
372     rbsize_results[17] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
373     rbsize_add_row(&rbsize_results[17], 4 + system_font_height);
374     rbsize_add_row(&rbsize_results[17], 4 + system_font_height);
375     rbsize_add_band(&rbsize_results[17], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
376     rbsize_add_band(&rbsize_results[17], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
377     rbsize_add_band(&rbsize_results[17], 412 - string_width("MMMMMMM"), 0, 595 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 183);
378     rbsize_add_band(&rbsize_results[17], 595 - string_width("MMMMMMM"), 0, 672, 4 + system_font_height, 0x00, 77 + string_width("MMMMMMM"));
379     rbsize_add_band(&rbsize_results[17], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
380 
381     rbsize_results[18] = rbsize_init(0, 0, 672, 56, 56, 2, 5);
382     rbsize_add_row(&rbsize_results[18], 28);
383     rbsize_add_row(&rbsize_results[18], 28);
384     rbsize_add_band(&rbsize_results[18], 0, 0, 87 + string_width("ABC"), 28, 0x00, 40);
385     rbsize_add_band(&rbsize_results[18], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 28, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
386     rbsize_add_band(&rbsize_results[18], 412 - string_width("MMMMMMM"), 0, 595 - string_width("MMMMMMM"), 28, 0x00, 183);
387     rbsize_add_band(&rbsize_results[18], 595 - string_width("MMMMMMM"), 0, 672, 28, 0x00, 77 + string_width("MMMMMMM"));
388     rbsize_add_band(&rbsize_results[18], 0, 28, 672, 56, 0x00, 200);
389 
390     rbsize_results[19] = rbsize_init(0, 0, 672, 8 + 2*system_font_height, 40, 2, 5);
391     rbsize_add_row(&rbsize_results[19], 4 + system_font_height);
392     rbsize_add_row(&rbsize_results[19], 4 + system_font_height);
393     rbsize_add_band(&rbsize_results[19], 0, 0, 87 + string_width("ABC"), 4 + system_font_height, 0x00, 40);
394     rbsize_add_band(&rbsize_results[19], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
395     rbsize_add_band(&rbsize_results[19], 412 - string_width("MMMMMMM"), 0, 595 - string_width("MMMMMMM"), 4 + system_font_height, 0x00, 183);
396     rbsize_add_band(&rbsize_results[19], 595 - string_width("MMMMMMM"), 0, 672, 4 + system_font_height, 0x00, 77 + string_width("MMMMMMM"));
397     rbsize_add_band(&rbsize_results[19], 0, 4 + system_font_height, 672, 8 + 2*system_font_height, 0x00, 200);
398 
399     rbsize_results[20] = rbsize_init(0, 0, 672, 56, 56, 2, 5);
400     rbsize_add_row(&rbsize_results[20], 28);
401     rbsize_add_row(&rbsize_results[20], 28);
402     rbsize_add_band(&rbsize_results[20], 0, 0, 87 + string_width("ABC"), 28, 0x00, 40);
403     rbsize_add_band(&rbsize_results[20], 87 + string_width("ABC"), 0, 412 - string_width("MMMMMMM"), 28, 0x00, 325 - string_width("ABC") - string_width("MMMMMMM"));
404     rbsize_add_band(&rbsize_results[20], 412 - string_width("MMMMMMM"), 0,  595 - string_width("MMMMMMM"), 28, 0x00, 183);
405     rbsize_add_band(&rbsize_results[20],  595 - string_width("MMMMMMM"), 0, 672, 28, 0x00, 77 + string_width("MMMMMMM"));
406     rbsize_add_band(&rbsize_results[20], 0, 28, 672, 56, 0x00, 200);
407 
408     rbsize_results[21] = rbsize_init(0, 0, 672, 0, 0, 0, 0);
409 
410     rbsize_results[22] = rbsize_init(0, 0, 672, 65, 56, 1, 3);
411     rbsize_add_row(&rbsize_results[22], 65);
412     rbsize_add_band(&rbsize_results[22], 0, 0, 90, 65, 0x40, 90);
413     rbsize_add_band(&rbsize_results[22], 90, 0, 180, 65, 0x40, 90);
414     rbsize_add_band(&rbsize_results[22], 180, 0, 672, 65, 0x40, 90);
415 
416     rbsize_results[23] = rbsize_init(0, 0, 0, 226, 0, 0, 0);
417 
418     rbsize_results[24] = rbsize_init(0, 0, 65, 226, 65, 1, 1);
419     rbsize_add_row(&rbsize_results[24], 65);
420     rbsize_add_band(&rbsize_results[24], 0, 0, 226, 65, 0x40, 90);
421 
422     rbsize_results[25] = rbsize_init(0, 0, 65, 226, 65, 1, 2);
423     rbsize_add_row(&rbsize_results[25], 65);
424     rbsize_add_band(&rbsize_results[25], 0, 0, 90, 65, 0x40, 90);
425     rbsize_add_band(&rbsize_results[25], 90, 0, 226, 65, 0x40, 90);
426 
427     rbsize_results[26] = rbsize_init(0, 0, 65, 226, 65, 1, 3);
428     rbsize_add_row(&rbsize_results[26], 65);
429     rbsize_add_band(&rbsize_results[26], 0, 0, 90, 65, 0x40, 90);
430     rbsize_add_band(&rbsize_results[26], 90, 0, 163, 65, 0x40, 90);
431     rbsize_add_band(&rbsize_results[26], 163, 0, 226, 65, 0x40, 90);
432 }
433 
434 static void rbsize_results_free(void)
435 {
436     int i;
437 
438     for (i = 0; i < rbsize_results_num; i++) {
439         heap_free(rbsize_results[i].cyRowHeights);
440         heap_free(rbsize_results[i].bands);
441     }
442     heap_free(rbsize_results);
443     rbsize_results = NULL;
444 }
445 
446 static int rbsize_numtests = 0;
447 
448 #define check_sizes_todo(todomask) { \
449         RECT rc; \
450         REBARBANDINFOA rbi; \
451         int count, i/*, mask=(todomask)*/; \
452         const rbsize_result_t *res = &rbsize_results[rbsize_numtests]; \
453         GetClientRect(hRebar, &rc); \
454         check_rect("client", rc, res->rcClient); \
455         count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0); \
456         compare(count, res->nRows, "%d"); \
457         for (i=0; i<min(count, res->nRows); i++) { \
458             int height = SendMessageA(hRebar, RB_GETROWHEIGHT, 0, 0);\
459             ok(height == res->cyRowHeights[i], "Height mismatch for row %d - %d vs %d\n", i, res->cyRowHeights[i], height); \
460         } \
461         count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0); \
462         compare(count, res->nBands, "%d"); \
463         for (i=0; i<min(count, res->nBands); i++) { \
464             ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_GETRECT\n"); \
465             if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
466                 check_rect("band", rc, res->bands[i].rc); \
467             rbi.cbSize = REBARBANDINFOA_V6_SIZE; \
468             rbi.fMask = RBBIM_STYLE | RBBIM_SIZE; \
469             ok(SendMessageA(hRebar, RB_GETBANDINFOA,  i, (LPARAM)&rbi) == 1, "RB_GETBANDINFOA\n"); \
470             compare(rbi.fStyle, res->bands[i].fStyle, "%x"); \
471             compare(rbi.cx, res->bands[i].cx, "%d"); \
472         } \
473         rbsize_numtests++; \
474     }
475 
476 #define check_sizes() check_sizes_todo(0)
477 
478 #endif
479 
480 static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal)
481 {
482     CHAR buffer[MAX_PATH];
483     REBARBANDINFOA rbi;
484 
485     if (lpszText != NULL)
486         strcpy(buffer, lpszText);
487     rbi.cbSize = REBARBANDINFOA_V6_SIZE;
488     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT;
489     rbi.cx = cx;
490     rbi.cxMinChild = cxMinChild;
491     rbi.cxIdeal = cxIdeal;
492     rbi.cyMinChild = 20;
493     rbi.hwndChild = build_toolbar(1, hRebar);
494     rbi.lpText = (lpszText ? buffer : NULL);
495     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
496 }
497 
498 static void test_layout(void)
499 {
500     HWND hRebar;
501     REBARBANDINFOA rbi;
502     HIMAGELIST himl;
503     REBARINFO ri;
504 
505     rbsize_results_init();
506 
507     hRebar = create_rebar_control();
508     check_sizes();
509     rbi.cbSize = REBARBANDINFOA_V6_SIZE;
510     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
511     rbi.cx = 200;
512     rbi.cxMinChild = 100;
513     rbi.cyMinChild = 30;
514     rbi.hwndChild = NULL;
515     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
516     check_sizes();
517 
518     rbi.fMask |= RBBIM_STYLE;
519     rbi.fStyle = RBBS_CHILDEDGE;
520     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
521     check_sizes();
522 
523     rbi.fStyle = 0;
524     rbi.cx = 200;
525     rbi.cxMinChild = 30;
526     rbi.cyMinChild = 30;
527     rbi.hwndChild = build_toolbar(0, hRebar);
528     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
529     check_sizes();
530 
531     rbi.fStyle = RBBS_CHILDEDGE;
532     rbi.cx = 68;
533     rbi.hwndChild = build_toolbar(0, hRebar);
534     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
535     check_sizes();
536 
537     SetWindowLongA(hRebar, GWL_STYLE, GetWindowLongA(hRebar, GWL_STYLE) | RBS_BANDBORDERS);
538     check_sizes();      /* a style change won't start a relayout */
539     rbi.fMask = RBBIM_SIZE;
540     rbi.cx = 66;
541     SendMessageA(hRebar, RB_SETBANDINFOA, 3, (LPARAM)&rbi);
542     check_sizes();      /* here it will be relayouted */
543 
544     /* this will force a new row */
545     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
546     rbi.cx = 200;
547     rbi.cxMinChild = 400;
548     rbi.cyMinChild = 30;
549     rbi.hwndChild = build_toolbar(0, hRebar);
550     SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rbi);
551     check_sizes();
552 
553     rbi.fMask = RBBIM_STYLE;
554     rbi.fStyle = RBBS_HIDDEN;
555     SendMessageA(hRebar, RB_SETBANDINFOA, 2, (LPARAM)&rbi);
556     check_sizes();
557 
558     SendMessageA(hRebar, RB_DELETEBAND, 2, 0);
559     check_sizes();
560     SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
561     check_sizes();
562     SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
563     check_sizes();
564 
565     DestroyWindow(hRebar);
566 
567     hRebar = create_rebar_control();
568     add_band_w(hRebar, "ABC",     70,  40, 100);
569     add_band_w(hRebar, NULL,      40,  70, 100);
570     add_band_w(hRebar, NULL,     170, 240, 100);
571     add_band_w(hRebar, "MMMMMMM", 60,  60, 100);
572     add_band_w(hRebar, NULL,     200, 200, 100);
573     check_sizes();
574     SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
575     check_sizes();
576     SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
577     check_sizes();
578     SendMessageA(hRebar, RB_MAXIMIZEBAND, 2, FALSE);
579     check_sizes();
580     SendMessageA(hRebar, RB_MINIMIZEBAND, 2, 0);
581     check_sizes();
582     SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 0);
583     check_sizes();
584 
585     /* an image will increase the band height */
586     himl = pImageList_LoadImageA(GetModuleHandleA("comctl32"), MAKEINTRESOURCEA(121), 24, 2,
587             CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
588     ri.cbSize = sizeof(ri);
589     ri.fMask = RBIM_IMAGELIST;
590     ri.himl = himl;
591     ok(SendMessageA(hRebar, RB_SETBARINFO, 0, (LPARAM)&ri), "RB_SETBARINFO failed\n");
592     rbi.fMask = RBBIM_IMAGE;
593     rbi.iImage = 1;
594     SendMessageA(hRebar, RB_SETBANDINFOA, 1, (LPARAM)&rbi);
595     check_sizes();
596 
597     /* after removing it everything is back to normal*/
598     rbi.iImage = -1;
599     SendMessageA(hRebar, RB_SETBANDINFOA, 1, (LPARAM)&rbi);
600     check_sizes();
601 
602     /* Only -1 means that the image is not present. Other invalid values increase the height */
603     rbi.iImage = -2;
604     SendMessageA(hRebar, RB_SETBANDINFOA, 1, (LPARAM)&rbi);
605     check_sizes();
606 
607     DestroyWindow(hRebar);
608 
609     /* VARHEIGHT resizing test on a horizontal rebar */
610     hRebar = create_rebar_control();
611     SetWindowLongA(hRebar, GWL_STYLE, GetWindowLongA(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
612     check_sizes();
613     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
614     rbi.fStyle = RBBS_VARIABLEHEIGHT;
615     rbi.cxMinChild = 50;
616     rbi.cyMinChild = 10;
617     rbi.cyIntegral = 11;
618     rbi.cyChild = 70;
619     rbi.cyMaxChild = 200;
620     rbi.cx = 90;
621     rbi.hwndChild = build_toolbar(0, hRebar);
622     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
623 
624     rbi.cyChild = 50;
625     rbi.hwndChild = build_toolbar(0, hRebar);
626     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
627 
628     rbi.cyMinChild = 40;
629     rbi.cyChild = 50;
630     rbi.cyIntegral = 5;
631     rbi.hwndChild = build_toolbar(0, hRebar);
632     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
633     check_sizes();
634 
635     DestroyWindow(hRebar);
636 
637     /* VARHEIGHT resizing on a vertical rebar */
638     hRebar = create_rebar_control();
639     SetWindowLongA(hRebar, GWL_STYLE, GetWindowLongA(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
640     check_sizes();
641     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
642     rbi.fStyle = RBBS_VARIABLEHEIGHT;
643     rbi.cxMinChild = 50;
644     rbi.cyMinChild = 10;
645     rbi.cyIntegral = 11;
646     rbi.cyChild = 70;
647     rbi.cyMaxChild = 90;
648     rbi.cx = 90;
649     rbi.hwndChild = build_toolbar(0, hRebar);
650     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
651     check_sizes();
652 
653     rbi.cyChild = 50;
654     rbi.hwndChild = build_toolbar(0, hRebar);
655     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
656     check_sizes();
657 
658     rbi.cyMinChild = 40;
659     rbi.cyChild = 50;
660     rbi.cyIntegral = 5;
661     rbi.hwndChild = build_toolbar(0, hRebar);
662     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
663     check_sizes();
664 
665     rbsize_results_free();
666     DestroyWindow(hRebar);
667     pImageList_Destroy(himl);
668 }
669 
670 #if 0       /* use this to generate more tests */
671 
672 static void dump_client(HWND hRebar)
673 {
674     RECT r;
675     BOOL notify;
676     GetWindowRect(hRebar, &r);
677     MapWindowPoints(HWND_DESKTOP, hMainWnd, &r, 2);
678     if (height_change_notify_rect.top != -1)
679     {
680         RECT rcClient;
681         GetClientRect(hRebar, &rcClient);
682         assert(EqualRect(&rcClient, &height_change_notify_rect));
683         notify = TRUE;
684     }
685     else
686         notify = FALSE;
687     printf("    {{%d, %d, %d, %d}, %d, %s},\n", r.left, r.top, r.right, r.bottom, SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0),
688         notify ? "TRUE" : "FALSE");
689     SetRect(&height_change_notify_rect, -1, -1, -1, -1);
690 }
691 
692 #define comment(fmt, arg1) printf("/* " fmt " */\n", arg1);
693 #define check_client() dump_client(hRebar)
694 
695 #else
696 
697 typedef struct {
698     RECT rc;
699     INT iNumRows;
700     BOOL heightNotify;
701 } rbresize_test_result_t;
702 
703 static const rbresize_test_result_t resize_results[] = {
704 /* style 00000001 */
705     {{0, 2, 672, 2}, 0, FALSE},
706     {{0, 2, 672, 22}, 1, TRUE},
707     {{0, 2, 672, 22}, 1, FALSE},
708     {{0, 2, 672, 22}, 1, FALSE},
709     {{0, 2, 672, 22}, 1, FALSE},
710     {{0, 2, 672, 22}, 0, FALSE},
711 /* style 00000041 */
712     {{0, 0, 672, 0}, 0, FALSE},
713     {{0, 0, 672, 20}, 1, TRUE},
714     {{0, 0, 672, 20}, 1, FALSE},
715     {{0, 0, 672, 20}, 1, FALSE},
716     {{0, 0, 672, 20}, 1, FALSE},
717     {{0, 0, 672, 20}, 0, FALSE},
718 /* style 00000003 */
719     {{0, 226, 672, 226}, 0, FALSE},
720     {{0, 206, 672, 226}, 1, TRUE},
721     {{0, 206, 672, 226}, 1, FALSE},
722     {{0, 206, 672, 226}, 1, FALSE},
723     {{0, 206, 672, 226}, 1, FALSE},
724     {{0, 206, 672, 226}, 0, FALSE},
725 /* style 00000043 */
726     {{0, 226, 672, 226}, 0, FALSE},
727     {{0, 206, 672, 226}, 1, TRUE},
728     {{0, 206, 672, 226}, 1, FALSE},
729     {{0, 206, 672, 226}, 1, FALSE},
730     {{0, 206, 672, 226}, 1, FALSE},
731     {{0, 206, 672, 226}, 0, FALSE},
732 /* style 00000080 */
733     {{2, 0, 2, 226}, 0, FALSE},
734     {{2, 0, 22, 226}, 1, TRUE},
735     {{2, 0, 22, 226}, 1, FALSE},
736     {{2, 0, 22, 226}, 1, FALSE},
737     {{2, 0, 22, 226}, 1, FALSE},
738     {{2, 0, 22, 226}, 0, FALSE},
739 /* style 00000083 */
740     {{672, 0, 672, 226}, 0, FALSE},
741     {{652, 0, 672, 226}, 1, TRUE},
742     {{652, 0, 672, 226}, 1, FALSE},
743     {{652, 0, 672, 226}, 1, FALSE},
744     {{652, 0, 672, 226}, 1, FALSE},
745     {{652, 0, 672, 226}, 0, FALSE},
746 /* style 00000008 */
747     {{10, 11, 510, 11}, 0, FALSE},
748     {{10, 15, 510, 35}, 1, TRUE},
749     {{10, 17, 510, 37}, 1, FALSE},
750     {{10, 14, 110, 54}, 2, TRUE},
751     {{0, 4, 0, 44}, 2, FALSE},
752     {{0, 6, 0, 46}, 2, FALSE},
753     {{0, 8, 0, 48}, 2, FALSE},
754     {{0, 12, 0, 32}, 1, TRUE},
755     {{0, 4, 100, 24}, 0, FALSE},
756 /* style 00000048 */
757     {{10, 5, 510, 5}, 0, FALSE},
758     {{10, 5, 510, 25}, 1, TRUE},
759     {{10, 5, 510, 25}, 1, FALSE},
760     {{10, 10, 110, 50}, 2, TRUE},
761     {{0, 0, 0, 40}, 2, FALSE},
762     {{0, 0, 0, 40}, 2, FALSE},
763     {{0, 0, 0, 40}, 2, FALSE},
764     {{0, 0, 0, 20}, 1, TRUE},
765     {{0, 0, 100, 20}, 0, FALSE},
766 /* style 00000004 */
767     {{10, 5, 510, 20}, 0, FALSE},
768     {{10, 5, 510, 20}, 1, TRUE},
769     {{10, 10, 110, 110}, 2, TRUE},
770     {{0, 0, 0, 0}, 2, FALSE},
771     {{0, 0, 0, 0}, 2, FALSE},
772     {{0, 0, 0, 0}, 2, FALSE},
773     {{0, 0, 0, 0}, 1, TRUE},
774     {{0, 0, 100, 100}, 0, FALSE},
775 /* style 00000002 */
776     {{0, 5, 672, 5}, 0, FALSE},
777     {{0, 5, 672, 25}, 1, TRUE},
778     {{0, 10, 672, 30}, 1, FALSE},
779     {{0, 0, 672, 20}, 1, FALSE},
780     {{0, 0, 672, 20}, 1, FALSE},
781     {{0, 0, 672, 20}, 0, FALSE},
782 /* style 00000082 */
783     {{10, 0, 10, 226}, 0, FALSE},
784     {{10, 0, 30, 226}, 1, TRUE},
785     {{10, 0, 30, 226}, 1, FALSE},
786     {{0, 0, 20, 226}, 1, FALSE},
787     {{0, 0, 20, 226}, 1, FALSE},
788     {{0, 0, 20, 226}, 0, FALSE},
789 /* style 00800001 */
790     {{-2, 0, 674, 4}, 0, FALSE},
791     {{-2, 0, 674, 24}, 1, TRUE},
792     {{-2, 0, 674, 24}, 1, FALSE},
793     {{-2, 0, 674, 24}, 1, FALSE},
794     {{-2, 0, 674, 24}, 1, FALSE},
795     {{-2, 0, 674, 24}, 0, FALSE},
796 /* style 00800048 */
797     {{10, 5, 510, 9}, 0, FALSE},
798     {{10, 5, 510, 29}, 1, TRUE},
799     {{10, 5, 510, 29}, 1, FALSE},
800     {{10, 10, 110, 54}, 2, TRUE},
801     {{0, 0, 0, 44}, 2, FALSE},
802     {{0, 0, 0, 44}, 2, FALSE},
803     {{0, 0, 0, 44}, 2, FALSE},
804     {{0, 0, 0, 24}, 1, TRUE},
805     {{0, 0, 100, 24}, 0, FALSE},
806 /* style 00800004 */
807     {{10, 5, 510, 20}, 0, FALSE},
808     {{10, 5, 510, 20}, 1, TRUE},
809     {{10, 10, 110, 110}, 2, TRUE},
810     {{0, 0, 0, 0}, 2, FALSE},
811     {{0, 0, 0, 0}, 2, FALSE},
812     {{0, 0, 0, 0}, 2, FALSE},
813     {{0, 0, 0, 0}, 1, TRUE},
814     {{0, 0, 100, 100}, 0, FALSE},
815 /* style 00800002 */
816     {{-2, 5, 674, 9}, 0, FALSE},
817     {{-2, 5, 674, 29}, 1, TRUE},
818     {{-2, 10, 674, 34}, 1, FALSE},
819     {{-2, 0, 674, 24}, 1, FALSE},
820     {{-2, 0, 674, 24}, 1, FALSE},
821     {{-2, 0, 674, 24}, 0, FALSE},
822 };
823 
824 static DWORD resize_numtests = 0;
825 
826 #define comment(fmt, arg1)
827 #define check_client() { \
828         RECT r; \
829         int value; \
830         const rbresize_test_result_t *res = &resize_results[resize_numtests++]; \
831         assert(resize_numtests <= ARRAY_SIZE(resize_results)); \
832         GetWindowRect(hRebar, &r); \
833         MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); \
834         if ((dwStyles[i] & (CCS_NOPARENTALIGN|CCS_NODIVIDER)) == CCS_NOPARENTALIGN) {\
835             check_rect_no_top("client", r, res->rc); /* the top coordinate changes after every layout and is very implementation-dependent */ \
836         } else { \
837             check_rect("client", r, res->rc); \
838         } \
839         value = (int)SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0); \
840         ok(res->iNumRows == value, "RB_GETROWCOUNT expected %d got %d\n", res->iNumRows, value); \
841         if (res->heightNotify) { \
842             RECT rcClient; \
843             GetClientRect(hRebar, &rcClient); \
844             check_rect("notify", height_change_notify_rect, rcClient); \
845         } else ok(height_change_notify_rect.top == -1, "Unexpected RBN_HEIGHTCHANGE received\n"); \
846         SetRect(&height_change_notify_rect, -1, -1, -1, -1); \
847     }
848 
849 #endif
850 
851 static void test_resize(void)
852 {
853     DWORD dwStyles[] = {CCS_TOP, CCS_TOP | CCS_NODIVIDER, CCS_BOTTOM, CCS_BOTTOM | CCS_NODIVIDER, CCS_VERT, CCS_RIGHT,
854         CCS_NOPARENTALIGN, CCS_NOPARENTALIGN | CCS_NODIVIDER, CCS_NORESIZE, CCS_NOMOVEY, CCS_NOMOVEY | CCS_VERT,
855         CCS_TOP | WS_BORDER, CCS_NOPARENTALIGN | CCS_NODIVIDER | WS_BORDER, CCS_NORESIZE | WS_BORDER,
856         CCS_NOMOVEY | WS_BORDER};
857 
858     const int styles_count = ARRAY_SIZE(dwStyles);
859     int i;
860 
861     for (i = 0; i < styles_count; i++)
862     {
863         HWND hRebar;
864 
865         comment("style %08x", dwStyles[i]);
866         SetRect(&height_change_notify_rect, -1, -1, -1, -1);
867         hRebar = CreateWindowA(REBARCLASSNAMEA, "A", dwStyles[i] | WS_CHILD | WS_VISIBLE, 10, 5, 500, 15, hMainWnd, NULL, GetModuleHandleA(NULL), 0);
868         check_client();
869         add_band_w(hRebar, NULL, 70, 100, 0);
870         if (dwStyles[i] & CCS_NOPARENTALIGN)  /* the window drifts downward for CCS_NOPARENTALIGN without CCS_NODIVIDER */
871             check_client();
872         add_band_w(hRebar, NULL, 70, 100, 0);
873         check_client();
874         MoveWindow(hRebar, 10, 10, 100, 100, TRUE);
875         check_client();
876         MoveWindow(hRebar, 0, 0, 0, 0, TRUE);
877         check_client();
878         /* try to fool the rebar by sending invalid width/height - won't work */
879         if (dwStyles[i] & (CCS_NORESIZE | CCS_NOPARENTALIGN))
880         {
881             WINDOWPOS pos;
882             pos.hwnd = hRebar;
883             pos.hwndInsertAfter = NULL;
884             pos.cx = 500;
885             pos.cy = 500;
886             pos.x = 10;
887             pos.y = 10;
888             pos.flags = 0;
889             SendMessageA(hRebar, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pos);
890             SendMessageA(hRebar, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pos);
891             check_client();
892             SendMessageA(hRebar, WM_SIZE, SIZE_RESTORED, MAKELONG(500, 500));
893             check_client();
894         }
895         SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
896         check_client();
897         SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
898         MoveWindow(hRebar, 0, 0, 100, 100, TRUE);
899         check_client();
900         DestroyWindow(hRebar);
901     }
902 }
903 
904 static void expect_band_content_(int line, HWND hRebar, UINT uBand, INT fStyle, COLORREF clrFore,
905     COLORREF clrBack, LPCSTR lpText, int iImage, HWND hwndChild,
906     INT cxMinChild, INT cyMinChild, INT cx, HBITMAP hbmBack, INT wID,
907     INT cyChild, INT cyMaxChild, INT cyIntegral, INT cxIdeal, LPARAM lParam,
908     UINT cxHeader, UINT cxHeader_broken)
909 {
910     CHAR buf[MAX_PATH] = "abc";
911     REBARBANDINFOA rb;
912 
913     memset(&rb, 0xdd, sizeof(rb));
914     rb.cbSize = REBARBANDINFOA_V6_SIZE;
915     rb.fMask = RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_COLORS
916         | RBBIM_HEADERSIZE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_IMAGE | RBBIM_LPARAM
917         | RBBIM_SIZE | RBBIM_STYLE | RBBIM_TEXT;
918     rb.lpText = buf;
919     rb.cch = MAX_PATH;
920     ok(SendMessageA(hRebar, RB_GETBANDINFOA, uBand, (LPARAM)&rb), "RB_GETBANDINFOA failed from line %d\n", line);
921     expect_eq(line, rb.fStyle, fStyle, int, "%x");
922     expect_eq(line, rb.clrFore, clrFore, COLORREF, "%x");
923     expect_eq(line, rb.clrBack, clrBack, COLORREF, "%x");
924     expect_eq(line, strcmp(rb.lpText, lpText), 0, int, "%d");
925     expect_eq(line, rb.iImage, iImage, int, "%x");
926     expect_eq(line, rb.hwndChild, hwndChild, HWND, "%p");
927     expect_eq(line, rb.cxMinChild, cxMinChild, int, "%d");
928     expect_eq(line, rb.cyMinChild, cyMinChild, int, "%d");
929     expect_eq(line, rb.cx, cx, int, "%d");
930     expect_eq(line, rb.hbmBack, hbmBack, HBITMAP, "%p");
931     expect_eq(line, rb.wID, wID, int, "%d");
932     /* the values of cyChild, cyMaxChild and cyIntegral can't be read unless the band is RBBS_VARIABLEHEIGHT */
933     expect_eq(line, rb.cyChild, cyChild, int, "%x");
934     expect_eq(line, rb.cyMaxChild, cyMaxChild, int, "%x");
935     expect_eq(line, rb.cyIntegral, cyIntegral, int, "%x");
936     expect_eq(line, rb.cxIdeal, cxIdeal, int, "%d");
937     expect_eq(line, rb.lParam, lParam, LPARAM, "%ld");
938     ok(rb.cxHeader == cxHeader || rb.cxHeader == cxHeader + 1 || broken(rb.cxHeader == cxHeader_broken),
939         "expected %d for %d from line %d\n", cxHeader, rb.cxHeader, line);
940 }
941 
942 #define expect_band_content(hRebar, uBand, fStyle, clrFore, clrBack,\
943  lpText, iImage, hwndChild, cxMinChild, cyMinChild, cx, hbmBack, wID,\
944  cyChild, cyMaxChild, cyIntegral, cxIdeal, lParam, cxHeader, cxHeader_broken) \
945  expect_band_content_(__LINE__, hRebar, uBand, fStyle, clrFore, clrBack,\
946  lpText, iImage, hwndChild, cxMinChild, cyMinChild, cx, hbmBack, wID,\
947  cyChild, cyMaxChild, cyIntegral, cxIdeal, lParam, cxHeader, cxHeader_broken)
948 
949 static void test_bandinfo(void)
950 {
951     REBARBANDINFOA rb;
952     CHAR szABC[] = "ABC";
953     CHAR szABCD[] = "ABCD";
954     HWND hRebar;
955 
956     hRebar = create_rebar_control();
957     rb.cbSize = REBARBANDINFOA_V6_SIZE;
958     rb.fMask = 0;
959     if (!SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb))
960     {
961         win_skip( "V6 info not supported\n" );
962         DestroyWindow(hRebar);
963         return;
964     }
965     expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1);
966 
967     rb.fMask = RBBIM_CHILDSIZE;
968     rb.cxMinChild = 15;
969     rb.cyMinChild = 20;
970     rb.cyChild = 30;
971     rb.cyMaxChild = 20;
972     rb.cyIntegral = 10;
973     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
974     expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1);
975 
976     rb.fMask = RBBIM_TEXT;
977     rb.lpText = szABC;
978     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
979     expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 3 + 2*system_font_height, -1);
980 
981     rb.cbSize = REBARBANDINFOA_V6_SIZE;
982     rb.fMask = 0;
983     ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBANDA failed\n");
984     expect_band_content(hRebar, 1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9, -1);
985     expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 8 + 2*system_font_height, -1);
986 
987     rb.fMask = RBBIM_HEADERSIZE;
988     rb.cxHeader = 50;
989     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
990     expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50, -1);
991 
992     rb.cxHeader = 5;
993     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
994     expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1);
995 
996     rb.fMask = RBBIM_TEXT;
997     rb.lpText = szABCD;
998     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
999     expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1);
1000     rb.fMask = RBBIM_STYLE | RBBIM_TEXT;
1001     rb.fStyle = RBBS_VARIABLEHEIGHT;
1002     rb.lpText = szABC;
1003     ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFOA failed\n");
1004     expect_band_content(hRebar, 0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 8 + 2*system_font_height, 5);
1005 
1006     DestroyWindow(hRebar);
1007 }
1008 
1009 static void test_colors(void)
1010 {
1011     COLORSCHEME scheme;
1012     COLORREF clr;
1013     BOOL ret;
1014     HWND hRebar;
1015     REBARBANDINFOA bi;
1016 
1017     hRebar = create_rebar_control();
1018 
1019     /* test default colors */
1020     clr = SendMessageA(hRebar, RB_GETTEXTCOLOR, 0, 0);
1021     compare(clr, CLR_NONE, "%x");
1022     clr = SendMessageA(hRebar, RB_GETBKCOLOR, 0, 0);
1023     compare(clr, CLR_NONE, "%x");
1024 
1025     scheme.dwSize = sizeof(scheme);
1026     scheme.clrBtnHighlight = 0;
1027     scheme.clrBtnShadow = 0;
1028     ret = SendMessageA(hRebar, RB_GETCOLORSCHEME, 0, (LPARAM)&scheme);
1029     if (ret)
1030     {
1031         compare(scheme.clrBtnHighlight, CLR_DEFAULT, "%x");
1032         compare(scheme.clrBtnShadow, CLR_DEFAULT, "%x");
1033     }
1034     else
1035         skip("RB_GETCOLORSCHEME not supported\n");
1036 
1037     /* check default band colors */
1038     add_band_w(hRebar, "", 0, 10, 10);
1039     bi.cbSize = REBARBANDINFOA_V6_SIZE;
1040     bi.fMask = RBBIM_COLORS;
1041     bi.clrFore = bi.clrBack = 0xc0ffe;
1042     ret = SendMessageA(hRebar, RB_GETBANDINFOA, 0, (LPARAM)&bi);
1043     ok(ret, "RB_GETBANDINFOA failed\n");
1044     compare(bi.clrFore, RGB(0, 0, 0), "%x");
1045     compare(bi.clrBack, GetSysColor(COLOR_3DFACE), "%x");
1046 
1047     SendMessageA(hRebar, RB_SETTEXTCOLOR, 0, RGB(255, 0, 0));
1048     bi.clrFore = bi.clrBack = 0xc0ffe;
1049     ret = SendMessageA(hRebar, RB_GETBANDINFOA, 0, (LPARAM)&bi);
1050     ok(ret, "RB_GETBANDINFOA failed\n");
1051     compare(bi.clrFore, RGB(0, 0, 0), "%x");
1052 
1053     DestroyWindow(hRebar);
1054 }
1055 
1056 
1057 static BOOL register_parent_wnd_class(void)
1058 {
1059     WNDCLASSA wc;
1060 
1061     wc.style = CS_HREDRAW | CS_VREDRAW;
1062     wc.cbClsExtra = 0;
1063     wc.cbWndExtra = 0;
1064     wc.hInstance = GetModuleHandleA(NULL);
1065     wc.hIcon = NULL;
1066     wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_IBEAM);
1067     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1068     wc.lpszMenuName = NULL;
1069     wc.lpszClassName = "MyTestWnd";
1070     wc.lpfnWndProc = parent_wndproc;
1071 
1072     return RegisterClassA(&wc);
1073 }
1074 
1075 static HWND create_parent_window(void)
1076 {
1077     HWND hwnd;
1078 
1079     if (!register_parent_wnd_class()) return NULL;
1080 
1081     hwnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
1082       CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
1083       226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
1084       NULL, NULL, GetModuleHandleA(NULL), 0);
1085 
1086     ShowWindow(hwnd, SW_SHOW);
1087     return hwnd;
1088 }
1089 
1090 static void test_showband(void)
1091 {
1092     HWND hRebar;
1093     REBARBANDINFOA rbi;
1094     BOOL ret;
1095 
1096     hRebar = create_rebar_control();
1097 
1098     /* no bands */
1099     ret = SendMessageA(hRebar, RB_SHOWBAND, 0, TRUE);
1100     ok(ret == FALSE, "got %d\n", ret);
1101 
1102     rbi.cbSize = REBARBANDINFOA_V6_SIZE;
1103     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
1104     rbi.cx = 200;
1105     rbi.cxMinChild = 100;
1106     rbi.cyMinChild = 30;
1107     rbi.hwndChild = NULL;
1108     SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
1109 
1110     /* index out of range */
1111     ret = SendMessageA(hRebar, RB_SHOWBAND, 1, TRUE);
1112     ok(ret == FALSE, "got %d\n", ret);
1113 
1114     ret = SendMessageA(hRebar, RB_SHOWBAND, 0, TRUE);
1115     ok(ret == TRUE, "got %d\n", ret);
1116 
1117     DestroyWindow(hRebar);
1118 }
1119 
1120 static void test_notification(void)
1121 {
1122     MEASUREITEMSTRUCT mis;
1123     HWND rebar;
1124 
1125     rebar = create_rebar_control();
1126 
1127     g_parent_measureitem = 0;
1128     SendMessageA(rebar, WM_MEASUREITEM, 0, (LPARAM)&mis);
1129     ok(g_parent_measureitem == 1, "got %d\n", g_parent_measureitem);
1130 
1131     DestroyWindow(rebar);
1132 }
1133 
1134 static void init_functions(void)
1135 {
1136     HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
1137 
1138 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
1139     X(ImageList_Destroy);
1140     X(ImageList_LoadImageA);
1141 #undef X
1142 }
1143 
1144 START_TEST(rebar)
1145 {
1146     MSG msg;
1147 
1148     init_system_font_height();
1149     init_functions();
1150 
1151     hMainWnd = create_parent_window();
1152 
1153     test_bandinfo();
1154     test_colors();
1155     test_showband();
1156     test_notification();
1157 
1158     if(!is_font_installed("System") || !is_font_installed("Tahoma"))
1159     {
1160         skip("Missing System or Tahoma font\n");
1161         goto out;
1162     }
1163 
1164     test_layout();
1165     test_resize();
1166 
1167 out:
1168     PostQuitMessage(0);
1169     while(GetMessageA(&msg,0,0,0)) {
1170         TranslateMessage(&msg);
1171         DispatchMessageA(&msg);
1172     }
1173     DestroyWindow(hMainWnd);
1174 }
1175