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