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