1 /* Unit test suite for uxtheme API functions
2  *
3  * Copyright 2006 Paul Vriens
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 
21 #include <stdarg.h>
22 
23 #include "windows.h"
24 #include "vfwmsgs.h"
25 #include "uxtheme.h"
26 
27 #include "wine/test.h"
28 
29 static HTHEME  (WINAPI * pOpenThemeDataEx)(HWND, LPCWSTR, DWORD);
30 static HPAINTBUFFER (WINAPI *pBeginBufferedPaint)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
31 static HRESULT (WINAPI *pBufferedPaintClear)(HPAINTBUFFER, const RECT *);
32 static HRESULT (WINAPI *pEndBufferedPaint)(HPAINTBUFFER, BOOL);
33 static HRESULT (WINAPI *pGetBufferedPaintBits)(HPAINTBUFFER, RGBQUAD **, int *);
34 static HDC (WINAPI *pGetBufferedPaintDC)(HPAINTBUFFER);
35 static HDC (WINAPI *pGetBufferedPaintTargetDC)(HPAINTBUFFER);
36 static HRESULT (WINAPI *pGetBufferedPaintTargetRect)(HPAINTBUFFER, RECT *);
37 
38 static void init_funcs(void)
39 {
40     HMODULE hUxtheme = GetModuleHandleA("uxtheme.dll");
41 
42 #define UXTHEME_GET_PROC(func) p ## func = (void*)GetProcAddress(hUxtheme, #func)
43     UXTHEME_GET_PROC(BeginBufferedPaint);
44     UXTHEME_GET_PROC(BufferedPaintClear);
45     UXTHEME_GET_PROC(EndBufferedPaint);
46     UXTHEME_GET_PROC(GetBufferedPaintBits);
47     UXTHEME_GET_PROC(GetBufferedPaintDC);
48     UXTHEME_GET_PROC(GetBufferedPaintTargetDC);
49     UXTHEME_GET_PROC(GetBufferedPaintTargetRect);
50     UXTHEME_GET_PROC(BufferedPaintClear);
51 
52     UXTHEME_GET_PROC(OpenThemeDataEx);
53 #undef UXTHEME_GET_PROC
54 }
55 
56 static void test_IsThemed(void)
57 {
58     BOOL bThemeActive;
59     BOOL bAppThemed;
60     BOOL bTPDefined;
61 
62     bThemeActive = IsThemeActive();
63     trace("Theming is %s\n", (bThemeActive) ? "active" : "inactive");
64 
65     bAppThemed = IsAppThemed();
66     trace("Test executable is %s\n", (bAppThemed) ? "themed" : "not themed");
67 
68     SetLastError(0xdeadbeef);
69     bTPDefined = IsThemePartDefined(NULL, 0 , 0);
70     ok( bTPDefined == FALSE, "Expected FALSE\n");
71     ok( GetLastError() == E_HANDLE,
72         "Expected E_HANDLE, got 0x%08x\n",
73         GetLastError());
74 }
75 
76 static void test_GetWindowTheme(void)
77 {
78     HTHEME    hTheme;
79     HWND      hWnd;
80 
81     SetLastError(0xdeadbeef);
82     hTheme = GetWindowTheme(NULL);
83     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
84     todo_wine
85         ok( GetLastError() == E_HANDLE,
86             "Expected E_HANDLE, got 0x%08x\n",
87             GetLastError());
88 
89     /* Only do the bare minimum to get a valid hwnd */
90     hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL);
91     ok(hWnd != NULL, "Failed to create a test window.\n");
92 
93     SetLastError(0xdeadbeef);
94     hTheme = GetWindowTheme(hWnd);
95     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
96     ok( GetLastError() == 0xdeadbeef,
97         "Expected 0xdeadbeef, got 0x%08x\n",
98         GetLastError());
99 
100     DestroyWindow(hWnd);
101 }
102 
103 static void test_SetWindowTheme(void)
104 {
105     HRESULT hRes;
106     HWND    hWnd;
107 
108     hRes = SetWindowTheme(NULL, NULL, NULL);
109 todo_wine
110     ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes);
111 
112     /* Only do the bare minimum to get a valid hwnd */
113     hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL);
114     ok(hWnd != NULL, "Failed to create a test window.\n");
115 
116     hRes = SetWindowTheme(hWnd, NULL, NULL);
117     ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
118 
119     DestroyWindow(hWnd);
120 }
121 
122 static void test_OpenThemeData(void)
123 {
124     HTHEME    hTheme, hTheme2;
125     HWND      hWnd;
126     BOOL      bThemeActive;
127     HRESULT   hRes;
128     BOOL      bTPDefined;
129 
130     WCHAR szInvalidClassList[] = {'D','E','A','D','B','E','E','F', 0 };
131     WCHAR szButtonClassList[]  = {'B','u','t','t','o','n', 0 };
132     WCHAR szButtonClassList2[]  = {'b','U','t','T','o','N', 0 };
133     WCHAR szClassList[]        = {'B','u','t','t','o','n',';','L','i','s','t','B','o','x', 0 };
134 
135     bThemeActive = IsThemeActive();
136 
137     /* All NULL */
138     SetLastError(0xdeadbeef);
139     hTheme = OpenThemeData(NULL, NULL);
140     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
141     ok( GetLastError() == E_POINTER,
142             "Expected GLE() to be E_POINTER, got 0x%08x\n",
143             GetLastError());
144 
145     /* A NULL hWnd and an invalid classlist */
146     SetLastError(0xdeadbeef);
147     hTheme = OpenThemeData(NULL, szInvalidClassList);
148     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
149     todo_wine
150         ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
151             "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
152             GetLastError());
153 
154     SetLastError(0xdeadbeef);
155     hTheme = OpenThemeData(NULL, szClassList);
156     if (bThemeActive)
157     {
158         ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
159         todo_wine
160             ok( GetLastError() == ERROR_SUCCESS,
161                 "Expected ERROR_SUCCESS, got 0x%08x\n",
162                 GetLastError());
163     }
164     else
165     {
166         ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
167         todo_wine
168             ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
169                 "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
170                 GetLastError());
171     }
172 
173     /* Only do the bare minimum to get a valid hdc */
174     hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL);
175     if (!hWnd) return;
176 
177     SetLastError(0xdeadbeef);
178     hTheme = OpenThemeData(hWnd, NULL);
179     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
180     ok( GetLastError() == E_POINTER,
181             "Expected GLE() to be E_POINTER, got 0x%08x\n",
182             GetLastError());
183 
184     SetLastError(0xdeadbeef);
185     hTheme = OpenThemeData(hWnd, szInvalidClassList);
186     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
187     todo_wine
188         ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
189             "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
190             GetLastError());
191 
192     /* Close invalid handle */
193     hRes = CloseThemeData((HTHEME)0xdeadbeef);
194     ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes);
195 
196     if (!bThemeActive)
197     {
198         SetLastError(0xdeadbeef);
199         hTheme = OpenThemeData(hWnd, szButtonClassList);
200         ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
201         todo_wine
202             ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
203                 "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
204                 GetLastError());
205         skip("No active theme, skipping rest of OpenThemeData tests\n");
206         return;
207     }
208 
209     /* Only do the next checks if we have an active theme */
210 
211     SetLastError(0xdeadbeef);
212     hTheme = OpenThemeData(hWnd, szButtonClassList);
213     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
214     todo_wine
215         ok( GetLastError() == ERROR_SUCCESS,
216             "Expected ERROR_SUCCESS, got 0x%08x\n",
217             GetLastError());
218 
219     /* Test with bUtToN instead of Button */
220     SetLastError(0xdeadbeef);
221     hTheme = OpenThemeData(hWnd, szButtonClassList2);
222     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
223     todo_wine
224         ok( GetLastError() == ERROR_SUCCESS,
225             "Expected ERROR_SUCCESS, got 0x%08x\n",
226             GetLastError());
227 
228     SetLastError(0xdeadbeef);
229     hTheme = OpenThemeData(hWnd, szClassList);
230     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
231     todo_wine
232         ok( GetLastError() == ERROR_SUCCESS,
233             "Expected ERROR_SUCCESS, got 0x%08x\n",
234             GetLastError());
235 
236     /* GetWindowTheme should return the last handle opened by OpenThemeData */
237     SetLastError(0xdeadbeef);
238     hTheme2 = GetWindowTheme(hWnd);
239     ok( hTheme == hTheme2, "Expected the same HTHEME handle (%p<->%p)\n",
240         hTheme, hTheme2);
241     ok( GetLastError() == 0xdeadbeef,
242         "Expected 0xdeadbeef, got 0x%08x\n",
243         GetLastError());
244 
245     hRes = CloseThemeData(hTheme);
246     ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
247 
248     /* Close a second time */
249     hRes = CloseThemeData(hTheme);
250     ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
251 
252     /* See if closing makes a difference for GetWindowTheme */
253     SetLastError(0xdeadbeef);
254     hTheme2 = NULL;
255     hTheme2 = GetWindowTheme(hWnd);
256     ok( hTheme == hTheme2, "Expected the same HTHEME handle (%p<->%p)\n",
257         hTheme, hTheme2);
258     ok( GetLastError() == 0xdeadbeef,
259         "Expected 0xdeadbeef, got 0x%08x\n",
260         GetLastError());
261 
262     SetLastError(0xdeadbeef);
263     bTPDefined = IsThemePartDefined(hTheme, 0 , 0);
264     todo_wine
265     {
266         ok( bTPDefined == FALSE, "Expected FALSE\n");
267         ok( GetLastError() == ERROR_SUCCESS,
268             "Expected ERROR_SUCCESS, got 0x%08x\n",
269             GetLastError());
270     }
271 
272     DestroyWindow(hWnd);
273 }
274 
275 static void test_OpenThemeDataEx(void)
276 {
277     HTHEME    hTheme;
278     HWND      hWnd;
279     BOOL      bThemeActive;
280 
281     WCHAR szInvalidClassList[] = {'D','E','A','D','B','E','E','F', 0 };
282     WCHAR szButtonClassList[]  = {'B','u','t','t','o','n', 0 };
283     WCHAR szButtonClassList2[]  = {'b','U','t','T','o','N', 0 };
284     WCHAR szClassList[]        = {'B','u','t','t','o','n',';','L','i','s','t','B','o','x', 0 };
285 
286     if (!pOpenThemeDataEx)
287     {
288         win_skip("OpenThemeDataEx not available\n");
289         return;
290     }
291 
292     bThemeActive = IsThemeActive();
293 
294     /* All NULL */
295     SetLastError(0xdeadbeef);
296     hTheme = pOpenThemeDataEx(NULL, NULL, 0);
297     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
298     ok( GetLastError() == E_POINTER,
299             "Expected GLE() to be E_POINTER, got 0x%08x\n",
300             GetLastError());
301 
302     /* A NULL hWnd and an invalid classlist without flags */
303     SetLastError(0xdeadbeef);
304     hTheme = pOpenThemeDataEx(NULL, szInvalidClassList, 0);
305     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
306     todo_wine
307         ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
308             "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
309             GetLastError());
310 
311     SetLastError(0xdeadbeef);
312     hTheme = pOpenThemeDataEx(NULL, szClassList, 0);
313     if (bThemeActive)
314     {
315         ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
316         todo_wine
317             ok( GetLastError() == ERROR_SUCCESS,
318                 "Expected ERROR_SUCCESS, got 0x%08x\n",
319                 GetLastError());
320     }
321     else
322     {
323         ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
324         todo_wine
325             ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
326                 "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
327                 GetLastError());
328     }
329 
330     /* Only do the bare minimum to get a valid hdc */
331     hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL);
332     if (!hWnd) return;
333 
334     SetLastError(0xdeadbeef);
335     hTheme = pOpenThemeDataEx(hWnd, NULL, 0);
336     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
337     ok( GetLastError() == E_POINTER,
338             "Expected GLE() to be E_POINTER, got 0x%08x\n",
339             GetLastError());
340 
341     SetLastError(0xdeadbeef);
342     hTheme = pOpenThemeDataEx(hWnd, szInvalidClassList, 0);
343     ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
344     todo_wine
345         ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
346             "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
347             GetLastError());
348 
349     if (!bThemeActive)
350     {
351         SetLastError(0xdeadbeef);
352         hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0);
353         ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme);
354         todo_wine
355             ok( GetLastError() == E_PROP_ID_UNSUPPORTED,
356                 "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n",
357                 GetLastError());
358         skip("No active theme, skipping rest of OpenThemeDataEx tests\n");
359         return;
360     }
361 
362     /* Only do the next checks if we have an active theme */
363 
364     SetLastError(0xdeadbeef);
365     hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0);
366     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
367     todo_wine
368         ok( GetLastError() == ERROR_SUCCESS,
369             "Expected ERROR_SUCCESS, got 0x%08x\n",
370             GetLastError());
371 
372     SetLastError(0xdeadbeef);
373     hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, OTD_FORCE_RECT_SIZING);
374     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
375     todo_wine
376         ok( GetLastError() == ERROR_SUCCESS,
377             "Expected ERROR_SUCCESS, got 0x%08x\n",
378             GetLastError());
379 
380     SetLastError(0xdeadbeef);
381     hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, OTD_NONCLIENT);
382     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
383     todo_wine
384         ok( GetLastError() == ERROR_SUCCESS,
385             "Expected ERROR_SUCCESS, got 0x%08x\n",
386             GetLastError());
387 
388     SetLastError(0xdeadbeef);
389     hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0x3);
390     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
391     todo_wine
392         ok( GetLastError() == ERROR_SUCCESS,
393             "Expected ERROR_SUCCESS, got 0x%08x\n",
394             GetLastError());
395 
396     /* Test with bUtToN instead of Button */
397     SetLastError(0xdeadbeef);
398     hTheme = pOpenThemeDataEx(hWnd, szButtonClassList2, 0);
399     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
400     todo_wine
401         ok( GetLastError() == ERROR_SUCCESS,
402             "Expected ERROR_SUCCESS, got 0x%08x\n",
403             GetLastError());
404 
405     SetLastError(0xdeadbeef);
406     hTheme = pOpenThemeDataEx(hWnd, szClassList, 0);
407     ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n");
408     todo_wine
409         ok( GetLastError() == ERROR_SUCCESS,
410             "Expected ERROR_SUCCESS, got 0x%08x\n",
411             GetLastError());
412 
413     DestroyWindow(hWnd);
414 }
415 
416 static void test_GetCurrentThemeName(void)
417 {
418     BOOL    bThemeActive;
419     HRESULT hRes;
420     WCHAR currentTheme[MAX_PATH];
421     WCHAR currentColor[MAX_PATH];
422     WCHAR currentSize[MAX_PATH];
423 
424     bThemeActive = IsThemeActive();
425 
426     /* All NULLs */
427     hRes = GetCurrentThemeName(NULL, 0, NULL, 0, NULL, 0);
428     if (bThemeActive)
429         ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
430     else
431         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
432 
433     /* Number of characters given is 0 */
434     hRes = GetCurrentThemeName(currentTheme, 0, NULL, 0, NULL, 0);
435     if (bThemeActive)
436         ok( hRes == S_OK || broken(hRes == E_FAIL /* WinXP SP1 */), "Expected S_OK, got 0x%08x\n", hRes);
437     else
438         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
439 
440     hRes = GetCurrentThemeName(currentTheme, 2, NULL, 0, NULL, 0);
441     if (bThemeActive)
442         todo_wine
443             ok(hRes == E_NOT_SUFFICIENT_BUFFER ||
444                broken(hRes == E_FAIL /* WinXP SP1 */),
445                "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes);
446     else
447         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
448 
449     /* The same is true if the number of characters is too small for Color and/or Size */
450     hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor, 2,
451                                currentSize,  ARRAY_SIZE(currentSize));
452     if (bThemeActive)
453         todo_wine
454             ok(hRes == E_NOT_SUFFICIENT_BUFFER ||
455                broken(hRes == E_FAIL /* WinXP SP1 */),
456                "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes);
457     else
458         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
459 
460     /* Given number of characters is correct */
461     hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), NULL, 0, NULL, 0);
462     if (bThemeActive)
463         ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
464     else
465         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
466 
467     /* Given number of characters for the theme name is too large */
468     hRes = GetCurrentThemeName(currentTheme, sizeof(currentTheme), NULL, 0, NULL, 0);
469     if (bThemeActive)
470         ok( hRes == E_POINTER || hRes == S_OK, "Expected E_POINTER or S_OK, got 0x%08x\n", hRes);
471     else
472         ok( hRes == E_PROP_ID_UNSUPPORTED ||
473             hRes == E_POINTER, /* win2k3 */
474             "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
475 
476     /* The too large case is only for the theme name, not for color name or size name */
477     hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor,
478                                sizeof(currentTheme), currentSize,  ARRAY_SIZE(currentSize));
479     if (bThemeActive)
480         ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
481     else
482         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
483 
484     hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor,
485                                ARRAY_SIZE(currentTheme), currentSize,  sizeof(currentSize));
486     if (bThemeActive)
487         ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
488     else
489         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
490 
491     /* Correct call */
492     hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor,
493                                ARRAY_SIZE(currentColor), currentSize,  ARRAY_SIZE(currentSize));
494     if (bThemeActive)
495         ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes);
496     else
497         ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes);
498 }
499 
500 static void test_CloseThemeData(void)
501 {
502     HRESULT hRes;
503 
504     hRes = CloseThemeData(NULL);
505     ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes);
506     hRes = CloseThemeData(INVALID_HANDLE_VALUE);
507     ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes);
508 }
509 
510 static void test_buffer_dc_props(HDC hdc, const RECT *rect)
511 {
512     static const XFORM ident = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
513     XFORM xform;
514     POINT org;
515     RECT box;
516     BOOL ret;
517 
518     ret = GetWorldTransform(hdc, &xform);
519     ok(ret, "Failed to get world transform\n");
520     ok(!memcmp(&xform, &ident, sizeof(xform)), "Unexpected world transform\n");
521 
522     ret = GetViewportOrgEx(hdc, &org);
523     ok(ret, "Failed to get vport origin\n");
524     ok(org.x == 0 && org.y == 0, "Unexpected vport origin\n");
525 
526     ret = GetWindowOrgEx(hdc, &org);
527     ok(ret, "Failed to get vport origin\n");
528     ok(org.x == rect->left && org.y == rect->top, "Unexpected window origin\n");
529 
530     ret = GetClipBox(hdc, &box);
531     ok(ret, "Failed to get clip box\n");
532     ok(box.left == rect->left && box.top == rect->top, "Unexpected clip box\n");
533 
534     ok(GetGraphicsMode(hdc) == GM_COMPATIBLE, "wrong graphics mode\n");
535 }
536 
537 static void test_buffered_paint(void)
538 {
539     HDC target, src, hdc, screen_dc;
540     BP_PAINTPARAMS params = { 0 };
541     BP_BUFFERFORMAT format;
542     HPAINTBUFFER buffer;
543     RECT rect, rect2;
544     RGBQUAD *bits;
545     HBITMAP hbm;
546     HRESULT hr;
547     int row;
548 
549     if (!pBeginBufferedPaint)
550     {
551         win_skip("Buffered painting API is not supported.\n");
552         return;
553     }
554 
555     buffer = pBeginBufferedPaint(NULL, NULL, BPBF_COMPATIBLEBITMAP,
556             NULL, NULL);
557     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
558 
559     target = CreateCompatibleDC(0);
560     buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP,
561             NULL, NULL);
562     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
563 
564     params.cbSize = sizeof(params);
565     buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP,
566             &params, NULL);
567     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
568 
569     src = (void *)0xdeadbeef;
570     buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP,
571             &params, &src);
572     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
573     ok(src == NULL, "Unexpected buffered dc %p\n", src);
574 
575     /* target rect is mandatory */
576     SetRectEmpty(&rect);
577     src = (void *)0xdeadbeef;
578     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP,
579             &params, &src);
580     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
581     ok(src == NULL, "Unexpected buffered dc %p\n", src);
582 
583     /* inverted rectangle */
584     SetRect(&rect, 10, 0, 5, 5);
585     src = (void *)0xdeadbeef;
586     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP,
587             &params, &src);
588     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
589     ok(src == NULL, "Unexpected buffered dc %p\n", src);
590 
591     SetRect(&rect, 0, 10, 5, 0);
592     src = (void *)0xdeadbeef;
593     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP,
594             &params, &src);
595     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
596     ok(src == NULL, "Unexpected buffered dc %p\n", src);
597 
598     /* valid rectangle, no target dc */
599     SetRect(&rect, 0, 0, 5, 5);
600     src = (void *)0xdeadbeef;
601     buffer = pBeginBufferedPaint(NULL, &rect, BPBF_COMPATIBLEBITMAP,
602             &params, &src);
603     ok(buffer == NULL, "Unexpected buffer %p\n", buffer);
604     ok(src == NULL, "Unexpected buffered dc %p\n", src);
605 
606     SetRect(&rect, 0, 0, 5, 5);
607     src = NULL;
608     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP,
609             &params, &src);
610     ok(buffer != NULL, "Unexpected buffer %p\n", buffer);
611     ok(src != NULL, "Expected buffered dc\n");
612     hr = pEndBufferedPaint(buffer, FALSE);
613     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
614 
615     SetRect(&rect, 0, 0, 5, 5);
616     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP,
617             &params, &src);
618     ok(buffer != NULL, "Unexpected buffer %p\n", buffer);
619 
620     /* clearing */
621     hr = pBufferedPaintClear(NULL, NULL);
622 todo_wine
623     ok(hr == E_FAIL, "Unexpected return code %#x\n", hr);
624 
625     hr = pBufferedPaintClear(buffer, NULL);
626 todo_wine
627     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
628 
629     /* access buffer attributes */
630     hdc = pGetBufferedPaintDC(buffer);
631     ok(hdc == src, "Unexpected hdc, %p, buffered dc %p\n", hdc, src);
632 
633     hdc = pGetBufferedPaintTargetDC(buffer);
634     ok(hdc == target, "Unexpected target hdc %p, original %p\n", hdc, target);
635 
636     hr = pGetBufferedPaintTargetRect(NULL, NULL);
637     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
638 
639     hr = pGetBufferedPaintTargetRect(buffer, NULL);
640     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
641 
642     hr = pGetBufferedPaintTargetRect(NULL, &rect2);
643     ok(hr == E_FAIL, "Unexpected return code %#x\n", hr);
644 
645     SetRectEmpty(&rect2);
646     hr = pGetBufferedPaintTargetRect(buffer, &rect2);
647     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
648     ok(EqualRect(&rect, &rect2), "Wrong target rect\n");
649 
650     hr = pEndBufferedPaint(buffer, FALSE);
651     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
652 
653     /* invalid buffer handle */
654     hr = pEndBufferedPaint(NULL, FALSE);
655     ok(hr == E_INVALIDARG, "Unexpected return code %#x\n", hr);
656 
657     hdc = pGetBufferedPaintDC(NULL);
658     ok(hdc == NULL, "Unexpected hdc %p\n", hdc);
659 
660     hdc = pGetBufferedPaintTargetDC(NULL);
661     ok(hdc == NULL, "Unexpected target hdc %p\n", hdc);
662 
663     hr = pGetBufferedPaintTargetRect(NULL, &rect2);
664     ok(hr == E_FAIL, "Unexpected return code %#x\n", hr);
665 
666     hr = pGetBufferedPaintTargetRect(NULL, NULL);
667     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
668 
669     bits = (void *)0xdeadbeef;
670     row = 10;
671     hr = pGetBufferedPaintBits(NULL, &bits, &row);
672     ok(hr == E_FAIL, "Unexpected return code %#x\n", hr);
673     ok(row == 10, "Unexpected row count %d\n", row);
674     ok(bits == (void *)0xdeadbeef, "Unexpected data pointer %p\n", bits);
675 
676     hr = pGetBufferedPaintBits(NULL, NULL, NULL);
677     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
678 
679     hr = pGetBufferedPaintBits(NULL, &bits, NULL);
680     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
681 
682     hr = pGetBufferedPaintBits(NULL, NULL, &row);
683     ok(hr == E_POINTER, "Unexpected return code %#x\n", hr);
684 
685     screen_dc = GetDC(0);
686 
687     hdc = CreateCompatibleDC(screen_dc);
688     ok(hdc != NULL, "Failed to create a DC\n");
689     hbm = CreateCompatibleBitmap(screen_dc, 64, 64);
690     ok(hbm != NULL, "Failed to create a bitmap\n");
691     SelectObject(hdc, hbm);
692 
693     ReleaseDC(0, screen_dc);
694 
695     SetRect(&rect, 1, 2, 34, 56);
696 
697     buffer = pBeginBufferedPaint(hdc, &rect, BPBF_COMPATIBLEBITMAP, NULL, &src);
698     test_buffer_dc_props(src, &rect);
699     hr = pEndBufferedPaint(buffer, FALSE);
700     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
701 
702     DeleteObject(hbm);
703     DeleteDC(hdc);
704 
705     buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, NULL, &src);
706     test_buffer_dc_props(src, &rect);
707     hr = pEndBufferedPaint(buffer, FALSE);
708     ok(hr == S_OK, "Unexpected return code %#x\n", hr);
709 
710     /* access buffer bits */
711     for (format = BPBF_COMPATIBLEBITMAP; format <= BPBF_TOPDOWNMONODIB; format++)
712     {
713         buffer = pBeginBufferedPaint(target, &rect, format, &params, &src);
714 
715         /* only works for DIB buffers */
716         bits = NULL;
717         row = 0;
718         hr = pGetBufferedPaintBits(buffer, &bits, &row);
719         if (format == BPBF_COMPATIBLEBITMAP)
720             ok(hr == E_FAIL, "Unexpected return code %#x\n", hr);
721         else
722         {
723             ok(hr == S_OK, "Unexpected return code %#x\n", hr);
724             ok(bits != NULL, "Bitmap bits %p\n", bits);
725             ok(row >= (rect.right - rect.left), "format %d: bitmap width %d\n", format, row);
726         }
727 
728         hr = pEndBufferedPaint(buffer, FALSE);
729         ok(hr == S_OK, "Unexpected return code %#x\n", hr);
730     }
731 
732     DeleteDC(target);
733 }
734 
735 START_TEST(system)
736 {
737     init_funcs();
738 
739     /* No real functional theme API tests will be done (yet). The current tests
740      * only show input/return behaviour
741      */
742 
743     test_IsThemed();
744     test_GetWindowTheme();
745     test_SetWindowTheme();
746     test_OpenThemeData();
747     test_OpenThemeDataEx();
748     test_GetCurrentThemeName();
749     test_CloseThemeData();
750     test_buffered_paint();
751 }
752