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     {1, WM_IME_SETCONTEXT, SENT},
665     {2, WM_SETFOCUS, SENT},
666     {2, BM_SETSTATE, SENT},
667     {2, WM_PAINT, POST},
668     {1, WM_CTLCOLORBTN},
669     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
670     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
671     {0,0}};
672 
673 MSG_ENTRY btndown_repeat_nonthemed_sequence[]={
674     {2, WM_LBUTTONDOWN, SENT},
675     {2, BM_SETSTATE, SENT},
676     {0,0}};
677 
678 MSG_ENTRY btnclick_nonthemed_sequence[]={
679     {2, BM_CLICK, SENT},
680     {2, WM_LBUTTONDOWN, SENT},
681     {2, BM_SETSTATE, SENT},
682     {2, WM_LBUTTONUP, SENT},
683     {2, BM_SETSTATE , SENT},
684     {2, WM_CAPTURECHANGED, SENT},
685     {1, WM_COMMAND, SENT},
686     {2, WM_PAINT, POST},
687     {1, WM_CTLCOLORBTN},
688     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREERASE},
689     {1, WM_NOTIFY, SENT, NM_CUSTOMDRAW, CDDS_PREPAINT},
690     {0,0}};
691 
692 MSG_ENTRY btnup_stray_sequence[]={
693     {2, WM_LBUTTONUP, SENT},
694     {0,0}};
695 
696 void Test_MessagesNonThemed()
697 {
698     DWORD state;
699 
700     MOVE_CURSOR(0,0);
701     EMPTY_CACHE();
702 
703     RegisterSimpleClass(TestProc, L"testClass");
704     hWnd1 = CreateWindowW(L"testClass", L"Test parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0, NULL, NULL, NULL);
705     ok (hWnd1 != NULL, "Expected CreateWindowW to succeed\n");
706     SetWindowTheme(hWnd1, L"", L"");
707     UpdateWindow(hWnd1);
708 
709     hWnd2 = CreateWindowW(L"Button", L"test button", /*BS_RADIOBUTTON | */WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hWnd1, NULL, NULL, NULL);
710     ok (hWnd2 != NULL, "Expected CreateWindowW to succeed\n");
711     SetWindowTheme(hWnd2, L"", L"");
712     SetWindowSubclass(hWnd2, subclass_proc, 0, 0);
713     UpdateWindow(hWnd2);
714 
715     FlushMessages();
716     EMPTY_CACHE();
717 
718     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE);
719     FlushMessages();
720     COMPARE_CACHE(empty_chain);
721     FlushMessages();
722     COMPARE_CACHE(empty_chain);
723 
724     RedrawWindow(hWnd2, NULL, NULL, RDW_FRAME);
725     FlushMessages();
726     COMPARE_CACHE(empty_chain);
727 
728     RedrawWindow(hWnd2, NULL, NULL, RDW_INTERNALPAINT);
729     FlushMessages();
730     COMPARE_CACHE(paint_nonthemed_sequence);
731 
732     RedrawWindow(hWnd2, NULL, NULL, RDW_INVALIDATE);
733     FlushMessages();
734     COMPARE_CACHE(paint_nonthemed_sequence);
735 
736     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
737     FlushMessages();
738     COMPARE_CACHE(redraw_nonthemed_sequence);
739 
740     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_ERASEBKGND);
741     FlushMessages();
742     COMPARE_CACHE(printclnt_nonthemed_sequence);
743 
744     SendMessageW(hWnd2, WM_MOUSEMOVE, 0, 0);
745     FlushMessages();
746     COMPARE_CACHE(pseudomove_nonthemed_sequence);
747 
748     SendMessageW(hWnd2, WM_MOUSEHOVER, 0, 0);
749     FlushMessages();
750     COMPARE_CACHE(pseudohover_sequence);
751 
752     SendMessageW(hWnd2, WM_MOUSELEAVE, 0, 0);
753     FlushMessages();
754     COMPARE_CACHE(pseudoleave_sequence);
755 
756     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
757     ok_hex(state, 0);
758     EMPTY_CACHE();
759 
760     MOVE_CURSOR(150,150);
761     FlushMessages();
762     COMPARE_CACHE(mouseenter_nonthemed_sequence);
763 
764     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
765     ok_hex(state, BST_HOT);
766     EMPTY_CACHE();
767 
768     MOVE_CURSOR(151,151);
769     FlushMessages();
770     COMPARE_CACHE(mousemove_sequence);
771 
772     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
773     ok_hex(state, BST_HOT);
774     EMPTY_CACHE();
775 
776     MOVE_CURSOR(0,0);
777     FlushMessages();
778     COMPARE_CACHE(empty_chain);
779     FlushMessages();
780     COMPARE_CACHE(mouseleave_nonthemed_sequence);
781 
782     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
783     ok(state == 0, "Expected state 0, got %lu\n", state);
784     EMPTY_CACHE();
785 
786     SendMessageW(hWnd2, WM_THEMECHANGED, 1, 0);
787     FlushMessages();
788     COMPARE_CACHE(themechanged_sequence);
789 
790     SendMessageW(hWnd2, WM_ENABLE, TRUE, 0);
791     FlushMessages();
792     COMPARE_CACHE(enable_nonthemed_sequence);
793 
794     SendMessageW(hWnd2, WM_LBUTTONDOWN, 0, 0);
795     FlushMessages();
796     COMPARE_CACHE(btndown_nonthemed_sequence);
797 
798     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
799     ok_hex(state, BST_PUSHED | BST_FOCUS | 0x20 | 0x40);
800     EMPTY_CACHE();
801 
802     SendMessageW(hWnd2, WM_LBUTTONDOWN, 0, 0);
803     FlushMessages();
804     COMPARE_CACHE(btndown_repeat_nonthemed_sequence);
805 
806     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
807     ok_hex(state, BST_PUSHED | BST_FOCUS | 0x20 | 0x40);
808     EMPTY_CACHE();
809 
810     SendMessageW(hWnd2, BM_CLICK, 0, 0);
811     FlushMessages();
812     COMPARE_CACHE(btnclick_nonthemed_sequence);
813 
814     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
815     ok_hex(state, BST_FOCUS);
816     EMPTY_CACHE();
817 
818     SendMessageW(hWnd2, WM_LBUTTONUP, 0, 0);
819     FlushMessages();
820     COMPARE_CACHE(btnup_stray_sequence);
821 
822     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
823     ok_hex(state, BST_FOCUS);
824     EMPTY_CACHE();
825 
826     DestroyWindow(hWnd1);
827     DestroyWindow(hWnd2);
828 }
829 
830 void Test_MessagesThemed()
831 {
832     DWORD state;
833 
834     MOVE_CURSOR(0,0);
835     EMPTY_CACHE();
836 
837     RegisterSimpleClass(TestProc, L"testClass");
838     hWnd1 = CreateWindowW(L"testClass", L"Test parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0, NULL, NULL, NULL);
839     ok (hWnd1 != NULL, "Expected CreateWindowW to succeed\n");
840     UpdateWindow(hWnd1);
841 
842     hWnd2 = CreateWindowW(L"Button", L"test button", /*BS_RADIOBUTTON | */WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hWnd1, NULL, NULL, NULL);
843     ok (hWnd2 != NULL, "Expected CreateWindowW to succeed\n");
844     SetWindowSubclass(hWnd2, subclass_proc, 0, 0);
845     UpdateWindow(hWnd2);
846 
847     FlushMessages();
848     EMPTY_CACHE();
849 
850     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE);
851     FlushMessages();
852     COMPARE_CACHE(empty_chain);
853     FlushMessages();
854     COMPARE_CACHE(empty_chain);
855 
856     RedrawWindow(hWnd2, NULL, NULL, RDW_FRAME);
857     FlushMessages();
858     COMPARE_CACHE(empty_chain);
859 
860     RedrawWindow(hWnd2, NULL, NULL, RDW_INTERNALPAINT);
861     FlushMessages();
862     COMPARE_CACHE(paint_sequence);
863 
864     RedrawWindow(hWnd2, NULL, NULL, RDW_INVALIDATE);
865     FlushMessages();
866     COMPARE_CACHE(paint_sequence);
867 
868     RedrawWindow(hWnd2, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
869     FlushMessages();
870     COMPARE_CACHE(redraw_sequence);
871 
872     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_ERASEBKGND);
873     FlushMessages();
874     COMPARE_CACHE(printclnt_sequence);
875 
876     SendMessageW(hWnd2, WM_PRINTCLIENT, 0, PRF_CLIENT);
877     FlushMessages();
878     COMPARE_CACHE(printclnt_sequence);
879 
880     SendMessageW(hWnd2, WM_MOUSEMOVE, 0, 0);
881     FlushMessages();
882     COMPARE_CACHE(pseudomove_sequence);
883 
884     SendMessageW(hWnd2, WM_MOUSEHOVER, 0, 0);
885     FlushMessages();
886     COMPARE_CACHE(pseudohover_sequence);
887 
888     SendMessageW(hWnd2, WM_MOUSELEAVE, 0, 0);
889     FlushMessages();
890     COMPARE_CACHE(pseudoleave_sequence);
891 
892     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
893     ok(state == 0, "Expected state 0, got %lu", state);
894     EMPTY_CACHE();
895 
896     MOVE_CURSOR(150,150);
897     FlushMessages();
898     COMPARE_CACHE(mouseenter_sequence);
899 
900     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
901     ok(state == BST_HOT, "Expected state BST_HOT, got %lu", state);
902     EMPTY_CACHE();
903 
904     MOVE_CURSOR(151,151);
905     FlushMessages();
906     COMPARE_CACHE(mousemove_sequence);
907 
908     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
909     ok(state == BST_HOT, "Expected state BST_HOT, got %lu", state);
910     EMPTY_CACHE();
911 
912     MOVE_CURSOR(0,0);
913     FlushMessages();
914     COMPARE_CACHE(empty_chain);
915     FlushMessages();
916     COMPARE_CACHE(mouseleave_sequence);
917 
918     state = SendMessageW(hWnd2, BM_GETSTATE,0,0);
919     ok(state == 0, "Expected state 0, got %lu", state);
920     EMPTY_CACHE();
921 
922     DestroyWindow(hWnd1);
923     DestroyWindow(hWnd2);
924 }
925 
926 START_TEST(button)
927 {
928     LoadLibraryW(L"comctl32.dll"); /* same as statically linking to comctl32 and doing InitCommonControls */
929     Test_TextMargin();
930     Test_Imagelist();
931     Test_GetIdealSizeNoThemes();
932 
933     Test_MessagesNonThemed();
934     if (IsThemeActive())
935         Test_MessagesThemed();
936     else
937         skip("No active theme, skipping Test_MessagesThemed\n");
938 
939 }
940 
941