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