1 /* Unit test suite for uxtheme API functions
3 * Copyright 2006 Paul Vriens
4 * Copyright 2021-2022 Zhiyi Zhang for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define WIN32_NO_STATUS
29 #include "ddk/d3dkmthk.h"
35 #include "wine/test.h"
39 static HTHEME (WINAPI
* pOpenThemeDataEx
)(HWND
, LPCWSTR
, DWORD
);
40 static HTHEME (WINAPI
*pOpenThemeDataForDpi
)(HWND
, LPCWSTR
, UINT
);
41 static HPAINTBUFFER (WINAPI
*pBeginBufferedPaint
)(HDC
, const RECT
*, BP_BUFFERFORMAT
, BP_PAINTPARAMS
*, HDC
*);
42 static HRESULT (WINAPI
*pBufferedPaintClear
)(HPAINTBUFFER
, const RECT
*);
43 static HRESULT (WINAPI
*pDrawThemeBackgroundEx
)(HTHEME
, HDC
, int, int, const RECT
*, const DTBGOPTS
*);
44 static HRESULT (WINAPI
*pEndBufferedPaint
)(HPAINTBUFFER
, BOOL
);
45 static HRESULT (WINAPI
*pGetBufferedPaintBits
)(HPAINTBUFFER
, RGBQUAD
**, int *);
46 static HDC (WINAPI
*pGetBufferedPaintDC
)(HPAINTBUFFER
);
47 static HDC (WINAPI
*pGetBufferedPaintTargetDC
)(HPAINTBUFFER
);
48 static HRESULT (WINAPI
*pGetBufferedPaintTargetRect
)(HPAINTBUFFER
, RECT
*);
49 static HRESULT (WINAPI
*pGetThemeIntList
)(HTHEME
, int, int, int, INTLIST
*);
50 static HRESULT (WINAPI
*pGetThemeTransitionDuration
)(HTHEME
, int, int, int, int, DWORD
*);
51 static BOOL (WINAPI
*pShouldSystemUseDarkMode
)(void);
52 static BOOL (WINAPI
*pShouldAppsUseDarkMode
)(void);
54 static LONG (WINAPI
*pDisplayConfigGetDeviceInfo
)(DISPLAYCONFIG_DEVICE_INFO_HEADER
*);
55 static LONG (WINAPI
*pDisplayConfigSetDeviceInfo
)(DISPLAYCONFIG_DEVICE_INFO_HEADER
*);
56 static BOOL (WINAPI
*pGetDpiForMonitorInternal
)(HMONITOR
, UINT
, UINT
*, UINT
*);
57 static UINT (WINAPI
*pGetDpiForSystem
)(void);
58 static DPI_AWARENESS_CONTEXT (WINAPI
*pSetThreadDpiAwarenessContext
)(DPI_AWARENESS_CONTEXT
);
60 static NTSTATUS (WINAPI
*pD3DKMTCloseAdapter
)(const D3DKMT_CLOSEADAPTER
*);
61 static NTSTATUS (WINAPI
*pD3DKMTOpenAdapterFromGdiDisplayName
)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME
*);
63 /* For message tests */
71 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
73 static void init_funcs(void)
75 HMODULE user32
= GetModuleHandleA("user32.dll");
76 HMODULE gdi32
= GetModuleHandleA("gdi32.dll");
77 HMODULE uxtheme
= GetModuleHandleA("uxtheme.dll");
79 pShouldSystemUseDarkMode
= (void *)GetProcAddress(uxtheme
, MAKEINTRESOURCEA(138));
80 pShouldAppsUseDarkMode
= (void *)GetProcAddress(uxtheme
, MAKEINTRESOURCEA(132));
82 #define GET_PROC(module, func) \
83 p##func = (void *)GetProcAddress(module, #func); \
85 trace("GetProcAddress(%s, %s) failed.\n", #module, #func);
87 GET_PROC(uxtheme
, BeginBufferedPaint
)
88 GET_PROC(uxtheme
, BufferedPaintClear
)
89 GET_PROC(uxtheme
, EndBufferedPaint
)
90 GET_PROC(uxtheme
, DrawThemeBackgroundEx
)
91 GET_PROC(uxtheme
, GetBufferedPaintBits
)
92 GET_PROC(uxtheme
, GetBufferedPaintDC
)
93 GET_PROC(uxtheme
, GetBufferedPaintTargetDC
)
94 GET_PROC(uxtheme
, GetBufferedPaintTargetRect
)
95 GET_PROC(uxtheme
, GetThemeIntList
)
96 GET_PROC(uxtheme
, GetThemeTransitionDuration
)
97 GET_PROC(uxtheme
, OpenThemeDataEx
)
98 GET_PROC(uxtheme
, OpenThemeDataForDpi
)
100 GET_PROC(user32
, DisplayConfigGetDeviceInfo
)
101 GET_PROC(user32
, DisplayConfigSetDeviceInfo
)
102 GET_PROC(user32
, GetDpiForMonitorInternal
)
103 GET_PROC(user32
, GetDpiForSystem
)
104 GET_PROC(user32
, SetThreadDpiAwarenessContext
)
106 GET_PROC(gdi32
, D3DKMTCloseAdapter
)
107 GET_PROC(gdi32
, D3DKMTOpenAdapterFromGdiDisplayName
)
112 static BOOL
compare_uint(unsigned int x
, unsigned int y
, unsigned int max_diff
)
114 unsigned int diff
= x
> y
? x
- y
: y
- x
;
116 return diff
<= max_diff
;
119 /* Try to make sure pending X events have been processed before continuing */
120 static void flush_events(void)
124 int min_timeout
= 100;
125 DWORD time
= GetTickCount() + diff
;
129 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
)
131 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
132 DispatchMessageA(&msg
);
133 diff
= time
- GetTickCount();
137 static unsigned int get_primary_monitor_effective_dpi(void)
139 DPI_AWARENESS_CONTEXT old_context
;
140 UINT dpi_x
= 0, dpi_y
= 0;
141 POINT point
= {0, 0};
144 if (pSetThreadDpiAwarenessContext
&& pGetDpiForMonitorInternal
)
146 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
147 monitor
= MonitorFromPoint(point
, MONITOR_DEFAULTTOPRIMARY
);
148 pGetDpiForMonitorInternal(monitor
, 0, &dpi_x
, &dpi_y
);
149 pSetThreadDpiAwarenessContext(old_context
);
153 return USER_DEFAULT_SCREEN_DPI
;
156 static int get_dpi_scale_index(int dpi
)
158 static const int scales
[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500};
159 int scale
, scale_idx
;
161 scale
= dpi
* 100 / 96;
162 for (scale_idx
= 0; scale_idx
< ARRAY_SIZE(scales
); ++scale_idx
)
164 if (scales
[scale_idx
] == scale
)
171 static BOOL
set_primary_monitor_effective_dpi(unsigned int primary_dpi
)
173 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc
;
174 DISPLAYCONFIG_GET_SOURCE_DPI_SCALE get_scale_req
;
175 DISPLAYCONFIG_SET_SOURCE_DPI_SCALE set_scale_req
;
176 int current_scale_idx
, target_scale_idx
;
177 D3DKMT_CLOSEADAPTER close_adapter_desc
;
181 #define CHECK_FUNC(func) \
184 win_skip("%s() is unavailable.\n", #func); \
188 CHECK_FUNC(D3DKMTCloseAdapter
)
189 CHECK_FUNC(D3DKMTOpenAdapterFromGdiDisplayName
)
190 CHECK_FUNC(DisplayConfigGetDeviceInfo
)
191 todo_wine
CHECK_FUNC(DisplayConfigSetDeviceInfo
)
192 if (ret
) return FALSE
;
196 lstrcpyW(open_adapter_gdi_desc
.DeviceName
, L
"\\\\.\\DISPLAY1");
197 if (pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc
) == STATUS_PROCEDURE_NOT_FOUND
)
199 win_skip("D3DKMTOpenAdapterFromGdiDisplayName() is unavailable.\n");
203 get_scale_req
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE
;
204 get_scale_req
.header
.size
= sizeof(get_scale_req
);
205 get_scale_req
.header
.adapterId
= open_adapter_gdi_desc
.AdapterLuid
;
206 get_scale_req
.header
.id
= open_adapter_gdi_desc
.VidPnSourceId
;
207 error
= pDisplayConfigGetDeviceInfo(&get_scale_req
.header
);
208 if (error
!= NO_ERROR
)
210 skip("DisplayConfigGetDeviceInfo failed, returned %ld.\n", error
);
214 current_scale_idx
= get_dpi_scale_index(get_primary_monitor_effective_dpi());
215 if (current_scale_idx
== -1)
217 skip("Failed to find current scale index.\n");
221 target_scale_idx
= get_dpi_scale_index(primary_dpi
);
222 if (target_scale_idx
< get_scale_req
.minRelativeScaleStep
223 || target_scale_idx
> get_scale_req
.maxRelativeScaleStep
)
225 skip("DPI %d is not available.\n", primary_dpi
);
229 set_scale_req
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE
;
230 set_scale_req
.header
.size
= sizeof(set_scale_req
);
231 set_scale_req
.header
.adapterId
= open_adapter_gdi_desc
.AdapterLuid
;
232 set_scale_req
.header
.id
= open_adapter_gdi_desc
.VidPnSourceId
;
233 set_scale_req
.relativeScaleStep
= get_scale_req
.curRelativeScaleStep
+ (target_scale_idx
- current_scale_idx
);
234 error
= pDisplayConfigSetDeviceInfo(&set_scale_req
.header
);
235 if (error
== NO_ERROR
)
236 ret
= get_primary_monitor_effective_dpi() == primary_dpi
;
240 close_adapter_desc
.hAdapter
= open_adapter_gdi_desc
.hAdapter
;
241 pD3DKMTCloseAdapter(&close_adapter_desc
);
245 static LRESULT WINAPI
TestSetWindowThemeParentProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
247 static LONG defwndproc_counter
;
248 struct message msg
= {0};
251 /* Only care about WM_THEMECHANGED */
252 if (message
!= WM_THEMECHANGED
)
253 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
255 msg
.message
= message
;
256 msg
.flags
= sent
| wparam
| lparam
;
257 if (defwndproc_counter
)
258 msg
.flags
|= defwinproc
;
261 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
263 InterlockedIncrement(&defwndproc_counter
);
264 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
265 InterlockedDecrement(&defwndproc_counter
);
269 static LRESULT WINAPI
TestSetWindowThemeChildProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
271 static LONG defwndproc_counter
;
272 struct message msg
= {0};
275 /* Only care about WM_THEMECHANGED */
276 if (message
!= WM_THEMECHANGED
)
277 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
279 msg
.message
= message
;
280 msg
.flags
= sent
| wparam
| lparam
;
281 if (defwndproc_counter
)
282 msg
.flags
|= defwinproc
;
285 add_message(sequences
, CHILD_SEQ_INDEX
, &msg
);
287 InterlockedIncrement(&defwndproc_counter
);
288 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
289 InterlockedDecrement(&defwndproc_counter
);
293 static void test_IsThemed(void)
298 bThemeActive
= IsThemeActive();
299 trace("Theming is %s\n", (bThemeActive
) ? "active" : "inactive");
301 bAppThemed
= IsAppThemed();
302 trace("Test executable is %s\n", (bAppThemed
) ? "themed" : "not themed");
305 static void test_IsThemePartDefined(void)
307 BOOL is_theme_active
, ret
;
315 const WCHAR
*class_name
;
323 {NULL
, 0, 0, FALSE
, E_HANDLE
},
324 {NULL
, 0xdeadbeef, 0, FALSE
, E_HANDLE
},
325 {L
"Button", 0xdeadbeef, 0, FALSE
, NO_ERROR
},
326 {L
"Button", BP_PUSHBUTTON
, 0, TRUE
, NO_ERROR
},
327 {L
"Button", BP_PUSHBUTTON
, PBS_NORMAL
, FALSE
, NO_ERROR
},
328 {L
"Button", BP_PUSHBUTTON
, PBS_DEFAULTED_ANIMATING
, FALSE
, NO_ERROR
},
329 {L
"Button", BP_PUSHBUTTON
, PBS_DEFAULTED_ANIMATING
+ 1, FALSE
, NO_ERROR
},
330 {L
"Edit", EP_EDITTEXT
, 0, TRUE
, NO_ERROR
},
331 {L
"Edit", EP_EDITTEXT
, ETS_NORMAL
, FALSE
, NO_ERROR
},
332 {L
"Edit", EP_EDITTEXT
, ETS_FOCUSED
, FALSE
, NO_ERROR
},
335 is_theme_active
= IsThemeActive();
336 hwnd
= CreateWindowA(WC_STATICA
, "", WS_POPUP
, 0, 0, 1, 1, 0, 0, 0, NULL
);
337 ok(hwnd
!= NULL
, "CreateWindowA failed, error %#lx.\n", GetLastError());
339 for (i
= 0; i
< ARRAY_SIZE(tests
); ++i
)
341 if (!is_theme_active
&& tests
[i
].class_name
)
344 winetest_push_context("class %s part %d state %d", wine_dbgstr_w(tests
[i
].class_name
),
345 tests
[i
].part
, tests
[i
].state
);
347 if (tests
[i
].class_name
)
349 theme
= OpenThemeData(hwnd
, tests
[i
].class_name
);
350 ok(theme
!= NULL
, "OpenThemeData failed, error %#lx.\n", GetLastError());
353 SetLastError(0xdeadbeef);
354 ret
= IsThemePartDefined(theme
, tests
[i
].part
, tests
[i
].state
);
355 error
= GetLastError();
356 ok(ret
== tests
[i
].defined
, "Expected %d.\n", tests
[i
].defined
);
357 ok(error
== tests
[i
].error
, "Expected %#lx, got %#lx.\n", tests
[i
].error
, error
);
361 CloseThemeData(theme
);
364 winetest_pop_context();
370 static void test_GetWindowTheme(void)
375 SetLastError(0xdeadbeef);
376 hTheme
= GetWindowTheme(NULL
);
377 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
378 ok( GetLastError() == E_HANDLE
, "Expected E_HANDLE, got 0x%08lx\n", GetLastError() );
380 /* Only do the bare minimum to get a valid hwnd */
381 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
382 ok(hWnd
!= NULL
, "Failed to create a test window.\n");
384 SetLastError(0xdeadbeef);
385 hTheme
= GetWindowTheme(hWnd
);
386 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
387 ok( GetLastError() == 0xdeadbeef,
388 "Expected 0xdeadbeef, got 0x%08lx\n",
394 static const struct message SetWindowThemeSeq
[] =
396 {WM_THEMECHANGED
, sent
},
400 static const struct message EmptySeq
[] =
405 static void test_SetWindowTheme(void)
413 hRes
= SetWindowTheme(NULL
, NULL
, NULL
);
414 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08lx\n", hRes
);
416 /* Test that WM_THEMECHANGED is sent and not posted to windows */
417 cls
.hInstance
= GetModuleHandleA(0);
418 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
419 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
420 cls
.lpfnWndProc
= TestSetWindowThemeParentProcA
;
421 cls
.lpszClassName
= "TestSetWindowThemeParentClass";
422 RegisterClassA(&cls
);
424 cls
.lpfnWndProc
= TestSetWindowThemeChildProcA
;
425 cls
.lpszClassName
= "TestSetWindowThemeChildClass";
426 RegisterClassA(&cls
);
428 hWnd
= CreateWindowA("TestSetWindowThemeParentClass", "parent",
429 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
, 100, 100, 200, 200, 0, 0, 0, NULL
);
430 ok(!!hWnd
, "Failed to create a parent window.\n");
431 child
= CreateWindowA("TestSetWindowThemeChildClass", "child", WS_CHILD
| WS_VISIBLE
, 0, 0, 50,
432 50, hWnd
, 0, 0, NULL
);
433 ok(!!child
, "Failed to create a child window.\n");
435 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
437 hRes
= SetWindowTheme(hWnd
, NULL
, NULL
);
438 ok(hRes
== S_OK
, "Expected %#lx, got %#lx.\n", S_OK
, hRes
);
439 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
441 struct message recv_msg
= {0};
443 if (msg
.message
== WM_THEMECHANGED
)
445 recv_msg
.message
= msg
.message
;
446 recv_msg
.flags
= posted
| wparam
| lparam
;
447 recv_msg
.wParam
= msg
.wParam
;
448 recv_msg
.lParam
= msg
.lParam
;
449 add_message(sequences
, msg
.hwnd
== hWnd
? PARENT_SEQ_INDEX
: CHILD_SEQ_INDEX
, &recv_msg
);
451 DispatchMessageA(&msg
);
453 ok_sequence(sequences
, PARENT_SEQ_INDEX
, SetWindowThemeSeq
, "SetWindowTheme parent", FALSE
);
454 ok_sequence(sequences
, CHILD_SEQ_INDEX
, EmptySeq
, "SetWindowTheme child", FALSE
);
456 UnregisterClassA("TestSetWindowThemeParentClass", GetModuleHandleA(0));
457 UnregisterClassA("TestSetWindowThemeChildClass", GetModuleHandleA(0));
459 /* Only do the bare minimum to get a valid hwnd */
460 hWnd
= CreateWindowExA(0, "button", "test", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
461 ok(hWnd
!= NULL
, "Failed to create a test window.\n");
463 hRes
= SetWindowTheme(hWnd
, NULL
, NULL
);
464 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
468 hTheme
= OpenThemeData(hWnd
, L
"Button");
469 ok(!!hTheme
, "OpenThemeData failed.\n");
470 CloseThemeData(hTheme
);
472 hRes
= SetWindowTheme(hWnd
, L
"deadbeef", NULL
);
473 ok(hRes
== S_OK
, "Expected S_OK, got 0x%08lx.\n", hRes
);
475 hTheme
= OpenThemeData(hWnd
, L
"Button");
476 ok(!!hTheme
, "OpenThemeData failed.\n");
477 CloseThemeData(hTheme
);
481 skip("No active theme, skipping rest of SetWindowTheme tests.\n");
487 static void test_OpenThemeData(void)
489 HTHEME hTheme
, hTheme2
;
495 const WCHAR szInvalidClassList
[] = L
"DEADBEEF";
496 const WCHAR szButtonClassList
[] = L
"Button";
497 const WCHAR szButtonClassList2
[] = L
"bUtToN";
498 const WCHAR szClassList
[] = L
"Button;ListBox";
500 bThemeActive
= IsThemeActive();
503 SetLastError(0xdeadbeef);
504 hTheme
= OpenThemeData(NULL
, NULL
);
505 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
506 ok( GetLastError() == E_POINTER
,
507 "Expected GLE() to be E_POINTER, got 0x%08lx\n",
510 /* A NULL hWnd and an invalid classlist */
511 SetLastError(0xdeadbeef);
512 hTheme
= OpenThemeData(NULL
, szInvalidClassList
);
513 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
514 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
515 E_PROP_ID_UNSUPPORTED
, GetLastError() );
517 SetLastError(0xdeadbeef);
518 hTheme
= OpenThemeData(NULL
, szClassList
);
521 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
522 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
526 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
527 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
528 E_PROP_ID_UNSUPPORTED
, GetLastError() );
531 /* Only do the bare minimum to get a valid hdc */
532 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
535 SetLastError(0xdeadbeef);
536 hTheme
= OpenThemeData(hWnd
, NULL
);
537 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
538 ok( GetLastError() == E_POINTER
,
539 "Expected GLE() to be E_POINTER, got 0x%08lx\n",
542 SetLastError(0xdeadbeef);
543 hTheme
= OpenThemeData(hWnd
, szInvalidClassList
);
544 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
545 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
546 E_PROP_ID_UNSUPPORTED
, GetLastError() );
550 SetLastError(0xdeadbeef);
551 hTheme
= OpenThemeData(hWnd
, szButtonClassList
);
552 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
553 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
554 E_PROP_ID_UNSUPPORTED
, GetLastError() );
555 skip("No active theme, skipping rest of OpenThemeData tests\n");
559 /* Only do the next checks if we have an active theme */
561 SetLastError(0xdeadbeef);
562 hTheme
= OpenThemeData(hWnd
, L
"dead::beef;explorer::treeview");
563 ok(!hTheme
, "OpenThemeData() should fail\n");
564 ok(GetLastError() == E_PROP_ID_UNSUPPORTED
, "Got unexpected %#lx.\n", GetLastError());
566 SetLastError(0xdeadbeef);
567 hTheme
= OpenThemeData(hWnd
, L
"explorer::treeview");
569 ok(hTheme
!= NULL
, "OpenThemeData() failed\n");
571 ok(GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError());
572 CloseThemeData(hTheme
);
574 SetLastError(0xdeadbeef);
575 hTheme
= OpenThemeData(hWnd
, L
"deadbeef::treeview;dead::beef");
577 ok(hTheme
!= NULL
, "OpenThemeData() failed\n");
579 ok(GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError());
580 CloseThemeData(hTheme
);
582 SetLastError(0xdeadbeef);
583 hTheme
= OpenThemeData(hWnd
, szButtonClassList
);
584 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
585 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
586 CloseThemeData(hTheme
);
588 /* Test with bUtToN instead of Button */
589 SetLastError(0xdeadbeef);
590 hTheme
= OpenThemeData(hWnd
, szButtonClassList2
);
591 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
592 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
593 CloseThemeData(hTheme
);
595 SetLastError(0xdeadbeef);
596 hTheme
= OpenThemeData(hWnd
, szClassList
);
597 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
598 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
600 /* GetWindowTheme should return the last handle opened by OpenThemeData */
601 SetLastError(0xdeadbeef);
602 hTheme2
= GetWindowTheme(hWnd
);
603 ok( hTheme
== hTheme2
, "Expected the same HTHEME handle (%p<->%p)\n",
605 ok( GetLastError() == 0xdeadbeef,
606 "Expected 0xdeadbeef, got 0x%08lx\n",
609 SetLastError(0xdeadbeef);
610 bTPDefined
= IsThemePartDefined(hTheme
, 0, 0);
612 ok( bTPDefined
== FALSE
, "Expected FALSE\n" );
613 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
615 hRes
= CloseThemeData(hTheme
);
616 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
618 /* Close a second time */
619 hRes
= CloseThemeData(hTheme
);
620 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
622 /* See if closing makes a difference for GetWindowTheme */
623 SetLastError(0xdeadbeef);
625 hTheme2
= GetWindowTheme(hWnd
);
626 ok( hTheme
== hTheme2
, "Expected the same HTHEME handle (%p<->%p)\n",
628 ok( GetLastError() == 0xdeadbeef,
629 "Expected 0xdeadbeef, got 0x%08lx\n",
635 static void test_OpenThemeDataEx(void)
641 const WCHAR szInvalidClassList
[] = L
"DEADBEEF";
642 const WCHAR szButtonClassList
[] = L
"Button";
643 const WCHAR szButtonClassList2
[] = L
"bUtToN";
644 const WCHAR szClassList
[] = L
"Button;ListBox";
646 if (!pOpenThemeDataEx
)
648 win_skip("OpenThemeDataEx not available\n");
652 bThemeActive
= IsThemeActive();
655 SetLastError(0xdeadbeef);
656 hTheme
= pOpenThemeDataEx(NULL
, NULL
, 0);
657 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
658 ok( GetLastError() == E_POINTER
,
659 "Expected GLE() to be E_POINTER, got 0x%08lx\n",
662 /* A NULL hWnd and an invalid classlist without flags */
663 SetLastError(0xdeadbeef);
664 hTheme
= pOpenThemeDataEx(NULL
, szInvalidClassList
, 0);
665 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
666 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
667 E_PROP_ID_UNSUPPORTED
, GetLastError() );
669 SetLastError(0xdeadbeef);
670 hTheme
= pOpenThemeDataEx(NULL
, szClassList
, 0);
673 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
674 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
678 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
679 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
680 E_PROP_ID_UNSUPPORTED
, GetLastError() );
683 /* Only do the bare minimum to get a valid hdc */
684 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
687 SetLastError(0xdeadbeef);
688 hTheme
= pOpenThemeDataEx(hWnd
, NULL
, 0);
689 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
690 ok( GetLastError() == E_POINTER
,
691 "Expected GLE() to be E_POINTER, got 0x%08lx\n",
694 SetLastError(0xdeadbeef);
695 hTheme
= pOpenThemeDataEx(hWnd
, szInvalidClassList
, 0);
696 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
697 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
698 E_PROP_ID_UNSUPPORTED
, GetLastError() );
702 SetLastError(0xdeadbeef);
703 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0);
704 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
705 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08lx, got 0x%08lx\n",
706 E_PROP_ID_UNSUPPORTED
, GetLastError() );
707 skip("No active theme, skipping rest of OpenThemeDataEx tests\n");
711 /* Only do the next checks if we have an active theme */
713 SetLastError(0xdeadbeef);
714 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0);
715 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
716 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
718 SetLastError(0xdeadbeef);
719 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, OTD_FORCE_RECT_SIZING
);
720 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
721 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
723 SetLastError(0xdeadbeef);
724 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, OTD_NONCLIENT
);
725 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
726 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
728 SetLastError(0xdeadbeef);
729 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0x3);
730 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
731 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
733 /* Test with bUtToN instead of Button */
734 SetLastError(0xdeadbeef);
735 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList2
, 0);
736 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
737 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
739 SetLastError(0xdeadbeef);
740 hTheme
= pOpenThemeDataEx(hWnd
, szClassList
, 0);
741 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
742 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08lx\n", GetLastError() );
747 static void test_OpenThemeDataForDpi(void)
749 BOOL is_theme_active
;
752 if (!pOpenThemeDataForDpi
)
754 win_skip("OpenThemeDataForDpi is unavailable.\n");
758 is_theme_active
= IsThemeActive();
759 SetLastError(0xdeadbeef);
760 htheme
= pOpenThemeDataForDpi(NULL
, WC_BUTTONW
, 96);
763 ok(!!htheme
, "Got a NULL handle.\n");
764 ok(GetLastError() == NO_ERROR
, "Expected error %u, got %lu.\n", NO_ERROR
, GetLastError());
765 CloseThemeData(htheme
);
769 ok(!htheme
, "Got a non-NULL handle.\n");
770 ok(GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected error %lu, got %lu.\n",
771 E_PROP_ID_UNSUPPORTED
, GetLastError());
775 static void test_GetCurrentThemeName(void)
779 WCHAR currentTheme
[MAX_PATH
];
780 WCHAR currentColor
[MAX_PATH
];
781 WCHAR currentSize
[MAX_PATH
];
783 bThemeActive
= IsThemeActive();
786 hRes
= GetCurrentThemeName(NULL
, 0, NULL
, 0, NULL
, 0);
788 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
790 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
792 /* Number of characters given is 0 */
793 hRes
= GetCurrentThemeName(currentTheme
, 0, NULL
, 0, NULL
, 0);
795 ok( hRes
== S_OK
|| broken(hRes
== E_FAIL
/* WinXP SP1 */), "Expected S_OK, got 0x%08lx\n", hRes
);
797 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
799 hRes
= GetCurrentThemeName(currentTheme
, 2, NULL
, 0, NULL
, 0);
802 ok(hRes
== E_NOT_SUFFICIENT_BUFFER
||
803 broken(hRes
== E_FAIL
/* WinXP SP1 */),
804 "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08lx\n", hRes
);
806 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
808 /* The same is true if the number of characters is too small for Color and/or Size */
809 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
, 2,
810 currentSize
, ARRAY_SIZE(currentSize
));
813 ok(hRes
== E_NOT_SUFFICIENT_BUFFER
||
814 broken(hRes
== E_FAIL
/* WinXP SP1 */),
815 "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08lx\n", hRes
);
817 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
819 /* Given number of characters is correct */
820 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), NULL
, 0, NULL
, 0);
822 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
824 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
826 /* Given number of characters for the theme name is too large */
827 hRes
= GetCurrentThemeName(currentTheme
, sizeof(currentTheme
), NULL
, 0, NULL
, 0);
829 ok( hRes
== E_POINTER
|| hRes
== S_OK
, "Expected E_POINTER or S_OK, got 0x%08lx\n", hRes
);
831 ok( hRes
== E_PROP_ID_UNSUPPORTED
||
832 hRes
== E_POINTER
, /* win2k3 */
833 "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
835 /* The too large case is only for the theme name, not for color name or size name */
836 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
837 sizeof(currentTheme
), currentSize
, ARRAY_SIZE(currentSize
));
839 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
841 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
843 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
844 ARRAY_SIZE(currentTheme
), currentSize
, sizeof(currentSize
));
846 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
848 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
851 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
852 ARRAY_SIZE(currentColor
), currentSize
, ARRAY_SIZE(currentSize
));
854 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08lx\n", hRes
);
856 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08lx\n", hRes
);
859 static void test_CloseThemeData(void)
863 hRes
= CloseThemeData(NULL
);
864 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08lx\n", hRes
);
865 hRes
= CloseThemeData(INVALID_HANDLE_VALUE
);
866 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08lx\n", hRes
);
867 hRes
= CloseThemeData((HTHEME
)0xdeadbeef);
868 ok(hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08lx\n", hRes
);
871 static void test_buffer_dc_props(HDC hdc
, const RECT
*rect
)
873 static const XFORM ident
= { 1.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
};
879 ret
= GetWorldTransform(hdc
, &xform
);
880 ok(ret
, "Failed to get world transform\n");
881 ok(!memcmp(&xform
, &ident
, sizeof(xform
)), "Unexpected world transform\n");
883 ret
= GetViewportOrgEx(hdc
, &org
);
884 ok(ret
, "Failed to get vport origin\n");
885 ok(org
.x
== 0 && org
.y
== 0, "Unexpected vport origin\n");
887 ret
= GetWindowOrgEx(hdc
, &org
);
888 ok(ret
, "Failed to get vport origin\n");
889 ok(org
.x
== rect
->left
&& org
.y
== rect
->top
, "Unexpected window origin\n");
891 ret
= GetClipBox(hdc
, &box
);
892 ok(ret
, "Failed to get clip box\n");
893 ok(box
.left
== rect
->left
&& box
.top
== rect
->top
, "Unexpected clip box\n");
895 ok(GetGraphicsMode(hdc
) == GM_COMPATIBLE
, "wrong graphics mode\n");
898 static void test_buffered_paint(void)
900 HDC target
, src
, hdc
, screen_dc
;
901 BP_PAINTPARAMS params
= { 0 };
902 BP_BUFFERFORMAT format
;
910 if (!pBeginBufferedPaint
)
912 win_skip("Buffered painting API is not supported.\n");
916 buffer
= pBeginBufferedPaint(NULL
, NULL
, BPBF_COMPATIBLEBITMAP
,
918 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
920 target
= CreateCompatibleDC(0);
921 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
923 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
925 params
.cbSize
= sizeof(params
);
926 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
928 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
930 src
= (void *)0xdeadbeef;
931 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
933 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
934 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
936 /* target rect is mandatory */
938 src
= (void *)0xdeadbeef;
939 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
941 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
942 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
944 /* inverted rectangle */
945 SetRect(&rect
, 10, 0, 5, 5);
946 src
= (void *)0xdeadbeef;
947 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
949 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
950 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
952 SetRect(&rect
, 0, 10, 5, 0);
953 src
= (void *)0xdeadbeef;
954 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
956 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
957 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
959 /* valid rectangle, no target dc */
960 SetRect(&rect
, 0, 0, 5, 5);
961 src
= (void *)0xdeadbeef;
962 buffer
= pBeginBufferedPaint(NULL
, &rect
, BPBF_COMPATIBLEBITMAP
,
964 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
965 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
967 SetRect(&rect
, 0, 0, 5, 5);
969 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
971 ok(buffer
!= NULL
, "Unexpected buffer %p\n", buffer
);
972 ok(src
!= NULL
, "Expected buffered dc\n");
973 hr
= pEndBufferedPaint(buffer
, FALSE
);
974 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
976 SetRect(&rect
, 0, 0, 5, 5);
977 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
979 ok(buffer
!= NULL
, "Unexpected buffer %p\n", buffer
);
982 hr
= pBufferedPaintClear(NULL
, NULL
);
984 ok(hr
== E_FAIL
, "Unexpected return code %#lx\n", hr
);
986 hr
= pBufferedPaintClear(buffer
, NULL
);
988 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
990 /* access buffer attributes */
991 hdc
= pGetBufferedPaintDC(buffer
);
992 ok(hdc
== src
, "Unexpected hdc, %p, buffered dc %p\n", hdc
, src
);
994 hdc
= pGetBufferedPaintTargetDC(buffer
);
995 ok(hdc
== target
, "Unexpected target hdc %p, original %p\n", hdc
, target
);
997 hr
= pGetBufferedPaintTargetRect(NULL
, NULL
);
998 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1000 hr
= pGetBufferedPaintTargetRect(buffer
, NULL
);
1001 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1003 hr
= pGetBufferedPaintTargetRect(NULL
, &rect2
);
1004 ok(hr
== E_FAIL
, "Unexpected return code %#lx\n", hr
);
1006 SetRectEmpty(&rect2
);
1007 hr
= pGetBufferedPaintTargetRect(buffer
, &rect2
);
1008 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1009 ok(EqualRect(&rect
, &rect2
), "Wrong target rect\n");
1011 hr
= pEndBufferedPaint(buffer
, FALSE
);
1012 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1014 /* invalid buffer handle */
1015 hr
= pEndBufferedPaint(NULL
, FALSE
);
1016 ok(hr
== E_INVALIDARG
, "Unexpected return code %#lx\n", hr
);
1018 hdc
= pGetBufferedPaintDC(NULL
);
1019 ok(hdc
== NULL
, "Unexpected hdc %p\n", hdc
);
1021 hdc
= pGetBufferedPaintTargetDC(NULL
);
1022 ok(hdc
== NULL
, "Unexpected target hdc %p\n", hdc
);
1024 hr
= pGetBufferedPaintTargetRect(NULL
, &rect2
);
1025 ok(hr
== E_FAIL
, "Unexpected return code %#lx\n", hr
);
1027 hr
= pGetBufferedPaintTargetRect(NULL
, NULL
);
1028 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1030 bits
= (void *)0xdeadbeef;
1032 hr
= pGetBufferedPaintBits(NULL
, &bits
, &row
);
1033 ok(hr
== E_FAIL
, "Unexpected return code %#lx\n", hr
);
1034 ok(row
== 10, "Unexpected row count %d\n", row
);
1035 ok(bits
== (void *)0xdeadbeef, "Unexpected data pointer %p\n", bits
);
1037 hr
= pGetBufferedPaintBits(NULL
, NULL
, NULL
);
1038 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1040 hr
= pGetBufferedPaintBits(NULL
, &bits
, NULL
);
1041 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1043 hr
= pGetBufferedPaintBits(NULL
, NULL
, &row
);
1044 ok(hr
== E_POINTER
, "Unexpected return code %#lx\n", hr
);
1046 screen_dc
= GetDC(0);
1048 hdc
= CreateCompatibleDC(screen_dc
);
1049 ok(hdc
!= NULL
, "Failed to create a DC\n");
1050 hbm
= CreateCompatibleBitmap(screen_dc
, 64, 64);
1051 ok(hbm
!= NULL
, "Failed to create a bitmap\n");
1052 SelectObject(hdc
, hbm
);
1054 ReleaseDC(0, screen_dc
);
1056 SetRect(&rect
, 1, 2, 34, 56);
1058 buffer
= pBeginBufferedPaint(hdc
, &rect
, BPBF_COMPATIBLEBITMAP
, NULL
, &src
);
1059 test_buffer_dc_props(src
, &rect
);
1060 hr
= pEndBufferedPaint(buffer
, FALSE
);
1061 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1066 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
, NULL
, &src
);
1067 test_buffer_dc_props(src
, &rect
);
1068 hr
= pEndBufferedPaint(buffer
, FALSE
);
1069 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1071 /* access buffer bits */
1072 for (format
= BPBF_COMPATIBLEBITMAP
; format
<= BPBF_TOPDOWNMONODIB
; format
++)
1074 buffer
= pBeginBufferedPaint(target
, &rect
, format
, ¶ms
, &src
);
1076 /* only works for DIB buffers */
1079 hr
= pGetBufferedPaintBits(buffer
, &bits
, &row
);
1080 if (format
== BPBF_COMPATIBLEBITMAP
)
1081 ok(hr
== E_FAIL
, "Unexpected return code %#lx\n", hr
);
1084 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1085 ok(bits
!= NULL
, "Bitmap bits %p\n", bits
);
1086 ok(row
>= (rect
.right
- rect
.left
), "format %d: bitmap width %d\n", format
, row
);
1089 hr
= pEndBufferedPaint(buffer
, FALSE
);
1090 ok(hr
== S_OK
, "Unexpected return code %#lx\n", hr
);
1096 static void test_GetThemePartSize(void)
1098 static const DWORD enabled
= 1;
1099 int old_dpi
, current_dpi
, system_dpi
, target_dpi
, min_dpi
;
1100 DPI_AWARENESS_CONTEXT old_context
;
1101 int i
, expected
, stretch_mark
= 0;
1102 HTHEME htheme
= NULL
;
1109 if (!pSetThreadDpiAwarenessContext
|| !pGetDpiForSystem
)
1111 win_skip("SetThreadDpiAwarenessContext() or GetDpiForSystem() is unavailable.\n");
1115 /* Set IgnorePerProcessSystemDPIToast to 1 to disable "fix blurry apps popup" on Windows 10,
1116 * which may interfere other tests because it steals focus */
1117 RegOpenKeyA(HKEY_CURRENT_USER
, "Control Panel\\Desktop", &key
);
1118 RegSetValueExA(key
, "IgnorePerProcessSystemDPIToast", 0, REG_DWORD
, (const BYTE
*)&enabled
,
1121 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
);
1122 current_dpi
= get_primary_monitor_effective_dpi();
1123 old_dpi
= current_dpi
;
1124 system_dpi
= pGetDpiForSystem();
1125 target_dpi
= system_dpi
;
1127 hwnd
= CreateWindowA("Button", "Test", WS_POPUP
, 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
1130 /* Test in the current DPI */
1131 /* Test that OpenThemeData() with NULL window handle uses system DPI even if DPI changes while running */
1132 htheme
= OpenThemeData(NULL
, WC_BUTTONW
);
1135 skip("Theming is inactive.\n");
1139 /* TMT_TRUESIZESTRETCHMARK is present, choose the next minimum DPI */
1140 hr
= GetThemeInt(htheme
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, TMT_TRUESIZESTRETCHMARK
, &stretch_mark
);
1141 if (SUCCEEDED(hr
) && stretch_mark
> 0)
1143 for (i
= 7; i
>= 1; --i
)
1145 hr
= GetThemeInt(htheme
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
,
1146 i
<= 5 ? TMT_MINDPI1
+ i
- 1 : TMT_MINDPI6
+ i
- 6, &min_dpi
);
1147 if (SUCCEEDED(hr
) && min_dpi
<= system_dpi
)
1149 target_dpi
= min_dpi
;
1154 expected
= MulDiv(13, target_dpi
, 96);
1156 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1157 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1158 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1159 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1160 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1161 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1162 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1163 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1164 CloseThemeData(htheme
);
1166 /* Test in 192 DPI */
1167 /* DPI needs to be 50% larger than 96 to avoid the effect of TrueSizeStretchMark */
1168 if (current_dpi
!= 192 && !set_primary_monitor_effective_dpi(192))
1170 skip("Failed to set primary monitor dpi to 192.\n");
1174 /* Test that OpenThemeData() with NULL window handle uses system DPI even if DPI changes while running */
1175 expected
= MulDiv(13, target_dpi
, 96);
1176 htheme
= OpenThemeData(NULL
, WC_BUTTONW
);
1177 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1178 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1179 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1180 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1181 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1182 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1183 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1184 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1185 CloseThemeData(htheme
);
1187 /* Test that OpenThemeData() with a window handle use window DPI */
1189 htheme
= OpenThemeData(hwnd
, WC_BUTTONW
);
1190 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1191 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1192 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1193 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1194 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1195 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1196 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1197 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1199 /* Test in 96 DPI */
1200 if (!set_primary_monitor_effective_dpi(96))
1202 skip("Failed to set primary monitor dpi to 96.\n");
1203 CloseThemeData(htheme
);
1207 /* Test that theme part size doesn't change even if DPI is changed */
1209 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1210 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1211 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1212 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1213 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1214 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1215 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1216 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1218 /* Test that theme part size changes after DPI is changed and theme handle is reopened.
1219 * If DPI awareness context is not DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, theme part size
1220 * still doesn't change, even after the theme handle is reopened. */
1221 CloseThemeData(htheme
);
1222 htheme
= OpenThemeData(hwnd
, WC_BUTTONW
);
1224 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1225 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1226 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1227 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1228 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1229 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1230 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1231 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1232 CloseThemeData(htheme
);
1234 /* Test that OpenThemeData() with NULL window handle use system DPI even if DPI changes while running */
1235 expected
= MulDiv(13, target_dpi
, 96);
1236 htheme
= OpenThemeData(NULL
, WC_BUTTONW
);
1237 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1238 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1239 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1240 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1241 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1242 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
1243 ok(compare_uint(size
.cx
, expected
, 1) && compare_uint(size
.cy
, expected
, 1),
1244 "Got unexpected size %ldx%ld.\n", size
.cx
, size
.cy
);
1245 CloseThemeData(htheme
);
1249 ReleaseDC(hwnd
, hdc
);
1251 DestroyWindow(hwnd
);
1252 if (get_primary_monitor_effective_dpi() != old_dpi
)
1253 set_primary_monitor_effective_dpi(old_dpi
);
1256 RegDeleteValueA(key
, "IgnorePerProcessSystemDPIToast");
1259 pSetThreadDpiAwarenessContext(old_context
);
1262 static void test_EnableTheming(void)
1264 WCHAR old_color_string
[13], new_color_string
[13], color_string
[13];
1265 BOOL old_gradient_caption
, new_gradient_caption
, gradient_caption
;
1266 BOOL old_flat_menu
, new_flat_menu
, flat_menu
;
1267 LOGFONTW old_logfont
, new_logfont
, logfont
;
1268 NONCLIENTMETRICSW old_ncm
, new_ncm
, ncm
;
1269 DPI_AWARENESS_CONTEXT old_context
= 0;
1270 COLORREF old_color
, new_color
;
1271 BOOL is_theme_active
, ret
;
1277 if (IsThemeActive())
1279 hr
= EnableTheming(TRUE
);
1280 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1281 ok(IsThemeActive(), "Expected theming active.\n");
1283 /* Only run in interactive mode because once theming is disabled, it can't be turned back on
1284 * via EnableTheming() */
1285 if (winetest_interactive
)
1287 if (pSetThreadDpiAwarenessContext
)
1289 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
1291 else if (get_primary_monitor_effective_dpi() != 96)
1293 skip("DPI isn't 96, skipping.\n");
1297 /* Read current system metrics */
1298 old_color
= GetSysColor(COLOR_SCROLLBAR
);
1299 swprintf(old_color_string
, ARRAY_SIZE(old_color_string
), L
"%d %d %d",
1300 GetRValue(old_color
), GetGValue(old_color
), GetBValue(old_color
));
1302 memset(&old_ncm
, 0, sizeof(old_ncm
));
1303 old_ncm
.cbSize
= FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
);
1304 ret
= SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(old_ncm
), &old_ncm
, 0);
1305 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1307 memset(&old_logfont
, 0, sizeof(old_logfont
));
1308 ret
= SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, sizeof(old_logfont
), &old_logfont
, 0);
1309 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1310 ret
= SystemParametersInfoW(SPI_GETFLATMENU
, 0, &old_flat_menu
, 0);
1311 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1312 ret
= SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS
, 0, &old_gradient_caption
, 0);
1313 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1315 /* Write new system metrics to the registry */
1316 new_color
= ~old_color
;
1317 new_flat_menu
= !old_flat_menu
;
1318 new_gradient_caption
= !old_gradient_caption
;
1319 memcpy(&new_ncm
, &old_ncm
, sizeof(new_ncm
));
1320 new_ncm
.iScrollWidth
+= 5;
1321 memcpy(&new_logfont
, &old_logfont
, sizeof(new_logfont
));
1322 new_logfont
.lfWidth
+= 5;
1324 ls
= RegOpenKeyExW(HKEY_CURRENT_USER
, L
"Control Panel\\Colors", 0, KEY_ALL_ACCESS
,
1326 ok(!ls
, "RegOpenKeyExW failed, ls %#lx.\n", ls
);
1328 length
= swprintf(new_color_string
, ARRAY_SIZE(new_color_string
), L
"%d %d %d",
1329 GetRValue(new_color
), GetGValue(new_color
), GetBValue(new_color
));
1330 ls
= RegSetValueExW(hkey
, L
"Scrollbar", 0, REG_SZ
, (BYTE
*)new_color_string
,
1331 (length
+ 1) * sizeof(WCHAR
));
1332 ok(!ls
, "RegSetValueExW failed, ls %#lx.\n", ls
);
1334 ret
= SystemParametersInfoW(SPI_SETNONCLIENTMETRICS
, sizeof(new_ncm
), &new_ncm
,
1335 SPIF_UPDATEINIFILE
);
1336 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1337 ret
= SystemParametersInfoW(SPI_SETICONTITLELOGFONT
, sizeof(new_logfont
), &new_logfont
,
1338 SPIF_UPDATEINIFILE
);
1339 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1340 ret
= SystemParametersInfoW(SPI_SETFLATMENU
, 0, (void *)(INT_PTR
)new_flat_menu
,
1341 SPIF_UPDATEINIFILE
);
1342 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1343 ret
= SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS
, 0,
1344 (void *)(INT_PTR
)new_gradient_caption
, SPIF_UPDATEINIFILE
);
1345 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1347 /* Change theming state */
1348 hr
= EnableTheming(FALSE
);
1349 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1350 is_theme_active
= IsThemeActive();
1351 ok(!is_theme_active
|| broken(is_theme_active
), /* Win8+ can no longer disable theming */
1352 "Expected theming inactive.\n");
1354 /* Test that system metrics are unchanged */
1355 size
= sizeof(color_string
);
1356 ls
= RegQueryValueExW(hkey
, L
"Scrollbar", NULL
, NULL
, (BYTE
*)color_string
, &size
);
1357 ok(!ls
, "RegQueryValueExW failed, ls %#lx.\n", ls
);
1358 ok(!lstrcmpW(color_string
, new_color_string
), "Expected %s, got %s.\n",
1359 wine_dbgstr_w(new_color_string
), wine_dbgstr_w(color_string
));
1361 ret
= SystemParametersInfoW(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1362 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1363 ok(flat_menu
== new_flat_menu
, "Expected %d, got %d.\n", new_flat_menu
, flat_menu
);
1364 ret
= SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS
, 0, &gradient_caption
, 0);
1365 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1366 ok(gradient_caption
== new_gradient_caption
, "Expected %d, got %d.\n",
1367 new_gradient_caption
, gradient_caption
);
1369 memset(&ncm
, 0, sizeof(ncm
));
1370 ncm
.cbSize
= FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
);
1371 ret
= SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0);
1372 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1373 ok(!memcmp(&ncm
, &new_ncm
, sizeof(ncm
)), "Expected non-client metrics unchanged.\n");
1375 memset(&logfont
, 0, sizeof(logfont
));
1376 ret
= SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, sizeof(logfont
), &logfont
, 0);
1377 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1378 ok(!memcmp(&logfont
, &new_logfont
, sizeof(logfont
)),
1379 "Expected icon title font unchanged.\n");
1381 /* Test that theming cannot be turned on via EnableTheming() */
1382 hr
= EnableTheming(TRUE
);
1383 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1384 is_theme_active
= IsThemeActive();
1385 ok(!is_theme_active
|| broken(is_theme_active
), /* Win8+ can no longer disable theming */
1386 "Expected theming inactive.\n");
1388 /* Restore system metrics */
1389 ls
= RegSetValueExW(hkey
, L
"Scrollbar", 0, REG_SZ
, (BYTE
*)old_color_string
,
1390 (lstrlenW(old_color_string
) + 1) * sizeof(WCHAR
));
1391 ok(!ls
, "RegSetValueExW failed, ls %#lx.\n", ls
);
1392 ret
= SystemParametersInfoW(SPI_SETFLATMENU
, 0, (void *)(INT_PTR
)old_flat_menu
,
1393 SPIF_UPDATEINIFILE
);
1394 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1395 ret
= SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS
, 0,
1396 (void *)(INT_PTR
)old_gradient_caption
, SPIF_UPDATEINIFILE
);
1397 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1398 ret
= SystemParametersInfoW(SPI_SETNONCLIENTMETRICS
, sizeof(old_ncm
), &old_ncm
,
1399 SPIF_UPDATEINIFILE
);
1400 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1401 ret
= SystemParametersInfoW(SPI_SETICONTITLELOGFONT
, sizeof(old_logfont
), &old_logfont
,
1402 SPIF_UPDATEINIFILE
);
1403 ok(ret
, "SystemParametersInfoW failed, error %lu.\n", GetLastError());
1406 if (pSetThreadDpiAwarenessContext
)
1407 pSetThreadDpiAwarenessContext(old_context
);
1412 hr
= EnableTheming(FALSE
);
1413 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1414 ok(!IsThemeActive(), "Expected theming inactive.\n");
1416 hr
= EnableTheming(TRUE
);
1417 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1418 ok(!IsThemeActive(), "Expected theming inactive.\n");
1420 hr
= EnableTheming(FALSE
);
1421 ok(hr
== S_OK
, "EnableTheming failed, hr %#lx.\n", hr
);
1422 ok(!IsThemeActive(), "Expected theming inactive.\n");
1426 static void test_GetThemeIntList(void)
1433 if (!pGetThemeIntList
)
1435 win_skip("GetThemeIntList is unavailable.\n");
1439 hwnd
= CreateWindowA("static", "", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
1440 theme
= OpenThemeData(hwnd
, L
"Button");
1443 skip("Theming is not active.\n");
1444 DestroyWindow(hwnd
);
1448 /* Check properties */
1449 /* TMT_TRANSITIONDURATIONS is a vista+ property */
1450 hr
= pGetThemeIntList(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1451 if (LOBYTE(LOWORD(GetVersion())) < 6)
1452 ok(hr
== E_PROP_ID_UNSUPPORTED
, "Expected %#lx, got %#lx.\n", E_PROP_ID_UNSUPPORTED
, hr
);
1454 ok(hr
== S_OK
, "GetThemeIntList failed, hr %#lx.\n", hr
);
1456 CloseThemeData(theme
);
1457 DestroyWindow(hwnd
);
1460 static void test_GetThemeTransitionDuration(void)
1462 int from_state
, to_state
, expected
;
1469 if (!pGetThemeTransitionDuration
|| !pGetThemeIntList
)
1471 win_skip("GetThemeTransitionDuration or GetThemeIntList is unavailable.\n");
1475 hwnd
= CreateWindowA("static", "", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
1476 theme
= OpenThemeData(hwnd
, L
"Button");
1479 skip("Theming is not active.\n");
1480 DestroyWindow(hwnd
);
1484 /* Invalid parameter tests */
1485 duration
= 0xdeadbeef;
1486 hr
= pGetThemeTransitionDuration(NULL
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1487 TMT_TRANSITIONDURATIONS
, &duration
);
1488 ok(hr
== E_HANDLE
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1489 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#lx.\n", 0xdeadbeef, duration
);
1491 /* Crash on Wine. HTHEME is not a pointer that can be directly referenced. */
1492 if (strcmp(winetest_platform
, "wine"))
1494 duration
= 0xdeadbeef;
1495 hr
= pGetThemeTransitionDuration((HTHEME
)0xdeadbeef, BP_PUSHBUTTON
, PBS_NORMAL
,
1496 PBS_DEFAULTED_ANIMATING
, TMT_TRANSITIONDURATIONS
, &duration
);
1498 ok(hr
== E_HANDLE
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1499 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#lx.\n", 0xdeadbeef, duration
);
1502 duration
= 0xdeadbeef;
1503 hr
= pGetThemeTransitionDuration(theme
, 0xdeadbeef, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1504 TMT_TRANSITIONDURATIONS
, &duration
);
1505 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1506 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1508 duration
= 0xdeadbeef;
1509 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
- 1, PBS_DEFAULTED_ANIMATING
,
1510 TMT_TRANSITIONDURATIONS
, &duration
);
1511 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1512 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#lx.\n", 0xdeadbeef, duration
);
1514 duration
= 0xdeadbeef;
1515 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_DEFAULTED_ANIMATING
+ 1,
1516 PBS_DEFAULTED_ANIMATING
, TMT_TRANSITIONDURATIONS
, &duration
);
1517 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1518 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1520 duration
= 0xdeadbeef;
1521 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_NORMAL
- 1,
1522 TMT_TRANSITIONDURATIONS
, &duration
);
1523 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1524 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#lx.\n", 0xdeadbeef, duration
);
1526 duration
= 0xdeadbeef;
1527 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
+ 1,
1528 TMT_TRANSITIONDURATIONS
, &duration
);
1529 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1530 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1532 duration
= 0xdeadbeef;
1533 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1534 TMT_BACKGROUND
, &duration
);
1535 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1536 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1538 duration
= 0xdeadbeef;
1539 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1540 0xdeadbeef, &duration
);
1541 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1542 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1544 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1545 TMT_TRANSITIONDURATIONS
, NULL
);
1546 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1548 /* Parts that don't have TMT_TRANSITIONDURATIONS */
1549 hr
= GetThemeIntList(theme
, BP_GROUPBOX
, GBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1550 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeIntList failed, hr %#lx.\n", hr
);
1552 duration
= 0xdeadbeef;
1553 hr
= pGetThemeTransitionDuration(theme
, BP_GROUPBOX
, GBS_NORMAL
, GBS_DISABLED
,
1554 TMT_TRANSITIONDURATIONS
, &duration
);
1555 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1556 ok(duration
== 0, "Expected duration %#x, got %#lx.\n", 0, duration
);
1558 /* Test parsing TMT_TRANSITIONDURATIONS property. TMT_TRANSITIONDURATIONS is a vista+ property */
1559 if (LOBYTE(LOWORD(GetVersion())) < 6)
1562 hr
= pGetThemeIntList(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1563 ok(hr
== S_OK
, "GetThemeIntList failed, hr %#lx.\n", hr
);
1564 /* The first value is the theme part state count. The following are the values from every state
1565 * to every state. So the total value count should be 1 + state ^ 2 */
1566 expected
= PBS_DEFAULTED_ANIMATING
- PBS_NORMAL
+ 1;
1567 ok(intlist
.iValues
[0] == expected
, "Expected the first value %d, got %d.\n", expected
,
1568 intlist
.iValues
[0]);
1569 expected
= 1 + intlist
.iValues
[0] * intlist
.iValues
[0];
1570 ok(intlist
.iValueCount
== expected
, "Expected value count %d, got %d.\n", expected
,
1571 intlist
.iValueCount
);
1574 for (from_state
= PBS_NORMAL
; from_state
<= PBS_DEFAULTED_ANIMATING
; ++from_state
)
1576 for (to_state
= PBS_NORMAL
; to_state
<= PBS_DEFAULTED_ANIMATING
; ++to_state
)
1578 winetest_push_context("from state %d to %d", from_state
, to_state
);
1580 duration
= 0xdeadbeef;
1581 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, from_state
, to_state
,
1582 TMT_TRANSITIONDURATIONS
, &duration
);
1583 ok(hr
== S_OK
, "GetThemeTransitionDuration failed, hr %#lx.\n", hr
);
1584 expected
= intlist
.iValues
[1 + intlist
.iValues
[0] * (from_state
- 1) + (to_state
- 1)];
1585 ok(duration
== expected
, "Expected duration %d, got %ld.\n", expected
, duration
);
1587 winetest_pop_context();
1593 CloseThemeData(theme
);
1594 DestroyWindow(hwnd
);
1597 static const struct message DrawThemeParentBackground_seq
[] =
1599 {WM_ERASEBKGND
, sent
},
1600 {WM_PRINTCLIENT
, sent
| lparam
, 0, PRF_CLIENT
},
1604 static LRESULT WINAPI
test_DrawThemeParentBackground_proc(HWND hwnd
, UINT message
, WPARAM wp
,
1607 static LONG defwndproc_counter
;
1608 struct message msg
= {0};
1615 /* Test that DrawThemeParentBackground() doesn't change brush origins */
1617 case WM_PRINTCLIENT
:
1618 ret
= GetBrushOrgEx((HDC
)wp
, &org
);
1619 ok(ret
, "GetBrushOrgEx failed, error %ld.\n", GetLastError());
1620 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1627 msg
.message
= message
;
1628 msg
.flags
= sent
| wparam
| lparam
;
1629 if (defwndproc_counter
)
1630 msg
.flags
|= defwinproc
;
1633 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
1635 InterlockedIncrement(&defwndproc_counter
);
1636 lr
= DefWindowProcA(hwnd
, message
, wp
, lp
);
1637 InterlockedDecrement(&defwndproc_counter
);
1641 static void test_DrawThemeParentBackground(void)
1651 memset(&cls
, 0, sizeof(cls
));
1652 cls
.hInstance
= GetModuleHandleA(0);
1653 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1654 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
1655 cls
.lpfnWndProc
= test_DrawThemeParentBackground_proc
;
1656 cls
.lpszClassName
= "TestDrawThemeParentBackgroundClass";
1657 RegisterClassA(&cls
);
1659 parent
= CreateWindowA("TestDrawThemeParentBackgroundClass", "parent", WS_POPUP
| WS_VISIBLE
, 0,
1660 0, 100, 100, 0, 0, 0, 0);
1661 ok(parent
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
1662 child
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 1, 2, 50, 50, parent
, 0, 0,
1664 ok(child
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
1666 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1669 ret
= GetBrushOrgEx(hdc
, &org
);
1670 ok(ret
, "GetBrushOrgEx failed, error %ld.\n", GetLastError());
1671 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1673 hr
= DrawThemeParentBackground(child
, hdc
, NULL
);
1674 ok(SUCCEEDED(hr
), "DrawThemeParentBackground failed, hr %#lx.\n", hr
);
1675 ok_sequence(sequences
, PARENT_SEQ_INDEX
, DrawThemeParentBackground_seq
,
1676 "DrawThemeParentBackground parent", FALSE
);
1677 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1679 GetClientRect(child
, &rect
);
1680 hr
= DrawThemeParentBackground(child
, hdc
, &rect
);
1681 ok(SUCCEEDED(hr
), "DrawThemeParentBackground failed, hr %#lx.\n", hr
);
1682 ok_sequence(sequences
, PARENT_SEQ_INDEX
, DrawThemeParentBackground_seq
,
1683 "DrawThemeParentBackground parent", FALSE
);
1684 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1686 ReleaseDC(child
, hdc
);
1687 DestroyWindow(parent
);
1688 UnregisterClassA("TestDrawThemeParentBackgroundClass", GetModuleHandleA(0));
1691 struct test_EnableThemeDialogTexture_param
1693 const CHAR
*class_name
;
1697 static const struct message empty_seq
[] =
1702 static const struct message wm_erasebkgnd_seq
[] =
1704 {WM_ERASEBKGND
, sent
},
1705 {WM_CTLCOLORDLG
, sent
},
1709 static const struct message wm_ctlcolormsgbox_seq
[] =
1711 {WM_CTLCOLORMSGBOX
, sent
},
1715 static const struct message wm_ctlcolorbtn_seq
[] =
1717 {WM_CTLCOLORBTN
, sent
},
1721 static const struct message wm_ctlcolordlg_seq
[] =
1723 {WM_CTLCOLORDLG
, sent
},
1727 static const struct message wm_ctlcolorstatic_seq
[] =
1729 {WM_CTLCOLORSTATIC
, sent
},
1733 static HWND dialog_child
;
1734 static DWORD dialog_init_flag
;
1735 static BOOL handle_WM_ERASEBKGND
;
1736 static BOOL handle_WM_CTLCOLORSTATIC
;
1738 static INT_PTR CALLBACK
test_EnableThemeDialogTexture_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1740 struct test_EnableThemeDialogTexture_param
*param
;
1741 struct message message
= {0};
1743 message
.message
= msg
;
1744 message
.flags
= sent
| wparam
| lparam
;
1745 message
.wParam
= wp
;
1746 message
.lParam
= lp
;
1747 add_message(sequences
, PARENT_SEQ_INDEX
, &message
);
1752 param
= (struct test_EnableThemeDialogTexture_param
*)lp
;
1753 dialog_child
= CreateWindowA(param
->class_name
, "child",
1754 param
->style
| WS_CHILD
| WS_VISIBLE
, 1, 2, 50, 50, hwnd
,
1755 (HMENU
)100, 0, NULL
);
1756 ok(dialog_child
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
1757 if (dialog_init_flag
)
1758 EnableThemeDialogTexture(hwnd
, dialog_init_flag
);
1763 if (!handle_WM_ERASEBKGND
)
1766 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, 0);
1770 case WM_CTLCOLORSTATIC
:
1771 return (INT_PTR
)(handle_WM_CTLCOLORSTATIC
? GetSysColorBrush(COLOR_MENU
) : 0);
1774 DestroyWindow(dialog_child
);
1775 dialog_child
= NULL
;
1783 static void test_EnableThemeDialogTexture(void)
1785 struct test_EnableThemeDialogTexture_param param
;
1786 HWND dialog
, child
, hwnd
, hwnd2
;
1787 int mode
, old_mode
, count
, i
, j
;
1788 COLORREF color
, old_color
;
1789 HBRUSH brush
, brush2
;
1807 DLGTEMPLATE
template;
1813 static const DWORD flags
[] =
1818 ETDT_USEAEROWIZARDTABTEXTURE
,
1820 ETDT_ENABLEAEROWIZARDTAB
,
1823 ETDT_DISABLE
| ETDT_ENABLE
,
1824 ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
1827 static const struct invalid_flag_test
1832 invalid_flag_tests
[] =
1835 {ETDT_DISABLE
| ETDT_ENABLE
, FALSE
},
1836 {ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
, TRUE
},
1837 {ETDT_USETABTEXTURE
| ETDT_USEAEROWIZARDTABTEXTURE
, TRUE
},
1838 {ETDT_VALIDBITS
, FALSE
},
1839 {~ETDT_VALIDBITS
, FALSE
},
1840 {~ETDT_VALIDBITS
| ETDT_DISABLE
, FALSE
}
1843 static const struct class_test
1845 struct test_EnableThemeDialogTexture_param param
;
1846 BOOL texture_enabled
;
1851 {{WC_BUTTONA
, BS_PUSHBUTTON
}, TRUE
},
1852 {{WC_BUTTONA
, BS_DEFPUSHBUTTON
}, TRUE
},
1853 {{WC_BUTTONA
, BS_CHECKBOX
}, TRUE
},
1854 {{WC_BUTTONA
, BS_AUTOCHECKBOX
}, TRUE
},
1855 {{WC_BUTTONA
, BS_RADIOBUTTON
}, TRUE
},
1856 {{WC_BUTTONA
, BS_3STATE
}, TRUE
},
1857 {{WC_BUTTONA
, BS_AUTO3STATE
}, TRUE
},
1858 {{WC_BUTTONA
, BS_GROUPBOX
}, TRUE
},
1859 {{WC_BUTTONA
, BS_USERBUTTON
}, TRUE
},
1860 {{WC_BUTTONA
, BS_AUTORADIOBUTTON
}, TRUE
},
1861 {{WC_BUTTONA
, BS_PUSHBOX
}, TRUE
},
1862 {{WC_BUTTONA
, BS_OWNERDRAW
}, TRUE
},
1863 {{WC_BUTTONA
, BS_SPLITBUTTON
}, TRUE
},
1864 {{WC_BUTTONA
, BS_DEFSPLITBUTTON
}, TRUE
},
1865 {{WC_BUTTONA
, BS_COMMANDLINK
}, TRUE
},
1866 {{WC_BUTTONA
, BS_DEFCOMMANDLINK
}, TRUE
},
1869 {{DATETIMEPICK_CLASSA
}},
1876 {{MONTHCAL_CLASSA
}},
1877 {{WC_NATIVEFONTCTLA
}},
1878 {{WC_PAGESCROLLERA
}},
1879 {{PROGRESS_CLASSA
}},
1880 {{REBARCLASSNAMEA
}},
1881 {{WC_STATICA
, SS_LEFT
}, TRUE
},
1882 {{WC_STATICA
, SS_ICON
}, TRUE
},
1883 {{WC_STATICA
, SS_BLACKRECT
}, TRUE
},
1884 {{WC_STATICA
, SS_OWNERDRAW
}, TRUE
},
1885 {{WC_STATICA
, SS_BITMAP
}, TRUE
},
1886 {{WC_STATICA
, SS_ENHMETAFILE
}, TRUE
},
1887 {{WC_STATICA
, SS_ETCHEDHORZ
}, TRUE
},
1888 {{STATUSCLASSNAMEA
}},
1891 {{TOOLBARCLASSNAMEA
}},
1892 {{TOOLTIPS_CLASSA
}},
1893 {{TRACKBAR_CLASSA
}},
1899 static const struct message_test
1902 const struct message
*msg_seq
;
1906 {WM_ERASEBKGND
, wm_erasebkgnd_seq
},
1907 {WM_CTLCOLORMSGBOX
, wm_ctlcolormsgbox_seq
},
1908 {WM_CTLCOLORBTN
, wm_ctlcolorbtn_seq
},
1909 {WM_CTLCOLORDLG
, wm_ctlcolordlg_seq
},
1910 {WM_CTLCOLORSTATIC
, wm_ctlcolorstatic_seq
},
1913 if (!IsThemeActive())
1915 skip("Theming is inactive.\n");
1919 memset(&cls
, 0, sizeof(cls
));
1920 cls
.lpfnWndProc
= DefWindowProcA
;
1921 cls
.hInstance
= GetModuleHandleA(NULL
);
1922 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1923 cls
.hbrBackground
= GetStockObject(GRAY_BRUSH
);
1924 cls
.lpszClassName
= "TestEnableThemeDialogTextureClass";
1925 RegisterClassA(&cls
);
1927 temp
.template.style
= WS_CHILD
| WS_VISIBLE
;
1928 temp
.template.cx
= 100;
1929 temp
.template.cy
= 100;
1930 param
.class_name
= cls
.lpszClassName
;
1932 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
1933 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
1934 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
1935 child
= GetDlgItem(dialog
, 100);
1936 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
1937 child_hdc
= GetDC(child
);
1939 /* Test that dialog procedure is unchanged */
1940 proc
= GetWindowLongPtrA(dialog
, DWLP_DLGPROC
);
1941 ok(proc
== (ULONG_PTR
)test_EnableThemeDialogTexture_proc
, "Unexpected proc %#Ix.\n", proc
);
1943 /* Test dialog texture is disabled by default. EnableThemeDialogTexture() needs to be called */
1944 ret
= IsThemeDialogTextureEnabled(dialog
);
1945 ok(!ret
, "Expected theme dialog texture disabled.\n");
1946 ok(GetWindowTheme(dialog
) == NULL
, "Expected NULL theme handle.\n");
1948 /* Test ETDT_ENABLE | ETDT_USETABTEXTURE doesn't take effect immediately */
1949 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USETABTEXTURE
);
1950 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
1951 ret
= IsThemeDialogTextureEnabled(dialog
);
1952 ok(ret
, "Expected theme dialog texture enabled.\n");
1954 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1955 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1956 GetSysColorBrush(COLOR_BTNFACE
), brush
);
1957 ret
= GetBrushOrgEx(child_hdc
, &org
);
1958 ok(ret
, "GetBrushOrgEx failed, error %lu.\n", GetLastError());
1959 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1961 /* Test WM_THEMECHANGED doesn't make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
1962 lr
= SendMessageA(dialog
, WM_THEMECHANGED
, 0, 0);
1963 ok(lr
== 0, "WM_THEMECHANGED failed.\n");
1964 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1965 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1966 GetSysColorBrush(COLOR_BTNFACE
), brush
);
1968 /* Test WM_ERASEBKGND make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
1969 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
1970 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
1971 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1972 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected brush changed.\n");
1974 /* Test disabling theme dialog texture should change the brush immediately */
1975 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1976 hr
= EnableThemeDialogTexture(dialog
, ETDT_DISABLE
);
1977 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
1978 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1979 ok(brush2
!= brush
, "Expected a different brush.\n");
1980 ok(brush2
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1981 GetSysColorBrush(COLOR_BTNFACE
), brush2
);
1983 /* Test re-enabling theme dialog texture with ETDT_ENABLE doesn't change the brush */
1984 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1985 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
);
1986 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
1987 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1988 ok(brush2
== brush
, "Expected the same brush.\n");
1989 ok(brush2
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1990 GetSysColorBrush(COLOR_BTNFACE
), brush2
);
1992 /* Test adding ETDT_USETABTEXTURE should change the brush immediately */
1993 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1994 hr
= EnableThemeDialogTexture(dialog
, ETDT_USETABTEXTURE
);
1995 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
1996 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1997 ok(brush2
!= brush
, "Expected a different brush.\n");
1999 /* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush immediately */
2000 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2001 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USEAEROWIZARDTABTEXTURE
);
2002 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2003 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2004 /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
2005 if (LOBYTE(LOWORD(GetVersion())) < 6)
2006 ok(brush2
== brush
, "Expected the same brush.\n");
2008 ok(brush2
!= brush
, "Expected a different brush.\n");
2010 hr
= EnableThemeDialogTexture(dialog
, ETDT_DISABLE
);
2011 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2012 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USETABTEXTURE
);
2013 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2015 /* Test that the dialog procedure should take precedence over DefDlgProc() for WM_CTLCOLORSTATIC */
2016 handle_WM_CTLCOLORSTATIC
= TRUE
;
2017 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2018 ok(brush
== GetSysColorBrush(COLOR_MENU
), "Expected brush %p, got %p.\n",
2019 GetSysColorBrush(COLOR_MENU
), brush
);
2020 handle_WM_CTLCOLORSTATIC
= FALSE
;
2022 /* Test that the dialog procedure should take precedence over DefDlgProc() for WM_ERASEBKGND */
2023 handle_WM_ERASEBKGND
= TRUE
;
2024 lr
= SendMessageW(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
2025 ok(lr
== 0, "Expected 0, got %#Ix.\n", lr
);
2026 handle_WM_ERASEBKGND
= FALSE
;
2028 /* Test that dialog doesn't have theme handle opened for itself */
2029 ok(GetWindowTheme(dialog
) == NULL
, "Expected NULL theme handle.\n");
2031 theme
= OpenThemeData(NULL
, L
"Tab");
2032 ok(theme
!= NULL
, "OpenThemeData failed.\n");
2035 hr
= GetThemePartSize(theme
, NULL
, TABP_BODY
, 0, NULL
, TS_TRUE
, &size
);
2036 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#lx.\n", hr
);
2037 CloseThemeData(theme
);
2039 /* Test which WM_CTLCOLOR* message uses tab background as dialog texture */
2040 for (msg
= WM_CTLCOLORMSGBOX
; msg
<= WM_CTLCOLORSTATIC
; ++msg
)
2042 winetest_push_context("msg %#x", msg
);
2044 /* Test that some WM_CTLCOLOR* messages change brush origin when dialog texture is on */
2045 ret
= SetBrushOrgEx(child_hdc
, 0, 0, NULL
);
2046 ok(ret
, "SetBrushOrgEx failed, error %lu.\n", GetLastError());
2047 SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2048 ret
= GetBrushOrgEx(child_hdc
, &org
);
2049 ok(ret
, "GetBrushOrgEx failed, error %lu.\n", GetLastError());
2050 /* WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX and WM_CTLCOLORSCROLLBAR don't use tab background */
2051 if (msg
== WM_CTLCOLOREDIT
|| msg
== WM_CTLCOLORLISTBOX
|| msg
== WM_CTLCOLORSCROLLBAR
)
2053 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
2054 winetest_pop_context();
2059 ok(org
.x
== -1 && org
.y
== -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org
));
2062 /* Test that some WM_CTLCOLOR* messages change background mode when dialog texture is on */
2063 old_mode
= SetBkMode(child_hdc
, OPAQUE
);
2064 ok(old_mode
!= 0, "SetBkMode failed.\n");
2065 SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2066 mode
= SetBkMode(child_hdc
, old_mode
);
2067 ok(mode
== TRANSPARENT
, "Expected mode %#x, got %#x.\n", TRANSPARENT
, mode
);
2069 /* Test that some WM_CTLCOLOR* messages change background color when dialog texture is on */
2070 old_color
= SetBkColor(child_hdc
, 0xaa5511);
2071 ok(old_color
!= CLR_INVALID
, "SetBkColor failed.\n");
2072 SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2073 color
= SetBkColor(child_hdc
, old_color
);
2074 ok(color
== GetSysColor(COLOR_BTNFACE
), "Expected background color %#lx, got %#lx.\n",
2075 GetSysColor(COLOR_BTNFACE
), color
);
2077 /* Test that the returned brush is a pattern brush created from the tab body */
2078 brush
= (HBRUSH
)SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2079 memset(&log_brush
, 0, sizeof(log_brush
));
2080 count
= GetObjectA(brush
, sizeof(log_brush
), &log_brush
);
2081 ok(count
== sizeof(log_brush
), "GetObjectA failed, error %lu.\n", GetLastError());
2082 ok(log_brush
.lbColor
== 0, "Expected brush color %#x, got %#lx.\n", 0, log_brush
.lbColor
);
2083 ok(log_brush
.lbStyle
== BS_PATTERN
, "Expected brush style %#x, got %#x.\n", BS_PATTERN
,
2086 memset(&bmp
, 0, sizeof(bmp
));
2087 count
= GetObjectA((HBITMAP
)log_brush
.lbHatch
, sizeof(bmp
), &bmp
);
2088 ok(count
== sizeof(bmp
), "GetObjectA failed, error %lu.\n", GetLastError());
2089 ok(bmp
.bmWidth
== size
.cx
, "Expected width %ld, got %d.\n", size
.cx
, bmp
.bmWidth
);
2090 ok(bmp
.bmHeight
== size
.cy
, "Expected height %ld, got %d.\n", size
.cy
, bmp
.bmHeight
);
2092 /* Test that DefDlgProcA/W() are hooked for some WM_CTLCOLOR* messages */
2093 brush
= (HBRUSH
)SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2094 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
2095 brush2
= (HBRUSH
)DefDlgProcW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2096 ok(brush2
== brush
, "Expected the same brush.\n");
2097 brush2
= (HBRUSH
)DefDlgProcA(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2098 ok(brush2
== brush
, "Expected the same brush.\n");
2100 /* Test that DefWindowProcA/W() are also hooked for some WM_CTLCOLOR* messages */
2101 brush
= (HBRUSH
)SendMessageW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2102 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
2103 if (msg
!= WM_CTLCOLORDLG
)
2105 brush2
= (HBRUSH
)DefWindowProcW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2107 ok(brush2
== brush
, "Expected the same brush.\n");
2108 brush2
= (HBRUSH
)DefWindowProcA(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2110 ok(brush2
== brush
, "Expected the same brush.\n");
2114 brush2
= (HBRUSH
)DefWindowProcW(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2115 ok(brush2
!= brush
, "Expected a different brush.\n");
2116 brush2
= (HBRUSH
)DefWindowProcA(dialog
, msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2117 ok(brush2
!= brush
, "Expected a different brush.\n");
2120 winetest_pop_context();
2123 /* Test that DefWindowProcA/W() are not hooked for WM_ERASEBKGND. So the background is still
2124 * drawn with hbrBackground, which in this case, is GRAY_BRUSH.
2126 * This test means it could be that both DefWindowProc() and DefDlgProc() are hooked for
2127 * WM_CTLCOLORSTATIC and only DefDlgProc() is hooked for WM_ERASEBKGND. Or it could mean
2128 * DefWindowProc() is hooked for WM_CTLCOLORSTATIC and DefDlgProc() is hooked for WM_ERASEBKGND.
2129 * Considering the dialog theming needs a WM_ERASEBKGND to activate, it would be weird for let
2130 * only DefWindowProc() to hook WM_CTLCOLORSTATIC. For example, what's the point of hooking
2131 * WM_CTLCOLORSTATIC in DefWindowProc() for a feature that can only be activated in
2132 * DefDlgProc()? So I tend to believe both DefWindowProc() and DefDlgProc() are hooked for
2133 * WM_CTLCOLORSTATIC */
2134 hwnd
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 0, 0, 100, 100, 0, 0,
2136 ok(hwnd
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
2137 hwnd2
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 10, 10, 20, 20, hwnd
, NULL
, 0,
2139 hr
= EnableThemeDialogTexture(hwnd
, ETDT_ENABLETAB
);
2140 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2141 ret
= IsThemeDialogTextureEnabled(hwnd
);
2142 ok(ret
, "Wrong dialog texture status.\n");
2146 color
= GetPixel(hdc
, 0, 0);
2147 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
2148 "Expected color %#x, got %#lx.\n", 0x808080, color
);
2149 color
= GetPixel(hdc
, 50, 50);
2150 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
2151 "Expected color %#x, got %#lx.\n", 0x808080, color
);
2152 color
= GetPixel(hdc
, 99, 99);
2153 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
2154 "Expected color %#x, got %#lx.\n", 0x808080, color
);
2155 ReleaseDC(hwnd
, hdc
);
2157 /* Test EnableThemeDialogTexture() doesn't work for non-dialog windows */
2159 brush
= (HBRUSH
)SendMessageW(hwnd
, WM_CTLCOLORSTATIC
, (WPARAM
)hdc
, (LPARAM
)hwnd2
);
2160 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
2161 ReleaseDC(hwnd2
, hdc
);
2163 DestroyWindow(hwnd
);
2165 /* Test that the brush is not a system object and has only one reference and shouldn't be freed */
2166 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2167 ret
= DeleteObject(brush
);
2168 ok(ret
, "DeleteObject failed, error %lu.\n", GetLastError());
2169 SetLastError(0xdeadbeef);
2170 ret
= GetObjectA(brush
, sizeof(log_brush
), &log_brush
);
2171 error
= GetLastError();
2172 ok(!ret
|| broken(ret
) /* XP */, "GetObjectA succeeded.\n");
2174 ok(error
== ERROR_INVALID_PARAMETER
|| broken(error
== 0xdeadbeef) /* XP */,
2175 "Expected error %u, got %lu.\n", ERROR_INVALID_PARAMETER
, error
);
2176 ret
= DeleteObject(brush
);
2177 ok(!ret
|| broken(ret
) /* XP */, "DeleteObject succeeded.\n");
2179 /* Should still report the same brush handle after the brush handle was freed */
2180 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2181 ok(brush2
== brush
, "Expected the same brush.\n");
2183 /* Test WM_THEMECHANGED can update the brush now that ETDT_ENABLE | ETDT_USETABTEXTURE is in
2184 * effect. This test needs to be ran last as it affect other tests for the same dialog for
2185 * unknown reason, causing the brush not to update */
2186 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2187 lr
= SendMessageA(dialog
, WM_THEMECHANGED
, 0, 0);
2188 ok(lr
== 0, "WM_THEMECHANGED failed.\n");
2189 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2190 ok(brush2
!= brush
, "Expected a different brush.\n");
2192 ReleaseDC(child
, child_hdc
);
2193 EndDialog(dialog
, 0);
2195 /* Test invalid flags */
2196 for (i
= 0; i
< ARRAY_SIZE(invalid_flag_tests
); ++i
)
2198 winetest_push_context("%d flag %#lx", i
, invalid_flag_tests
[i
].flag
);
2200 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2201 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
2202 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2203 hr
= EnableThemeDialogTexture(dialog
, invalid_flag_tests
[i
].flag
);
2204 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2205 ret
= IsThemeDialogTextureEnabled(dialog
);
2206 ok(ret
== invalid_flag_tests
[i
].enabled
, "Wrong dialog texture status.\n");
2207 EndDialog(dialog
, 0);
2209 winetest_pop_context();
2212 /* Test different flag combinations */
2213 for (i
= 0; i
< ARRAY_SIZE(flags
); ++i
)
2215 for (j
= 0; j
< ARRAY_SIZE(flags
); ++j
)
2217 /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
2218 if (LOBYTE(LOWORD(GetVersion())) < 6
2219 && ((flags
[i
] | flags
[j
]) & ETDT_USEAEROWIZARDTABTEXTURE
))
2222 winetest_push_context("%#lx to %#lx", flags
[i
], flags
[j
]);
2224 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2225 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
2226 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2228 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2230 hr
= EnableThemeDialogTexture(dialog
, flags
[i
]);
2231 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2232 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2233 "EnableThemeDialogTexture first flag", FALSE
);
2234 ret
= IsThemeDialogTextureEnabled(dialog
);
2235 /* Non-zero flags without ETDT_DISABLE enables dialog texture */
2236 ok(ret
== (!(flags
[i
] & ETDT_DISABLE
) && flags
[i
]), "Wrong dialog texture status.\n");
2238 child
= GetDlgItem(dialog
, 100);
2239 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2240 child_hdc
= GetDC(child
);
2241 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
2242 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
2243 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2244 if (flags
[i
] == ETDT_ENABLETAB
|| flags
[i
] == ETDT_ENABLEAEROWIZARDTAB
)
2245 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2247 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2248 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2250 hr
= EnableThemeDialogTexture(dialog
, flags
[j
]);
2251 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#lx.\n", hr
);
2252 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2253 "EnableThemeDialogTexture second flag", FALSE
);
2254 ret
= IsThemeDialogTextureEnabled(dialog
);
2255 /* If the flag is zero, it will have previous dialog texture status */
2257 ok(ret
== !(flags
[j
] & ETDT_DISABLE
), "Wrong dialog texture status.\n");
2259 ok(ret
== (!(flags
[i
] & ETDT_DISABLE
) && flags
[i
]), "Wrong dialog texture status.\n");
2260 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
2261 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
2262 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2263 /* Dialog texture is turned on when the flag contains ETDT_ENABLETAB or
2264 * ETDT_ENABLEAEROWIZARDTAB. The flag can be turned on in multiple steps, but you can't
2265 * do things like set ETDT_ENABLETAB and then ETDT_USEAEROWIZARDTABTEXTURE */
2266 if (((flags
[j
] == ETDT_ENABLETAB
|| flags
[j
] == ETDT_ENABLEAEROWIZARDTAB
)
2267 || ((((flags
[i
] | flags
[j
]) & ETDT_ENABLETAB
) == ETDT_ENABLETAB
2268 || ((flags
[i
] | flags
[j
]) & ETDT_ENABLEAEROWIZARDTAB
) == ETDT_ENABLEAEROWIZARDTAB
)
2269 && !((flags
[i
] | flags
[j
]) & ETDT_DISABLE
)))
2270 && (((flags
[i
] | flags
[j
]) & (ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
)) != (ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
)))
2271 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2273 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2275 ReleaseDC(child
, child_hdc
);
2276 EndDialog(dialog
, 0);
2278 winetest_pop_context();
2282 /* Test that the dialog procedure should set ETDT_USETABTEXTURE/ETDT_USEAEROWIZARDTABTEXTURE and
2283 * find out which comctl32 class should set ETDT_ENABLE to turn on dialog texture */
2284 for (i
= 0; i
< ARRAY_SIZE(class_tests
); ++i
)
2286 winetest_push_context("%s %#lx", wine_dbgstr_a(class_tests
[i
].param
.class_name
),
2287 class_tests
[i
].param
.style
);
2289 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2290 test_EnableThemeDialogTexture_proc
,
2291 (LPARAM
)&class_tests
[i
].param
);
2292 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2293 /* GetDlgItem() fails to get the child control if the child is a tooltip */
2294 child
= dialog_child
;
2295 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2296 child_hdc
= GetDC(child
);
2298 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2299 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2301 ReleaseDC(child
, child_hdc
);
2302 EndDialog(dialog
, 0);
2304 dialog_init_flag
= ETDT_ENABLE
;
2305 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2306 test_EnableThemeDialogTexture_proc
,
2307 (LPARAM
)&class_tests
[i
].param
);
2308 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2309 child
= dialog_child
;
2310 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2311 child_hdc
= GetDC(child
);
2313 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2314 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2316 ReleaseDC(child
, child_hdc
);
2317 EndDialog(dialog
, 0);
2319 dialog_init_flag
= ETDT_USETABTEXTURE
;
2320 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2321 test_EnableThemeDialogTexture_proc
,
2322 (LPARAM
)&class_tests
[i
].param
);
2323 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2324 child
= dialog_child
;
2325 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2326 child_hdc
= GetDC(child
);
2327 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2328 if (class_tests
[i
].texture_enabled
)
2329 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2331 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2332 ReleaseDC(child
, child_hdc
);
2333 EndDialog(dialog
, 0);
2335 if (LOBYTE(LOWORD(GetVersion())) < 6)
2337 dialog_init_flag
= 0;
2338 winetest_pop_context();
2342 dialog_init_flag
= ETDT_USEAEROWIZARDTABTEXTURE
;
2343 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2344 test_EnableThemeDialogTexture_proc
,
2345 (LPARAM
)&class_tests
[i
].param
);
2346 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2347 child
= dialog_child
;
2348 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2349 child_hdc
= GetDC(child
);
2350 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2351 if (class_tests
[i
].texture_enabled
)
2352 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2354 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2355 ReleaseDC(child
, child_hdc
);
2356 EndDialog(dialog
, 0);
2357 dialog_init_flag
= 0;
2359 winetest_pop_context();
2362 /* Test that EnableThemeDialogTexture() is called from child controls for its parent */
2363 hwnd
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 100, 100, 200, 200, 0,
2365 ok(hwnd
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
2366 ret
= IsThemeDialogTextureEnabled(hwnd
);
2367 ok(!ret
, "Wrong dialog texture status.\n");
2368 child
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 0, 0, 50, 50, hwnd
, 0, 0,
2370 ok(child
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
2371 ret
= IsThemeDialogTextureEnabled(hwnd
);
2372 ok(ret
, "Wrong dialog texture status.\n");
2374 /* Test that if you move the child control to another window, it doesn't enables tab texture for
2376 hwnd2
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 100, 100, 200, 200, 0,
2378 ok(hwnd2
!= NULL
, "CreateWindowA failed, error %ld.\n", GetLastError());
2379 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2380 ok(!ret
, "Wrong dialog texture status.\n");
2382 SetParent(child
, hwnd2
);
2383 ok(GetParent(child
) == hwnd2
, "Wrong parent.\n");
2384 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2385 ok(!ret
, "Wrong dialog texture status.\n");
2386 InvalidateRect(child
, NULL
, TRUE
);
2388 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2389 ok(!ret
, "Wrong dialog texture status.\n");
2391 DestroyWindow(hwnd2
);
2392 DestroyWindow(hwnd
);
2394 /* Test that application dialog procedures should be called only once for each message */
2395 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2396 test_EnableThemeDialogTexture_proc
,
2398 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %ld.\n", GetLastError());
2399 child
= dialog_child
;
2400 ok(child
!= NULL
, "Failed to get child control, error %ld.\n", GetLastError());
2401 child_hdc
= GetDC(child
);
2402 for (i
= 0; i
< ARRAY_SIZE(message_tests
); ++i
)
2404 sprintf(buffer
, "message %#x\n", message_tests
[i
].msg
);
2405 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2406 SendMessageW(dialog
, message_tests
[i
].msg
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2407 ok_sequence(sequences
, PARENT_SEQ_INDEX
, message_tests
[i
].msg_seq
, buffer
, FALSE
);
2409 ReleaseDC(child
, child_hdc
);
2410 EndDialog(dialog
, 0);
2412 UnregisterClassA(cls
.lpszClassName
, GetModuleHandleA(NULL
));
2415 static void test_DrawThemeBackgroundEx(void)
2417 static const int width
= 10, height
= 10;
2418 static const RECT rect
= {0, 0, 10, 10};
2419 HBITMAP bitmap
, old_bitmap
;
2420 BOOL transparent
, found
;
2421 BITMAPINFO bitmap_info
;
2430 proc
= GetProcAddress(GetModuleHandleA("uxtheme.dll"), MAKEINTRESOURCEA(47));
2431 ok(proc
== (void *)pDrawThemeBackgroundEx
, "Expected DrawThemeBackgroundEx() at ordinal 47.\n");
2433 hwnd
= CreateWindowA(WC_STATICA
, "", WS_POPUP
, 0, 0, 1, 1, 0, 0, 0, NULL
);
2434 ok(hwnd
!= NULL
, "CreateWindowA failed, error %#lx.\n", GetLastError());
2435 htheme
= OpenThemeData(hwnd
, L
"Spin");
2438 skip("Theming is inactive.\n");
2439 DestroyWindow(hwnd
);
2443 bitmap_info
.bmiHeader
.biSize
= sizeof(bitmap_info
.bmiHeader
);
2444 bitmap_info
.bmiHeader
.biWidth
= width
;
2445 bitmap_info
.bmiHeader
.biHeight
= height
;
2446 bitmap_info
.bmiHeader
.biPlanes
= 1;
2447 bitmap_info
.bmiHeader
.biBitCount
= 32;
2448 bitmap_info
.bmiHeader
.biCompression
= BI_RGB
;
2449 bitmap
= CreateDIBSection(0, &bitmap_info
, DIB_RGB_COLORS
, (void **)&bits
, 0, 0);
2450 mem_dc
= CreateCompatibleDC(NULL
);
2451 old_bitmap
= SelectObject(mem_dc
, bitmap
);
2453 /* Drawing opaque background with transparent glyphs should discard the alpha values from the glyphs */
2454 transparent
= IsThemeBackgroundPartiallyTransparent(htheme
, SPNP_UP
, UPS_NORMAL
);
2455 ok(!transparent
, "Expected spin button background opaque.\n");
2456 hr
= GetThemeBool(htheme
, SPNP_UP
, UPS_NORMAL
, TMT_TRANSPARENT
, &transparent
);
2457 ok(hr
== E_PROP_ID_UNSUPPORTED
, "Got unexpected hr %#lx.\n", hr
);
2458 transparent
= FALSE
;
2459 hr
= GetThemeBool(htheme
, SPNP_UP
, UPS_NORMAL
, TMT_GLYPHTRANSPARENT
, &transparent
);
2460 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2461 ok(transparent
, "Expected spin button glyph transparent.\n");
2463 memset(bits
, 0xa5, width
* height
* sizeof(int));
2464 hr
= DrawThemeBackgroundEx(htheme
, mem_dc
, SPNP_UP
, UPS_NORMAL
, &rect
, NULL
);
2465 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2467 for (i
= 0; i
< width
* height
; ++i
)
2474 ok(i
== width
* height
|| broken(ptr
[3] == 0) /* Spin button glyphs on XP don't use alpha */,
2475 "Unexpected alpha value %#x at (%d,%d).\n", ptr
[3], i
% height
, i
/ height
);
2477 /* Drawing transparent background without glyphs should keep the alpha values */
2478 CloseThemeData(htheme
);
2479 htheme
= OpenThemeData(hwnd
, L
"Scrollbar");
2480 transparent
= IsThemeBackgroundPartiallyTransparent(htheme
, SBP_SIZEBOX
, SZB_RIGHTALIGN
);
2481 ok(transparent
, "Expected scrollbar sizebox transparent.\n");
2482 transparent
= FALSE
;
2483 hr
= GetThemeBool(htheme
, SBP_SIZEBOX
, SZB_RIGHTALIGN
, TMT_TRANSPARENT
, &transparent
);
2484 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2485 ok(transparent
, "Expected scrollbar sizebox transparent.\n");
2486 hr
= GetThemeEnumValue(htheme
, SBP_SIZEBOX
, SZB_RIGHTALIGN
, TMT_GLYPHTYPE
, &glyph_type
);
2487 ok(hr
== E_PROP_ID_UNSUPPORTED
, "Got unexpected hr %#lx.\n", hr
);
2489 memset(bits
, 0xa5, width
* height
* sizeof(int));
2490 hr
= DrawThemeBackgroundEx(htheme
, mem_dc
, SBP_SIZEBOX
, SZB_RIGHTALIGN
, &rect
, NULL
);
2491 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2494 for (i
= 0; i
< width
* height
; ++i
)
2504 ok(found
, "Expected alpha values found.\n");
2506 /* Drawing transparent background with transparent glyphs should keep alpha values */
2507 CloseThemeData(htheme
);
2508 htheme
= OpenThemeData(hwnd
, L
"Header");
2509 if (IsThemePartDefined(htheme
, HP_HEADERDROPDOWN
, 0))
2511 transparent
= IsThemeBackgroundPartiallyTransparent(htheme
, HP_HEADERDROPDOWN
, HDDS_NORMAL
);
2512 ok(transparent
, "Expected header dropdown transparent.\n");
2513 transparent
= FALSE
;
2514 hr
= GetThemeBool(htheme
, HP_HEADERDROPDOWN
, HDDS_NORMAL
, TMT_TRANSPARENT
, &transparent
);
2515 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2516 ok(transparent
, "Expected header dropdown background transparent.\n");
2517 transparent
= FALSE
;
2518 hr
= GetThemeBool(htheme
, HP_HEADERDROPDOWN
, HDDS_NORMAL
, TMT_GLYPHTRANSPARENT
, &transparent
);
2519 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2520 ok(transparent
, "Expected header dropdown glyph transparent.\n");
2522 memset(bits
, 0xa5, width
* height
* sizeof(int));
2523 hr
= DrawThemeBackgroundEx(htheme
, mem_dc
, HP_HEADERDROPDOWN
, HDDS_NORMAL
, &rect
, NULL
);
2524 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2527 for (i
= 0; i
< width
* height
; ++i
)
2537 ok(found
, "Expected alpha values found.\n");
2541 skip("Failed to get header dropdown parts.\n");
2544 SelectObject(mem_dc
, old_bitmap
);
2546 DeleteObject(bitmap
);
2547 CloseThemeData(htheme
);
2548 DestroyWindow(hwnd
);
2551 static void test_GetThemeBackgroundRegion(void)
2560 hwnd
= CreateWindowA(WC_STATICA
, "", WS_POPUP
, 0, 0, 1, 1, 0, 0, 0, NULL
);
2561 ok(hwnd
!= NULL
, "CreateWindowA failed, error %#lx.\n", GetLastError());
2562 htheme
= OpenThemeData(hwnd
, L
"Rebar");
2565 skip("Theming is inactive.\n");
2566 DestroyWindow(hwnd
);
2570 hr
= GetThemeEnumValue(htheme
, RP_BAND
, 0, TMT_BGTYPE
, &ret
);
2571 ok(hr
== S_OK
, "Got unexpected hr %#lx,\n", hr
);
2572 ok(ret
== BT_NONE
, "Got expected type %d.\n", ret
);
2574 SetRect(&rect
, 0, 0, 10, 10);
2575 region
= (HRGN
)0xdeadbeef;
2576 hr
= GetThemeBackgroundRegion(htheme
, NULL
, RP_BAND
, 0, &rect
, ®ion
);
2577 ok(hr
== E_UNEXPECTED
|| broken(hr
== S_OK
) /* < Win10 */, "Got unexpected hr %#lx.\n", hr
);
2578 ok(region
== (HRGN
)0xdeadbeef, "Got unexpected region.\n");
2580 CloseThemeData(htheme
);
2581 DestroyWindow(hwnd
);
2584 static void test_theme(void)
2591 if (!IsThemeActive())
2593 skip("Theming is inactive.\n");
2597 hwnd
= CreateWindowA(WC_STATICA
, "", WS_POPUP
, 0, 0, 1, 1, 0, 0, 0, NULL
);
2598 ok(!!hwnd
, "CreateWindowA failed, error %#lx.\n", GetLastError());
2600 /* Test that scrollbar arrow parts are transparent */
2601 htheme
= OpenThemeData(hwnd
, L
"ScrollBar");
2602 ok(!!htheme
, "OpenThemeData failed.\n");
2604 transparent
= FALSE
;
2605 hr
= GetThemeBool(htheme
, SBP_ARROWBTN
, 0, TMT_TRANSPARENT
, &transparent
);
2606 /* XP does use opaque scrollbar arrow parts and TMT_TRANSPARENT is FALSE */
2607 if (LOBYTE(LOWORD(GetVersion())) < 6)
2609 ok(hr
== E_PROP_ID_UNSUPPORTED
, "Got unexpected hr %#lx.\n", hr
);
2611 transparent
= IsThemeBackgroundPartiallyTransparent(htheme
, SBP_ARROWBTN
, 0);
2612 ok(!transparent
, "Expected opaque.\n");
2614 /* > XP use opaque scrollbar arrow parts, but TMT_TRANSPARENT is TRUE */
2617 ok(hr
== S_OK
, "Got unexpected hr %#lx.\n", hr
);
2618 ok(transparent
, "Expected transparent.\n");
2620 transparent
= IsThemeBackgroundPartiallyTransparent(htheme
, SBP_ARROWBTN
, 0);
2621 ok(transparent
, "Expected transparent.\n");
2623 CloseThemeData(htheme
);
2625 DestroyWindow(hwnd
);
2628 static void test_ShouldSystemUseDarkMode(void)
2630 DWORD light_theme
, light_theme_size
= sizeof(light_theme
), last_error
;
2634 if (!pShouldSystemUseDarkMode
)
2636 win_skip("ShouldSystemUseDarkMode() is unavailable.\n");
2640 ls
= RegGetValueW(HKEY_CURRENT_USER
,
2641 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
2642 L
"SystemUsesLightTheme", RRF_RT_REG_DWORD
, NULL
, &light_theme
, &light_theme_size
);
2643 if (ls
== ERROR_FILE_NOT_FOUND
)
2645 skip("SystemUsesLightTheme registry value not found.\n");
2648 ok(ls
== 0, "RegGetValue failed: %ld.\n", ls
);
2650 SetLastError(0xdeadbeef);
2651 result
= pShouldSystemUseDarkMode();
2652 last_error
= GetLastError();
2653 ok(last_error
== 0xdeadbeef, "ShouldSystemUseDarkMode set last error: %ld.\n", last_error
);
2654 ok(result
== !light_theme
, "Expected value %d, got %d.\n", !light_theme
, result
);
2657 static void test_ShouldAppsUseDarkMode(void)
2659 DWORD light_theme
, light_theme_size
= sizeof(light_theme
), last_error
;
2663 if (!pShouldAppsUseDarkMode
)
2665 win_skip("ShouldAppsUseDarkMode() is unavailable\n");
2669 ls
= RegGetValueW(HKEY_CURRENT_USER
,
2670 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
2671 L
"AppsUseLightTheme", RRF_RT_REG_DWORD
, NULL
, &light_theme
, &light_theme_size
);
2672 if (ls
== ERROR_FILE_NOT_FOUND
)
2674 skip("AppsUseLightTheme registry value not found.\n");
2677 ok(ls
== 0, "RegGetValue failed: %ld.\n", ls
);
2679 SetLastError(0xdeadbeef);
2680 result
= pShouldAppsUseDarkMode();
2681 last_error
= GetLastError();
2682 ok(last_error
== 0xdeadbeef, "ShouldAppsUseDarkMode set last error: %ld.\n", last_error
);
2683 ok(result
== !light_theme
, "Expected value %d, got %d\n", !light_theme
, result
);
2688 ULONG_PTR ctx_cookie
;
2692 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2695 test_IsThemePartDefined();
2696 test_GetWindowTheme();
2697 test_SetWindowTheme();
2698 test_OpenThemeData();
2699 test_OpenThemeDataEx();
2700 test_OpenThemeDataForDpi();
2701 test_GetCurrentThemeName();
2702 test_GetThemePartSize();
2703 test_CloseThemeData();
2704 test_buffered_paint();
2705 test_GetThemeIntList();
2706 test_GetThemeTransitionDuration();
2707 test_DrawThemeParentBackground();
2708 test_DrawThemeBackgroundEx();
2709 test_GetThemeBackgroundRegion();
2711 test_ShouldSystemUseDarkMode();
2712 test_ShouldAppsUseDarkMode();
2714 if (load_v6_module(&ctx_cookie
, &ctx
))
2716 test_EnableThemeDialogTexture();
2718 unload_v6_module(ctx_cookie
, ctx
);
2721 /* Test EnableTheming() in the end because it may disable theming */
2722 test_EnableTheming();