1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for Button window class v6
5  * PROGRAMMERS:     Giannis Adamopoulos
6  */
7 
8 #include "wine/test.h"
9 #include <stdio.h>
10 #include <windows.h>
11 #include <commctrl.h>
12 #include <uxtheme.h>
13 #include <undocuser.h>
14 #include <msgtrace.h>
15 #include <user32testhelpers.h>
16 
17 #define ok_rect(rc, l,r,t,b) ok((rc.left == (l)) && (rc.right == (r)) && (rc.top == (t)) && (rc.bottom == (b)), "Wrong rect. expected %d, %d, %d, %d got %ld, %ld, %ld, %ld\n", l,t,r,b, rc.left, rc.top, rc.right, rc.bottom)
18 #define ok_size(s, width, height) ok((s.cx == (width) && s.cy == (height)), "Expected size (%lu,%lu) got (%lu,%lu)\n", (LONG)width, (LONG)height, s.cx, s.cy)
19 
20 void Test_TextMargin()
21 {
22     RECT rc;
23     BOOL ret;
24     HWND hwnd1;
25 
26     hwnd1 = CreateWindowW(L"Button", L"Test1", 0, 10, 10, 100, 100, 0, NULL, NULL, NULL);
27     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
28     SetWindowTheme(hwnd1, L"", L"");
29 
30     ret = SendMessageW(hwnd1, BCM_GETTEXTMARGIN, 0, (LPARAM)&rc);
31     ok (ret == TRUE, "Expected BCM_GETTEXTMARGIN to succeed\n");
32     ok_rect(rc, 1, 1, 1, 1);
33 
34     SetRect(&rc, 0,0,0,0);
35     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
36     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
37 
38     ret = SendMessageW(hwnd1, BCM_GETTEXTMARGIN, 0, (LPARAM)&rc);
39     ok (ret == TRUE, "Expected BCM_GETTEXTMARGIN to succeed\n");
40     ok_rect(rc, 0, 0, 0, 0);
41 
42     SetRect(&rc, -1,-1,-1,-1);
43     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
44     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
45 
46     ret = SendMessageW(hwnd1, BCM_GETTEXTMARGIN, 0, (LPARAM)&rc);
47     ok (ret == TRUE, "Expected BCM_GETTEXTMARGIN to succeed\n");
48     ok_rect(rc, -1, -1, -1, -1);
49 
50     SetRect(&rc, 1000,1000,1000,1000);
51     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
52     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
53 
54     ret = SendMessageW(hwnd1, BCM_GETTEXTMARGIN, 0, (LPARAM)&rc);
55     ok (ret == TRUE, "Expected BCM_GETTEXTMARGIN to succeed\n");
56     ok_rect(rc, 1000, 1000, 1000, 1000);
57 
58     DestroyWindow(hwnd1);
59 
60     hwnd1 = CreateWindowW(L"Button", L"Test1", BS_DEFPUSHBUTTON, 10, 10, 100, 100, 0, NULL, NULL, NULL);
61     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
62     SetWindowTheme(hwnd1, L"", L"");
63 
64     ret = SendMessageW(hwnd1, BCM_GETTEXTMARGIN, 0, (LPARAM)&rc);
65     ok (ret == TRUE, "Expected BCM_GETTEXTMARGIN to succeed\n");
66     ok_rect(rc, 1, 1, 1, 1);
67 
68     DestroyWindow(hwnd1);
69 
70 }
71 
72 void Test_Imagelist()
73 {
74     HWND hwnd1;
75     BOOL ret;
76     BUTTON_IMAGELIST imlData;
77 
78     hwnd1 = CreateWindowW(L"Button", L"Test2", 0, 10, 10, 100, 100, 0, NULL, NULL, NULL);
79     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
80 
81     ret = SendMessageW(hwnd1, BCM_GETIMAGELIST, 0, (LPARAM)&imlData);
82     ok (ret == TRUE, "Expected BCM_GETIMAGELIST to succeed\n");
83     ok (imlData.himl == 0, "Expected 0 himl\n");
84     ok (imlData.uAlign == 0, "Expected 0 uAlign\n");
85     ok_rect(imlData.margin, 0, 0, 0, 0);
86 
87     SetRect(&imlData.margin, 0,0,0,1);
88     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
89     ok (ret == FALSE, "Expected BCM_SETIMAGELIST to fail\n"); /* This works in win10 */
90 
91     imlData.himl = (HIMAGELIST)0xdead;
92     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
93     ok (ret == TRUE, "Expected BCM_SETIMAGELIST to fail\n");
94 
95     ret = SendMessageW(hwnd1, BCM_GETIMAGELIST, 0, (LPARAM)&imlData);
96     ok (ret == TRUE, "Expected BCM_GETIMAGELIST to succeed\n");
97     ok (imlData.himl == (HIMAGELIST)0xdead, "Expected 0 himl\n");
98     ok (imlData.uAlign == 0, "Expected 0 uAlign\n");
99     ok_rect(imlData.margin, 0, 0, 0, 1);
100 
101     imlData.himl = 0;
102     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
103     ok (ret == FALSE, "Expected BCM_SETIMAGELIST to fail\n"); /* This works in win10 */
104 
105     DestroyWindow(hwnd1);
106 }
107 
108 void Test_GetIdealSizeNoThemes()
109 {
110     HWND hwnd1, hwnd2;
111     BOOL ret;
112     SIZE s, textent;
113     HFONT font;
114     HDC hdc;
115     HANDLE hbmp;
116     HIMAGELIST himl;
117     BUTTON_IMAGELIST imlData;
118     RECT rc;
119     LOGFONTW lf;
120     DWORD i;
121 
122     hwnd2 = CreateWindowW(L"Static", L"", 0, 0, 0, 100, 100, 0, NULL, NULL, NULL);
123     ok (hwnd2 != NULL, "Expected CreateWindowW to succeed\n");
124 
125     hwnd1 = CreateWindowW(L"Button", L" ", WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
126     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
127     SetWindowTheme(hwnd1, L"", L"");
128 
129     font = (HFONT)SendMessageW(hwnd1, WM_GETFONT, 0, 0);
130     hdc = GetDC(hwnd1);
131     SelectObject(hdc, font);
132     GetTextExtentPoint32W(hdc, L" ", 1, &textent);
133 
134     memset(&s, 0, sizeof(s));
135     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
136     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
137     ok_size(s, textent.cx + 5 + 2,
138                textent.cy + 7 + 2); /* the last +2 is the text margin */
139 
140     DestroyWindow(hwnd1);
141 
142 
143     hwnd1 = CreateWindowW(L"Button", L" ", BS_USERBUTTON | WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
144     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
145     SetWindowTheme(hwnd1, L"", L"");
146 
147     memset(&s, 0, sizeof(s));
148     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
149     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
150     ok_size(s, textent.cx + 5 + 2,
151                textent.cy + 7 + 2); /* the last +2 is the text margin */
152 
153     DestroyWindow(hwnd1);
154 
155 
156 
157     hwnd1 = CreateWindowW(L"Button", L"", WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
158     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
159     SetWindowTheme(hwnd1, L"", L"");
160 
161     s.cx = 1;
162     s.cy = 1;
163     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
164     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
165     ok_size(s, 100, 100);
166 
167     hbmp = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(5), IMAGE_BITMAP, 0, 0, 0);
168     ok (hbmp != 0, "Expected LoadImage to succeed\n");
169 
170     SendMessageW(hwnd1, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
171 
172     memset(&s, 0, sizeof(s));
173     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
174     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
175     ok_size(s, 100, 100);
176 
177     himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(5), 1, 1, 0, IMAGE_BITMAP, 0);
178     ok (himl != 0, "Expected ImageList_LoadImage to succeed\n");
179 
180     memset(&imlData, 0, sizeof(imlData));
181     imlData.himl = himl;
182     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
183     ok (ret == TRUE, "Expected BCM_SETIMAGELIST to fail\n"); /* This works in win10 */
184 
185     memset(&s, 0, sizeof(s));
186     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
187     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
188     ok_size(s, 100, 100);
189 
190     DestroyWindow(hwnd1);
191 
192 
193 
194 
195 
196     hwnd1 = CreateWindowW(L"Button", L"",  WS_CHILD, 10, 10, 5, 5, hwnd2, NULL, NULL, NULL);
197     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
198     SetWindowTheme(hwnd1, L"", L"");
199 
200     memset(&s, 0, sizeof(s));
201     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
202     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
203     ok_size(s, 5, 5);
204 
205     DestroyWindow(hwnd1);
206 
207 
208 
209 
210     hwnd1 = CreateWindowW(L"Button", L" ", BS_BITMAP | WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
211     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
212     SetWindowTheme(hwnd1, L"", L"");
213 
214     SendMessageW(hwnd1, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp);
215 
216     memset(&s, 0, sizeof(s));
217     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
218     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
219 
220     /* In xp and 2k3 the image is ignored, in vista+ its width is added to the text width */
221     ok_size(s, textent.cx + 5 + 2,
222                textent.cy + 7 + 2); /* the last +2 is the text margin */
223 
224     DestroyWindow(hwnd1);
225 
226 
227 
228     hwnd1 = CreateWindowW(L"Button", L" ", WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
229     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
230     SetWindowTheme(hwnd1, L"", L"");
231 
232     SetRect(&rc, 0,0,0,0);
233     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
234     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
235 
236     memset(&s, 0, sizeof(s));
237     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
238     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
239     ok_size(s, textent.cx + 5,
240                textent.cy + 7);
241 
242     SetRect(&rc, 50,50,50,50);
243     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
244     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
245 
246     memset(&s, 0, sizeof(s));
247     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
248     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
249     ok_size(s, textent.cx + 5 + 100,
250                textent.cy + 7 + 100);
251 
252     SetRect(&rc, 1,1,1,1);
253     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
254     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
255 
256     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
257     ok (ret == TRUE, "Expected BCM_SETIMAGELIST to fail\n");
258 
259     memset(&s, 0, sizeof(s));
260     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
261     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
262     ok_size(s, textent.cx + 5 + 2 + 1, /* we get an extra pixel due to the iml */
263                textent.cy + 7 + 2);
264 
265     s.cx = 1;
266     s.cy = 1;
267     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
268     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
269     ok_size(s, textent.cx + 5 + 2 + 1,
270                textent.cy + 7 + 2);
271 
272     s.cx = 100;
273     s.cy = 100;
274     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
275     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
276     ok_size(s, textent.cx + 5 + 2 + 1,
277                textent.cy + 7 + 2);
278 
279     SetRect(&imlData.margin, 1,1,1,1);
280     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
281     ok (ret == TRUE, "Expected BCM_SETIMAGELIST to fail\n");
282 
283     memset(&s, 0, sizeof(s));
284     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
285     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
286     /* expected width = text width + hardcoded value + text margins + image width + image margins */
287     ok_size(s, textent.cx + 5 + 2 + 1 + 2,
288                textent.cy + 7 + 2);
289 
290     SetRect(&imlData.margin, 50,50,50,50);
291     ret = SendMessageW(hwnd1, BCM_SETIMAGELIST, 0, (LPARAM)&imlData);
292     ok (ret == TRUE, "Expected BCM_SETIMAGELIST to fail\n");
293 
294     memset(&s, 0, sizeof(s));
295     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
296     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
297     /* image + its margins is so big that the height is dictated by them */
298     ok_size(s, textent.cx + 5 + 2 + 1 + 100, (LONG)101);
299 
300     DestroyWindow(hwnd1);
301 
302 
303 
304 
305 
306 
307     hwnd1 = CreateWindowW(L"Button", L"Start", BS_VCENTER | WS_CHILD, 0, 0, 0, 0, hwnd2, NULL, NULL, NULL);
308     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
309     SetWindowTheme(hwnd1, L"", L"");
310 
311     font = (HFONT)SendMessageW(hwnd1, WM_GETFONT, 0, 0);
312     hdc = GetDC(hwnd1);
313     SelectObject(hdc, font);
314     GetTextExtentPoint32W(hdc, L"Start", 5, &textent);
315 
316     SetRect(&rc, 0,0,0,0);
317     ret = SendMessageW(hwnd1, BCM_SETTEXTMARGIN, 0, (LPARAM)&rc);
318     ok (ret == TRUE, "Expected BCM_SETTEXTMARGIN to succeed\n");
319 
320     memset(&s, 0, sizeof(s));
321     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
322     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
323     ok_size(s, textent.cx + 5, textent.cy + 7);
324 
325     DestroyWindow(hwnd1);
326 
327 
328 
329 
330     /* Test again with some real text to see if the formula is correct */
331     hwnd1 = CreateWindowW(L"Button", L"Some test text", WS_CHILD, 10, 10, 100, 100, hwnd2, NULL, NULL, NULL);
332     ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
333     SetWindowTheme(hwnd1, L"", L"");
334 
335     font = (HFONT)SendMessageW(hwnd1, WM_GETFONT, 0, 0);
336     hdc = GetDC(hwnd1);
337     SelectObject(hdc, font);
338     GetTextExtentPoint32W(hdc, L"Some test text", 14, &textent);
339 
340     memset(&s, 0, sizeof(s));
341     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
342     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
343     ok_size(s, textent.cx + 5 + 2,  /* the last +2 is the text margin */
344                textent.cy + 7 + 2);
345 
346     /* The hardcoded values are independent of the margin */
347     lf.lfHeight = 200;
348     lf.lfWidth = 200;
349     lf.lfWeight = FW_BOLD;
350     wcscpy(lf.lfFaceName, L"Arial");
351     font = CreateFontIndirectW(&lf);
352     ok(font != NULL, "\n");
353     SendMessageW(hwnd1, WM_SETFONT, (WPARAM)font, FALSE);
354 
355     SelectObject(hdc, font);
356     GetTextExtentPoint32W(hdc, L"Some test text", 14, &textent);
357 
358     memset(&s, 0, sizeof(s));
359     ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
360     ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
361     ok_size(s, textent.cx + 5 + 2,  /* the last +2 is the text margin */
362                textent.cy + 7 + 2);
363 
364     DestroyWindow(hwnd1);
365 
366     for (i = BS_PUSHBUTTON; i <= BS_OWNERDRAW; i++)
367     {
368         if (i == BS_USERBUTTON)
369             continue;
370 
371         if (i >= BS_CHECKBOX)
372         {
373             hwnd1 = CreateWindowW(L"Button", L" ", i|WS_CHILD, 0, 0, 72, 72, hwnd2, NULL, NULL, NULL);
374             ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
375             memset(&s, 0, sizeof(s));
376             ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
377             ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
378             ok_size(s, 72, 72);
379 
380             SetWindowTheme(hwnd1, L"", L"");
381             memset(&s, 0, sizeof(s));
382             ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
383             ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
384             ok_size(s, 72, 72);
385             DestroyWindow(hwnd1);
386 
387             hwnd1 = CreateWindowW(L"Button", L" ", i|WS_CHILD, 0, 0, 12, 12, hwnd2, NULL, NULL, NULL);
388             ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
389             memset(&s, 0, sizeof(s));
390             ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
391             ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
392             ok_size(s, 12, 12);
393             DestroyWindow(hwnd1);
394         }
395 
396         hwnd1 = CreateWindowW(L"Button", L"", i|WS_CHILD, 0, 0, 72, 72, hwnd2, NULL, NULL, NULL);
397         ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
398         memset(&s, 0, sizeof(s));
399         ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
400         ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
401         ok_size(s, 72, 72);
402         DestroyWindow(hwnd1);
403 
404         hwnd1 = CreateWindowW(L"Button", L"", i|WS_CHILD, 0, 0, 150, 72, hwnd2, NULL, NULL, NULL);
405         ok (hwnd1 != NULL, "Expected CreateWindowW to succeed\n");
406         memset(&s, 0, sizeof(s));
407         ret = SendMessageW(hwnd1, BCM_GETIDEALSIZE, 0, (LPARAM)&s);
408         ok (ret == TRUE, "Expected BCM_GETIDEALSIZE to succeed\n");
409         ok_size(s, 150, 72);
410         DestroyWindow(hwnd1);
411     }
412     DestroyWindow(hwnd2);
413 }
414 
415 
416 HWND hWnd1, hWnd2;
417 
418 #define MOVE_CURSOR(x,y) mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE ,                           \
419                                      x*(65535/GetSystemMetrics(SM_CXVIRTUALSCREEN)),                     \
420                                      y*(65535/GetSystemMetrics(SM_CYVIRTUALSCREEN)) , 0,0);
421 
422 static int get_iwnd(HWND hWnd)
423 {
424     if(hWnd == hWnd1) return 1;
425     else if(hWnd == hWnd2) return 2;
426     else return 0;
427 }
428 
429 static LRESULT CALLBACK subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR ref_data)
430 {
431     int iwnd = get_iwnd(hwnd);
432 
433     if(message > WM_USER || !iwnd )
434         return DefSubclassProc(hwnd, message, wParam, lParam);
435 
436     switch(message)
437     {
438     case WM_IME_SETCONTEXT:
439     case WM_IME_NOTIFY :
440     case WM_GETICON :
441     case WM_GETTEXT:
442     case WM_GETTEXTLENGTH:
443         break;
444     case WM_NOTIFY:
445     {
446         NMHDR* pnmhdr = (NMHDR*)lParam;
447         if (pnmhdr->code == NM_CUSTOMDRAW)
448         {
449             NMCUSTOMDRAW* pnmcd = (NMCUSTOMDRAW*)lParam;
450             RECORD_MESSAGE(iwnd, message, SENT, pnmhdr->code, pnmcd->dwDrawStage);
451         }
452         else
453         {
454             RECORD_MESSAGE(iwnd, message, SENT, pnmhdr->idFrom,pnmhdr->code);
455         }
456         break;
457     }
458     default:
459         RECORD_MESSAGE(iwnd, message, SENT, 0,0);
460     }
461     return DefSubclassProc(hwnd, message, wParam, lParam);
462 }
463 
464 static LRESULT CALLBACK TestProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
465 {
466     int iwnd = get_iwnd(hwnd);
467 
468     if (iwnd != 0  && message == WM_NOTIFY)
469     {
470         NMHDR* pnmhdr = (NMHDR*)lParam;
471         if (pnmhdr->code == NM_CUSTOMDRAW)
472         {
473             NMCUSTOMDRAW* pnmcd = (NMCUSTOMDRAW*)lParam;
474             RECORD_MESSAGE(iwnd, message, SENT, pnmhdr->code, pnmcd->dwDrawStage);
475         }
476         else
477         {
478             RECORD_MESSAGE(iwnd, message, SENT, pnmhdr->idFrom,pnmhdr->code);
479         }
480     }
481     else if (iwnd != 0 && message < WM_USER && message != WM_GETICON)
482     {
483         RECORD_MESSAGE(iwnd, message, SENT, 0,0);
484     }
485 
486     return DefWindowProc(hwnd, message, wParam, lParam);
487 }
488 
489 static void FlushMessages()
490 {
491     MSG msg;
492 
493     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
494     {
495         int iwnd = get_iwnd(msg.hwnd);
496         if(iwnd)
497         {
498             if(msg.message <= WM_USER && iwnd != 0)
499                 RECORD_MESSAGE(iwnd, msg.message, POST,0,0);
500         }
501         DispatchMessageW( &msg );
502     }
503 }
504 
505 MSG_ENTRY paint_sequence[]={
506     {2, WM_PAINT, POST},
507     {1, WM_ERASEBKGND},
508     {1, WM_PRINTCLIENT},
509     {1, WM_CTLCOLORBTN},
510     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
511     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
512     {0,0}};
513 
514 MSG_ENTRY paint_nonthemed_sequence[]={
515     {2, WM_PAINT, POST},
516     {1, WM_CTLCOLORBTN},
517     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
518     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
519     {0,0}};
520 
521 MSG_ENTRY redraw_sequence[]={
522     {2, WM_PAINT, POST},
523     {2, WM_ERASEBKGND},
524     {1, WM_ERASEBKGND},
525     {1, WM_PRINTCLIENT},
526     {1, WM_CTLCOLORBTN},
527     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
528     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
529     {0,0}};
530 
531 MSG_ENTRY redraw_nonthemed_sequence[]={
532     {2, WM_PAINT, POST},
533     {2, WM_ERASEBKGND},
534     {1, WM_CTLCOLORBTN},
535     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
536     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
537     {0,0}};
538 
539 MSG_ENTRY printclnt_nonthemed_sequence[]={
540     {2, WM_PRINTCLIENT},
541     {1, WM_CTLCOLORBTN},
542     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
543     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
544     {0,0}};
545 
546 MSG_ENTRY printclnt_sequence[]={
547     {2, WM_PRINTCLIENT},
548     {1, WM_CTLCOLORBTN},
549     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
550     {0,0}};
551 
552 MSG_ENTRY pseudomove_sequence[]={
553     {2, WM_MOUSEMOVE},
554     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
555     {2, WM_MOUSELEAVE, POST},
556     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
557     {2, WM_PAINT, POST},
558     {2, WM_ERASEBKGND},
559     {1, WM_ERASEBKGND},
560     {1, WM_PRINTCLIENT},
561     {1, WM_CTLCOLORBTN},
562     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
563     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
564     {0,0}};
565 
566 MSG_ENTRY pseudomove_nonthemed_sequence[]={
567     {2, WM_MOUSEMOVE},
568     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
569     {2, WM_MOUSELEAVE, POST},
570     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
571     {2, WM_PAINT, POST},
572     {2, WM_ERASEBKGND},
573     {1, WM_CTLCOLORBTN},
574     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
575     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
576     {0,0}};
577 
578 MSG_ENTRY pseudohover_sequence[]={
579     {2, WM_MOUSEHOVER},
580     {0,0}};
581 
582 MSG_ENTRY pseudoleave_sequence[]={
583     {2, WM_MOUSELEAVE},
584     {0,0}};
585 
586 MSG_ENTRY mouseenter_sequence[]={
587     {2, WM_NCHITTEST},
588     {2, WM_SETCURSOR},
589     {1, WM_SETCURSOR},
590     {2, WM_MOUSEMOVE, POST},
591     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
592     {2, WM_PAINT, POST},
593     {2, WM_ERASEBKGND},
594     {1, WM_ERASEBKGND},
595     {1, WM_PRINTCLIENT},
596     {1, WM_CTLCOLORBTN},
597     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
598     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
599     {0,0}};
600 
601 MSG_ENTRY mouseenter_nonthemed_sequence[]={
602     {2, WM_NCHITTEST},
603     {2, WM_SETCURSOR},
604     {1, WM_SETCURSOR},
605     {2, WM_MOUSEMOVE, POST},
606     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
607     {2, WM_PAINT, POST},
608     {2, WM_ERASEBKGND},
609     {1, WM_CTLCOLORBTN},
610     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
611     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
612     {0,0}};
613 
614 MSG_ENTRY mousemove_sequence[]={
615     {2, WM_NCHITTEST},
616     {2, WM_SETCURSOR},
617     {1, WM_SETCURSOR},
618     {2, WM_MOUSEMOVE, POST},
619     {0,0}};
620 
621 MSG_ENTRY mouseleave_sequence[]={
622     {2, WM_MOUSELEAVE, POST},
623     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
624     {2, WM_PAINT, POST},
625     {2, WM_ERASEBKGND},
626     {1, WM_ERASEBKGND},
627     {1, WM_PRINTCLIENT},
628     {1, WM_CTLCOLORBTN},
629     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
630     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
631     {0,0}};
632 
633 MSG_ENTRY mouseleave_nonthemed_sequence[]={
634     {2, WM_MOUSELEAVE, POST},
635     {1, WM_NOTIFY, SENT, 0, BCN_HOTITEMCHANGE},
636     {2, WM_PAINT, POST},
637     {2, WM_ERASEBKGND},
638     {1, WM_CTLCOLORBTN},
639     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
640     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
641     {0,0}};
642 
643 MSG_ENTRY themechanged_sequence[]={
644     {2, WM_THEMECHANGED, SENT},
645     {1, WM_NOTIFY, SENT, 0, NM_THEMECHANGED },
646     {2, WM_PAINT, POST},
647     {2, WM_ERASEBKGND},
648     {1, WM_CTLCOLORBTN},
649     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
650     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
651     {0,0}};
652 
653 MSG_ENTRY enable_nonthemed_sequence[]={
654     {2, WM_ENABLE, SENT},
655     {1, WM_CTLCOLORBTN},
656     {1, WM_CTLCOLORBTN},
657     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
658     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
659     {0,0}};
660 
661 MSG_ENTRY btndown_nonthemed_sequence[]={
662     {2, WM_LBUTTONDOWN, SENT},
663     {1, WM_KILLFOCUS, SENT},
664     {2, WM_SETFOCUS, SENT},
665     {2, BM_SETSTATE, SENT},
666     {2, WM_PAINT, POST},
667     {1, WM_CTLCOLORBTN},
668     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
669     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
670     {0,0}};
671 
672 MSG_ENTRY btndown_repeat_nonthemed_sequence[]={
673     {2, WM_LBUTTONDOWN, SENT},
674     {2, BM_SETSTATE, SENT},
675     {0,0}};
676 
677 MSG_ENTRY btnclick_nonthemed_sequence[]={
678     {2, BM_CLICK, SENT},
679     {2, WM_LBUTTONDOWN, SENT},
680     {2, BM_SETSTATE, SENT},
681     {2, WM_LBUTTONUP, SENT},
682     {2, BM_SETSTATE , SENT},
683     {2, WM_CAPTURECHANGED, SENT},
684     {1, WM_COMMAND, SENT},
685     {2, WM_PAINT, POST},
686     {1, WM_CTLCOLORBTN},
687     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
688     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
689     {0,0}};
690 
691 MSG_ENTRY btnup_stray_sequence[]={
692     {2, WM_LBUTTONUP, SENT},
693     {0,0}};
694 
695 void Test_MessagesNonThemed()
696 {
697     DWORD state;
698 
699     MOVE_CURSOR(0,0);
700     EMPTY_CACHE();
701 
702     RegisterSimpleClass(TestProc, L"testClass");
703     hWnd1 = CreateWindowW(L"testClass", L"Test parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0, NULL, NULL, NULL);
704     ok (hWnd1 != NULL, "Expected CreateWindowW to succeed\n");
705     SetWindowTheme(hWnd1, L"", L"");
706     UpdateWindow(hWnd1);
707 
708     hWnd2 = CreateWindowW(L"Button", L"test button", /*BS_RADIOBUTTON | */WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hWnd1, NULL, NULL, NULL);
709     ok (hWnd2 != NULL, "Expected CreateWindowW to succeed\n");
710     SetWindowTheme(hWnd2, L"", L"");
711     SetWindowSubclass(hWnd2, subclass_proc, 0, 0);
712     UpdateWindow(hWnd2);
713 
714     FlushMessages();
715     EMPTY_CACHE();
716 
717     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE);
718     FlushMessages();
719     COMPARE_CACHE(empty_chain);
720     FlushMessages();
721     COMPARE_CACHE(empty_chain);
722 
723     RedrawWindow(hWnd2, NULL, NULL, RDW_FRAME);
724     FlushMessages();
725     COMPARE_CACHE(empty_chain);
726 
727     RedrawWindow(hWnd2, NULL, NULL, RDW_INTERNALPAINT);
728     FlushMessages();
729     COMPARE_CACHE(paint_nonthemed_sequence);
730 
731     RedrawWindow(hWnd2, NULL, NULL, RDW_INVALIDATE);
732     FlushMessages();
733     COMPARE_CACHE(paint_nonthemed_sequence);
734 
735     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
736     FlushMessages();
737     COMPARE_CACHE(redraw_nonthemed_sequence);
738 
739     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_ERASEBKGND);
740     FlushMessages();
741     COMPARE_CACHE(printclnt_nonthemed_sequence);
742 
743     SendMessageW(hWnd2, WM_MOUSEMOVE, 0, 0);
744     FlushMessages();
745     COMPARE_CACHE(pseudomove_nonthemed_sequence);
746 
747     SendMessageW(hWnd2, WM_MOUSEHOVER, 0, 0);
748     FlushMessages();
749     COMPARE_CACHE(pseudohover_sequence);
750 
751     SendMessageW(hWnd2, WM_MOUSELEAVE, 0, 0);
752     FlushMessages();
753     COMPARE_CACHE(pseudoleave_sequence);
754 
755     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
756     ok(state == 0, "Expected state 0, got %lu\n", state);
757     EMPTY_CACHE();
758 
759     MOVE_CURSOR(150,150);
760     FlushMessages();
761     COMPARE_CACHE(mouseenter_nonthemed_sequence);
762 
763     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
764     ok(state == BST_HOT, "Expected state BST_HOT, got %lu\n", state);
765     EMPTY_CACHE();
766 
767     MOVE_CURSOR(151,151);
768     FlushMessages();
769     COMPARE_CACHE(mousemove_sequence);
770 
771     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
772     ok(state == BST_HOT, "Expected state BST_HOT, got %lu\n", state);
773     EMPTY_CACHE();
774 
775     MOVE_CURSOR(0,0);
776     FlushMessages();
777     COMPARE_CACHE(empty_chain);
778     FlushMessages();
779     COMPARE_CACHE(mouseleave_nonthemed_sequence);
780 
781     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
782     ok(state == 0, "Expected state 0, got %lu\n", state);
783     EMPTY_CACHE();
784 
785     SendMessageW(hWnd2, WM_THEMECHANGED, 1, 0);
786     FlushMessages();
787     COMPARE_CACHE(themechanged_sequence);
788 
789     SendMessageW(hWnd2, WM_ENABLE, TRUE, 0);
790     FlushMessages();
791     COMPARE_CACHE(enable_nonthemed_sequence);
792 
793     SendMessageW(hWnd2, WM_LBUTTONDOWN, 0, 0);
794     FlushMessages();
795     COMPARE_CACHE(btndown_nonthemed_sequence);
796 
797     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
798     ok(state == 0, "Expected state 0, got %lu\n", state);
799     EMPTY_CACHE();
800 
801     SendMessageW(hWnd2, WM_LBUTTONDOWN, 0, 0);
802     FlushMessages();
803     COMPARE_CACHE(btndown_repeat_nonthemed_sequence);
804 
805     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
806     ok(state == 0, "Expected state 0, got %lu\n", state);
807     EMPTY_CACHE();
808 
809     SendMessageW(hWnd2, BM_CLICK, 0, 0);
810     FlushMessages();
811     COMPARE_CACHE(btnclick_nonthemed_sequence);
812 
813     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
814     ok(state == 0, "Expected state 0, got %lu\n", state);
815     EMPTY_CACHE();
816 
817     SendMessageW(hWnd2, WM_LBUTTONUP, 0, 0);
818     FlushMessages();
819     COMPARE_CACHE(btnup_stray_sequence);
820 
821     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
822     ok(state == 0, "Expected state 0, got %lu\n", state);
823     EMPTY_CACHE();
824 
825     DestroyWindow(hWnd1);
826     DestroyWindow(hWnd2);
827 }
828 
829 void Test_MessagesThemed()
830 {
831     DWORD state;
832 
833     MOVE_CURSOR(0,0);
834     EMPTY_CACHE();
835 
836     RegisterSimpleClass(TestProc, L"testClass");
837     hWnd1 = CreateWindowW(L"testClass", L"Test parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0, NULL, NULL, NULL);
838     ok (hWnd1 != NULL, "Expected CreateWindowW to succeed\n");
839     UpdateWindow(hWnd1);
840 
841     hWnd2 = CreateWindowW(L"Button", L"test button", /*BS_RADIOBUTTON | */WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hWnd1, NULL, NULL, NULL);
842     ok (hWnd2 != NULL, "Expected CreateWindowW to succeed\n");
843     SetWindowSubclass(hWnd2, subclass_proc, 0, 0);
844     UpdateWindow(hWnd2);
845 
846     FlushMessages();
847     EMPTY_CACHE();
848 
849     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE);
850     FlushMessages();
851     COMPARE_CACHE(empty_chain);
852     FlushMessages();
853     COMPARE_CACHE(empty_chain);
854 
855     RedrawWindow(hWnd2, NULL, NULL, RDW_FRAME);
856     FlushMessages();
857     COMPARE_CACHE(empty_chain);
858 
859     RedrawWindow(hWnd2, NULL, NULL, RDW_INTERNALPAINT);
860     FlushMessages();
861     COMPARE_CACHE(paint_sequence);
862 
863     RedrawWindow(hWnd2, NULL, NULL, RDW_INVALIDATE);
864     FlushMessages();
865     COMPARE_CACHE(paint_sequence);
866 
867     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
868     FlushMessages();
869     COMPARE_CACHE(redraw_sequence);
870 
871     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_ERASEBKGND);
872     FlushMessages();
873     COMPARE_CACHE(printclnt_sequence);
874 
875     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_CLIENT);
876     FlushMessages();
877     COMPARE_CACHE(printclnt_sequence);
878 
879     SendMessageW(hWnd2, WM_MOUSEMOVE, 0, 0);
880     FlushMessages();
881     COMPARE_CACHE(pseudomove_sequence);
882 
883     SendMessageW(hWnd2, WM_MOUSEHOVER, 0, 0);
884     FlushMessages();
885     COMPARE_CACHE(pseudohover_sequence);
886 
887     SendMessageW(hWnd2, WM_MOUSELEAVE, 0, 0);
888     FlushMessages();
889     COMPARE_CACHE(pseudoleave_sequence);
890 
891     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
892     ok(state == 0, "Expected state 0, got %lu", state);
893     EMPTY_CACHE();
894 
895     MOVE_CURSOR(150,150);
896     FlushMessages();
897     COMPARE_CACHE(mouseenter_sequence);
898 
899     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
900     ok(state == BST_HOT, "Expected state BST_HOT, got %lu", state);
901     EMPTY_CACHE();
902 
903     MOVE_CURSOR(151,151);
904     FlushMessages();
905     COMPARE_CACHE(mousemove_sequence);
906 
907     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
908     ok(state == BST_HOT, "Expected state BST_HOT, got %lu", state);
909     EMPTY_CACHE();
910 
911     MOVE_CURSOR(0,0);
912     FlushMessages();
913     COMPARE_CACHE(empty_chain);
914     FlushMessages();
915     COMPARE_CACHE(mouseleave_sequence);
916 
917     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
918     ok(state == 0, "Expected state 0, got %lu", state);
919     EMPTY_CACHE();
920 
921     DestroyWindow(hWnd1);
922     DestroyWindow(hWnd2);
923 }
924 
925 START_TEST(button)
926 {
927     LoadLibraryW(L"comctl32.dll"); /* same as statically linking to comctl32 and doing InitCommonControls */
928     Test_TextMargin();
929     Test_Imagelist();
930     Test_GetIdealSizeNoThemes();
931 
932     Test_MessagesNonThemed();
933     if (IsThemeActive())
934         Test_MessagesThemed();
935     else
936         skip("No active theme, skipping Test_MessagesThemed\n");
937 
938 }
939 
940