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
*pEndBufferedPaint
)(HPAINTBUFFER
, BOOL
);
44 static HRESULT (WINAPI
*pGetBufferedPaintBits
)(HPAINTBUFFER
, RGBQUAD
**, int *);
45 static HDC (WINAPI
*pGetBufferedPaintDC
)(HPAINTBUFFER
);
46 static HDC (WINAPI
*pGetBufferedPaintTargetDC
)(HPAINTBUFFER
);
47 static HRESULT (WINAPI
*pGetBufferedPaintTargetRect
)(HPAINTBUFFER
, RECT
*);
48 static HRESULT (WINAPI
*pGetThemeIntList
)(HTHEME
, int, int, int, INTLIST
*);
49 static HRESULT (WINAPI
*pGetThemeTransitionDuration
)(HTHEME
, int, int, int, int, DWORD
*);
51 static LONG (WINAPI
*pDisplayConfigGetDeviceInfo
)(DISPLAYCONFIG_DEVICE_INFO_HEADER
*);
52 static LONG (WINAPI
*pDisplayConfigSetDeviceInfo
)(DISPLAYCONFIG_DEVICE_INFO_HEADER
*);
53 static BOOL (WINAPI
*pGetDpiForMonitorInternal
)(HMONITOR
, UINT
, UINT
*, UINT
*);
54 static DPI_AWARENESS_CONTEXT (WINAPI
*pSetThreadDpiAwarenessContext
)(DPI_AWARENESS_CONTEXT
);
56 static NTSTATUS (WINAPI
*pD3DKMTCloseAdapter
)(const D3DKMT_CLOSEADAPTER
*);
57 static NTSTATUS (WINAPI
*pD3DKMTOpenAdapterFromGdiDisplayName
)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME
*);
59 /* For message tests */
67 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
69 static void init_funcs(void)
71 HMODULE user32
= GetModuleHandleA("user32.dll");
72 HMODULE gdi32
= GetModuleHandleA("gdi32.dll");
73 HMODULE uxtheme
= GetModuleHandleA("uxtheme.dll");
75 #define GET_PROC(module, func) \
76 p##func = (void *)GetProcAddress(module, #func); \
78 trace("GetProcAddress(%s, %s) failed.\n", #module, #func);
80 GET_PROC(uxtheme
, BeginBufferedPaint
)
81 GET_PROC(uxtheme
, BufferedPaintClear
)
82 GET_PROC(uxtheme
, EndBufferedPaint
)
83 GET_PROC(uxtheme
, GetBufferedPaintBits
)
84 GET_PROC(uxtheme
, GetBufferedPaintDC
)
85 GET_PROC(uxtheme
, GetBufferedPaintTargetDC
)
86 GET_PROC(uxtheme
, GetBufferedPaintTargetRect
)
87 GET_PROC(uxtheme
, GetThemeIntList
)
88 GET_PROC(uxtheme
, GetThemeTransitionDuration
)
89 GET_PROC(uxtheme
, OpenThemeDataEx
)
90 GET_PROC(uxtheme
, OpenThemeDataForDpi
)
92 GET_PROC(user32
, DisplayConfigGetDeviceInfo
)
93 GET_PROC(user32
, DisplayConfigSetDeviceInfo
)
94 GET_PROC(user32
, GetDpiForMonitorInternal
)
95 GET_PROC(user32
, SetThreadDpiAwarenessContext
)
97 GET_PROC(gdi32
, D3DKMTCloseAdapter
)
98 GET_PROC(gdi32
, D3DKMTOpenAdapterFromGdiDisplayName
)
103 /* Try to make sure pending X events have been processed before continuing */
104 static void flush_events(void)
108 int min_timeout
= 100;
109 DWORD time
= GetTickCount() + diff
;
113 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
)
115 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
116 DispatchMessageA(&msg
);
117 diff
= time
- GetTickCount();
121 static unsigned int get_primary_monitor_effective_dpi(void)
123 DPI_AWARENESS_CONTEXT old_context
;
124 UINT dpi_x
= 0, dpi_y
= 0;
125 POINT point
= {0, 0};
128 if (pSetThreadDpiAwarenessContext
&& pGetDpiForMonitorInternal
)
130 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
131 monitor
= MonitorFromPoint(point
, MONITOR_DEFAULTTOPRIMARY
);
132 pGetDpiForMonitorInternal(monitor
, 0, &dpi_x
, &dpi_y
);
133 pSetThreadDpiAwarenessContext(old_context
);
137 return USER_DEFAULT_SCREEN_DPI
;
140 static int get_dpi_scale_index(int dpi
)
142 static const int scales
[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500};
143 int scale
, scale_idx
;
145 scale
= dpi
* 100 / 96;
146 for (scale_idx
= 0; scale_idx
< ARRAY_SIZE(scales
); ++scale_idx
)
148 if (scales
[scale_idx
] == scale
)
155 static BOOL
set_primary_monitor_effective_dpi(unsigned int primary_dpi
)
157 D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc
;
158 DISPLAYCONFIG_GET_SOURCE_DPI_SCALE get_scale_req
;
159 DISPLAYCONFIG_SET_SOURCE_DPI_SCALE set_scale_req
;
160 int current_scale_idx
, target_scale_idx
;
161 D3DKMT_CLOSEADAPTER close_adapter_desc
;
165 #define CHECK_FUNC(func) \
168 skip("%s() is unavailable.\n", #func); \
172 CHECK_FUNC(D3DKMTCloseAdapter
)
173 CHECK_FUNC(D3DKMTOpenAdapterFromGdiDisplayName
)
174 CHECK_FUNC(DisplayConfigGetDeviceInfo
)
175 CHECK_FUNC(DisplayConfigSetDeviceInfo
)
179 lstrcpyW(open_adapter_gdi_desc
.DeviceName
, L
"\\\\.\\DISPLAY1");
180 if (pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc
) == STATUS_PROCEDURE_NOT_FOUND
)
182 win_skip("D3DKMTOpenAdapterFromGdiDisplayName() is unavailable.\n");
186 get_scale_req
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE
;
187 get_scale_req
.header
.size
= sizeof(get_scale_req
);
188 get_scale_req
.header
.adapterId
= open_adapter_gdi_desc
.AdapterLuid
;
189 get_scale_req
.header
.id
= open_adapter_gdi_desc
.VidPnSourceId
;
190 error
= pDisplayConfigGetDeviceInfo(&get_scale_req
.header
);
191 if (error
!= NO_ERROR
)
193 skip("DisplayConfigGetDeviceInfo failed, returned %d.\n", error
);
197 current_scale_idx
= get_dpi_scale_index(get_primary_monitor_effective_dpi());
198 if (current_scale_idx
== -1)
200 skip("Failed to find current scale index.\n");
204 target_scale_idx
= get_dpi_scale_index(primary_dpi
);
205 if (target_scale_idx
< get_scale_req
.minRelativeScaleStep
206 || target_scale_idx
> get_scale_req
.maxRelativeScaleStep
)
208 skip("DPI %d is not available.\n", primary_dpi
);
212 set_scale_req
.header
.type
= DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE
;
213 set_scale_req
.header
.size
= sizeof(set_scale_req
);
214 set_scale_req
.header
.adapterId
= open_adapter_gdi_desc
.AdapterLuid
;
215 set_scale_req
.header
.id
= open_adapter_gdi_desc
.VidPnSourceId
;
216 set_scale_req
.relativeScaleStep
= get_scale_req
.curRelativeScaleStep
+ (target_scale_idx
- current_scale_idx
);
217 error
= pDisplayConfigSetDeviceInfo(&set_scale_req
.header
);
218 if (error
== NO_ERROR
)
219 ret
= get_primary_monitor_effective_dpi() == primary_dpi
;
223 close_adapter_desc
.hAdapter
= open_adapter_gdi_desc
.hAdapter
;
224 pD3DKMTCloseAdapter(&close_adapter_desc
);
228 static LRESULT WINAPI
TestSetWindowThemeParentProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
230 static LONG defwndproc_counter
;
231 struct message msg
= {0};
234 /* Only care about WM_THEMECHANGED */
235 if (message
!= WM_THEMECHANGED
)
236 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
238 msg
.message
= message
;
239 msg
.flags
= sent
| wparam
| lparam
;
240 if (defwndproc_counter
)
241 msg
.flags
|= defwinproc
;
244 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
246 InterlockedIncrement(&defwndproc_counter
);
247 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
248 InterlockedDecrement(&defwndproc_counter
);
252 static LRESULT WINAPI
TestSetWindowThemeChildProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
254 static LONG defwndproc_counter
;
255 struct message msg
= {0};
258 /* Only care about WM_THEMECHANGED */
259 if (message
!= WM_THEMECHANGED
)
260 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
262 msg
.message
= message
;
263 msg
.flags
= sent
| wparam
| lparam
;
264 if (defwndproc_counter
)
265 msg
.flags
|= defwinproc
;
268 add_message(sequences
, CHILD_SEQ_INDEX
, &msg
);
270 InterlockedIncrement(&defwndproc_counter
);
271 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
272 InterlockedDecrement(&defwndproc_counter
);
276 static void test_IsThemed(void)
282 bThemeActive
= IsThemeActive();
283 trace("Theming is %s\n", (bThemeActive
) ? "active" : "inactive");
285 bAppThemed
= IsAppThemed();
286 trace("Test executable is %s\n", (bAppThemed
) ? "themed" : "not themed");
288 SetLastError(0xdeadbeef);
289 bTPDefined
= IsThemePartDefined(NULL
, 0 , 0);
290 ok( bTPDefined
== FALSE
, "Expected FALSE\n");
291 ok( GetLastError() == E_HANDLE
,
292 "Expected E_HANDLE, got 0x%08x\n",
296 static void test_GetWindowTheme(void)
301 SetLastError(0xdeadbeef);
302 hTheme
= GetWindowTheme(NULL
);
303 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
304 ok( GetLastError() == E_HANDLE
, "Expected E_HANDLE, got 0x%08x\n", GetLastError() );
306 /* Only do the bare minimum to get a valid hwnd */
307 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
308 ok(hWnd
!= NULL
, "Failed to create a test window.\n");
310 SetLastError(0xdeadbeef);
311 hTheme
= GetWindowTheme(hWnd
);
312 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
313 ok( GetLastError() == 0xdeadbeef,
314 "Expected 0xdeadbeef, got 0x%08x\n",
320 static const struct message SetWindowThemeSeq
[] =
322 {WM_THEMECHANGED
, sent
},
326 static const struct message EmptySeq
[] =
331 static void test_SetWindowTheme(void)
339 hRes
= SetWindowTheme(NULL
, NULL
, NULL
);
340 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08x\n", hRes
);
342 /* Test that WM_THEMECHANGED is sent and not posted to windows */
343 cls
.hInstance
= GetModuleHandleA(0);
344 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
345 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
346 cls
.lpfnWndProc
= TestSetWindowThemeParentProcA
;
347 cls
.lpszClassName
= "TestSetWindowThemeParentClass";
348 RegisterClassA(&cls
);
350 cls
.lpfnWndProc
= TestSetWindowThemeChildProcA
;
351 cls
.lpszClassName
= "TestSetWindowThemeChildClass";
352 RegisterClassA(&cls
);
354 hWnd
= CreateWindowA("TestSetWindowThemeParentClass", "parent",
355 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
, 100, 100, 200, 200, 0, 0, 0, NULL
);
356 ok(!!hWnd
, "Failed to create a parent window.\n");
357 child
= CreateWindowA("TestSetWindowThemeChildClass", "child", WS_CHILD
| WS_VISIBLE
, 0, 0, 50,
358 50, hWnd
, 0, 0, NULL
);
359 ok(!!child
, "Failed to create a child window.\n");
361 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
363 hRes
= SetWindowTheme(hWnd
, NULL
, NULL
);
364 ok(hRes
== S_OK
, "Expected %#x, got %#x.\n", S_OK
, hRes
);
365 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
367 struct message recv_msg
= {0};
369 if (msg
.message
== WM_THEMECHANGED
)
371 recv_msg
.message
= msg
.message
;
372 recv_msg
.flags
= posted
| wparam
| lparam
;
373 recv_msg
.wParam
= msg
.wParam
;
374 recv_msg
.lParam
= msg
.lParam
;
375 add_message(sequences
, msg
.hwnd
== hWnd
? PARENT_SEQ_INDEX
: CHILD_SEQ_INDEX
, &recv_msg
);
377 DispatchMessageA(&msg
);
379 ok_sequence(sequences
, PARENT_SEQ_INDEX
, SetWindowThemeSeq
, "SetWindowTheme parent", FALSE
);
380 ok_sequence(sequences
, CHILD_SEQ_INDEX
, EmptySeq
, "SetWindowTheme child", FALSE
);
382 UnregisterClassA("TestSetWindowThemeParentClass", GetModuleHandleA(0));
383 UnregisterClassA("TestSetWindowThemeChildClass", GetModuleHandleA(0));
385 /* Only do the bare minimum to get a valid hwnd */
386 hWnd
= CreateWindowExA(0, "button", "test", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
387 ok(hWnd
!= NULL
, "Failed to create a test window.\n");
389 hRes
= SetWindowTheme(hWnd
, NULL
, NULL
);
390 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
394 hTheme
= OpenThemeData(hWnd
, L
"Button");
395 ok(!!hTheme
, "OpenThemeData failed.\n");
396 CloseThemeData(hTheme
);
398 hRes
= SetWindowTheme(hWnd
, L
"deadbeef", NULL
);
399 ok(hRes
== S_OK
, "Expected S_OK, got 0x%08x.\n", hRes
);
401 hTheme
= OpenThemeData(hWnd
, L
"Button");
402 ok(!!hTheme
, "OpenThemeData failed.\n");
403 CloseThemeData(hTheme
);
407 skip("No active theme, skipping rest of SetWindowTheme tests.\n");
413 static void test_OpenThemeData(void)
415 HTHEME hTheme
, hTheme2
;
421 const WCHAR szInvalidClassList
[] = L
"DEADBEEF";
422 const WCHAR szButtonClassList
[] = L
"Button";
423 const WCHAR szButtonClassList2
[] = L
"bUtToN";
424 const WCHAR szClassList
[] = L
"Button;ListBox";
426 bThemeActive
= IsThemeActive();
429 SetLastError(0xdeadbeef);
430 hTheme
= OpenThemeData(NULL
, NULL
);
431 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
432 ok( GetLastError() == E_POINTER
,
433 "Expected GLE() to be E_POINTER, got 0x%08x\n",
436 /* A NULL hWnd and an invalid classlist */
437 SetLastError(0xdeadbeef);
438 hTheme
= OpenThemeData(NULL
, szInvalidClassList
);
439 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
440 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
441 E_PROP_ID_UNSUPPORTED
, GetLastError() );
443 SetLastError(0xdeadbeef);
444 hTheme
= OpenThemeData(NULL
, szClassList
);
447 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
448 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
452 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
453 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
454 E_PROP_ID_UNSUPPORTED
, GetLastError() );
457 /* Only do the bare minimum to get a valid hdc */
458 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
461 SetLastError(0xdeadbeef);
462 hTheme
= OpenThemeData(hWnd
, NULL
);
463 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
464 ok( GetLastError() == E_POINTER
,
465 "Expected GLE() to be E_POINTER, got 0x%08x\n",
468 SetLastError(0xdeadbeef);
469 hTheme
= OpenThemeData(hWnd
, szInvalidClassList
);
470 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
471 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
472 E_PROP_ID_UNSUPPORTED
, GetLastError() );
476 SetLastError(0xdeadbeef);
477 hTheme
= OpenThemeData(hWnd
, szButtonClassList
);
478 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
479 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
480 E_PROP_ID_UNSUPPORTED
, GetLastError() );
481 skip("No active theme, skipping rest of OpenThemeData tests\n");
485 /* Only do the next checks if we have an active theme */
487 SetLastError(0xdeadbeef);
488 hTheme
= OpenThemeData(hWnd
, szButtonClassList
);
489 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
490 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
492 /* Test with bUtToN instead of Button */
493 SetLastError(0xdeadbeef);
494 hTheme
= OpenThemeData(hWnd
, szButtonClassList2
);
495 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
496 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
498 SetLastError(0xdeadbeef);
499 hTheme
= OpenThemeData(hWnd
, szClassList
);
500 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
501 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
503 /* GetWindowTheme should return the last handle opened by OpenThemeData */
504 SetLastError(0xdeadbeef);
505 hTheme2
= GetWindowTheme(hWnd
);
506 ok( hTheme
== hTheme2
, "Expected the same HTHEME handle (%p<->%p)\n",
508 ok( GetLastError() == 0xdeadbeef,
509 "Expected 0xdeadbeef, got 0x%08x\n",
512 hRes
= CloseThemeData(hTheme
);
513 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
515 /* Close a second time */
516 hRes
= CloseThemeData(hTheme
);
517 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
519 /* See if closing makes a difference for GetWindowTheme */
520 SetLastError(0xdeadbeef);
522 hTheme2
= GetWindowTheme(hWnd
);
523 ok( hTheme
== hTheme2
, "Expected the same HTHEME handle (%p<->%p)\n",
525 ok( GetLastError() == 0xdeadbeef,
526 "Expected 0xdeadbeef, got 0x%08x\n",
529 SetLastError(0xdeadbeef);
530 bTPDefined
= IsThemePartDefined(hTheme
, 0 , 0);
533 ok( bTPDefined
== FALSE
, "Expected FALSE\n");
534 ok( GetLastError() == ERROR_SUCCESS
,
535 "Expected ERROR_SUCCESS, got 0x%08x\n",
542 static void test_OpenThemeDataEx(void)
548 const WCHAR szInvalidClassList
[] = L
"DEADBEEF";
549 const WCHAR szButtonClassList
[] = L
"Button";
550 const WCHAR szButtonClassList2
[] = L
"bUtToN";
551 const WCHAR szClassList
[] = L
"Button;ListBox";
553 if (!pOpenThemeDataEx
)
555 win_skip("OpenThemeDataEx not available\n");
559 bThemeActive
= IsThemeActive();
562 SetLastError(0xdeadbeef);
563 hTheme
= pOpenThemeDataEx(NULL
, NULL
, 0);
564 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
565 ok( GetLastError() == E_POINTER
,
566 "Expected GLE() to be E_POINTER, got 0x%08x\n",
569 /* A NULL hWnd and an invalid classlist without flags */
570 SetLastError(0xdeadbeef);
571 hTheme
= pOpenThemeDataEx(NULL
, szInvalidClassList
, 0);
572 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
573 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
574 E_PROP_ID_UNSUPPORTED
, GetLastError() );
576 SetLastError(0xdeadbeef);
577 hTheme
= pOpenThemeDataEx(NULL
, szClassList
, 0);
580 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
581 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
585 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
586 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
587 E_PROP_ID_UNSUPPORTED
, GetLastError() );
590 /* Only do the bare minimum to get a valid hdc */
591 hWnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,0, 0, 0, NULL
);
594 SetLastError(0xdeadbeef);
595 hTheme
= pOpenThemeDataEx(hWnd
, NULL
, 0);
596 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
597 ok( GetLastError() == E_POINTER
,
598 "Expected GLE() to be E_POINTER, got 0x%08x\n",
601 SetLastError(0xdeadbeef);
602 hTheme
= pOpenThemeDataEx(hWnd
, szInvalidClassList
, 0);
603 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
604 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
605 E_PROP_ID_UNSUPPORTED
, GetLastError() );
609 SetLastError(0xdeadbeef);
610 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0);
611 ok( hTheme
== NULL
, "Expected a NULL return, got %p\n", hTheme
);
612 ok( GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected 0x%08x, got 0x%08x\n",
613 E_PROP_ID_UNSUPPORTED
, GetLastError() );
614 skip("No active theme, skipping rest of OpenThemeDataEx tests\n");
618 /* Only do the next checks if we have an active theme */
620 SetLastError(0xdeadbeef);
621 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0);
622 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
623 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
625 SetLastError(0xdeadbeef);
626 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, OTD_FORCE_RECT_SIZING
);
627 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
628 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
630 SetLastError(0xdeadbeef);
631 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, OTD_NONCLIENT
);
632 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
633 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
635 SetLastError(0xdeadbeef);
636 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList
, 0x3);
637 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
638 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
640 /* Test with bUtToN instead of Button */
641 SetLastError(0xdeadbeef);
642 hTheme
= pOpenThemeDataEx(hWnd
, szButtonClassList2
, 0);
643 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
644 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
646 SetLastError(0xdeadbeef);
647 hTheme
= pOpenThemeDataEx(hWnd
, szClassList
, 0);
648 ok( hTheme
!= NULL
, "got NULL, expected a HTHEME handle\n");
649 ok( GetLastError() == ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() );
654 static void test_OpenThemeDataForDpi(void)
656 BOOL is_theme_active
;
659 if (!pOpenThemeDataForDpi
)
661 win_skip("OpenThemeDataForDpi is unavailable.\n");
665 is_theme_active
= IsThemeActive();
666 SetLastError(0xdeadbeef);
667 htheme
= pOpenThemeDataForDpi(NULL
, WC_BUTTONW
, 96);
670 ok(!!htheme
, "Got a NULL handle.\n");
671 ok(GetLastError() == NO_ERROR
, "Expected error %u, got %u.\n", NO_ERROR
, GetLastError());
672 CloseThemeData(htheme
);
676 ok(!htheme
, "Got a non-NULL handle.\n");
677 ok(GetLastError() == E_PROP_ID_UNSUPPORTED
, "Expected error %u, got %u.\n",
678 E_PROP_ID_UNSUPPORTED
, GetLastError());
682 static void test_GetCurrentThemeName(void)
686 WCHAR currentTheme
[MAX_PATH
];
687 WCHAR currentColor
[MAX_PATH
];
688 WCHAR currentSize
[MAX_PATH
];
690 bThemeActive
= IsThemeActive();
693 hRes
= GetCurrentThemeName(NULL
, 0, NULL
, 0, NULL
, 0);
695 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
697 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
699 /* Number of characters given is 0 */
700 hRes
= GetCurrentThemeName(currentTheme
, 0, NULL
, 0, NULL
, 0);
702 ok( hRes
== S_OK
|| broken(hRes
== E_FAIL
/* WinXP SP1 */), "Expected S_OK, got 0x%08x\n", hRes
);
704 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
706 hRes
= GetCurrentThemeName(currentTheme
, 2, NULL
, 0, NULL
, 0);
709 ok(hRes
== E_NOT_SUFFICIENT_BUFFER
||
710 broken(hRes
== E_FAIL
/* WinXP SP1 */),
711 "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes
);
713 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
715 /* The same is true if the number of characters is too small for Color and/or Size */
716 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
, 2,
717 currentSize
, ARRAY_SIZE(currentSize
));
720 ok(hRes
== E_NOT_SUFFICIENT_BUFFER
||
721 broken(hRes
== E_FAIL
/* WinXP SP1 */),
722 "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes
);
724 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
726 /* Given number of characters is correct */
727 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), NULL
, 0, NULL
, 0);
729 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
731 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
733 /* Given number of characters for the theme name is too large */
734 hRes
= GetCurrentThemeName(currentTheme
, sizeof(currentTheme
), NULL
, 0, NULL
, 0);
736 ok( hRes
== E_POINTER
|| hRes
== S_OK
, "Expected E_POINTER or S_OK, got 0x%08x\n", hRes
);
738 ok( hRes
== E_PROP_ID_UNSUPPORTED
||
739 hRes
== E_POINTER
, /* win2k3 */
740 "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
742 /* The too large case is only for the theme name, not for color name or size name */
743 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
744 sizeof(currentTheme
), currentSize
, ARRAY_SIZE(currentSize
));
746 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
748 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
750 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
751 ARRAY_SIZE(currentTheme
), currentSize
, sizeof(currentSize
));
753 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
755 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
758 hRes
= GetCurrentThemeName(currentTheme
, ARRAY_SIZE(currentTheme
), currentColor
,
759 ARRAY_SIZE(currentColor
), currentSize
, ARRAY_SIZE(currentSize
));
761 ok( hRes
== S_OK
, "Expected S_OK, got 0x%08x\n", hRes
);
763 ok( hRes
== E_PROP_ID_UNSUPPORTED
, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes
);
766 static void test_CloseThemeData(void)
770 hRes
= CloseThemeData(NULL
);
771 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08x\n", hRes
);
772 hRes
= CloseThemeData(INVALID_HANDLE_VALUE
);
773 ok( hRes
== E_HANDLE
, "Expected E_HANDLE, got 0x%08x\n", hRes
);
776 static void test_buffer_dc_props(HDC hdc
, const RECT
*rect
)
778 static const XFORM ident
= { 1.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
};
784 ret
= GetWorldTransform(hdc
, &xform
);
785 ok(ret
, "Failed to get world transform\n");
786 ok(!memcmp(&xform
, &ident
, sizeof(xform
)), "Unexpected world transform\n");
788 ret
= GetViewportOrgEx(hdc
, &org
);
789 ok(ret
, "Failed to get vport origin\n");
790 ok(org
.x
== 0 && org
.y
== 0, "Unexpected vport origin\n");
792 ret
= GetWindowOrgEx(hdc
, &org
);
793 ok(ret
, "Failed to get vport origin\n");
794 ok(org
.x
== rect
->left
&& org
.y
== rect
->top
, "Unexpected window origin\n");
796 ret
= GetClipBox(hdc
, &box
);
797 ok(ret
, "Failed to get clip box\n");
798 ok(box
.left
== rect
->left
&& box
.top
== rect
->top
, "Unexpected clip box\n");
800 ok(GetGraphicsMode(hdc
) == GM_COMPATIBLE
, "wrong graphics mode\n");
803 static void test_buffered_paint(void)
805 HDC target
, src
, hdc
, screen_dc
;
806 BP_PAINTPARAMS params
= { 0 };
807 BP_BUFFERFORMAT format
;
815 if (!pBeginBufferedPaint
)
817 win_skip("Buffered painting API is not supported.\n");
821 buffer
= pBeginBufferedPaint(NULL
, NULL
, BPBF_COMPATIBLEBITMAP
,
823 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
825 target
= CreateCompatibleDC(0);
826 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
828 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
830 params
.cbSize
= sizeof(params
);
831 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
833 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
835 src
= (void *)0xdeadbeef;
836 buffer
= pBeginBufferedPaint(target
, NULL
, BPBF_COMPATIBLEBITMAP
,
838 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
839 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
841 /* target rect is mandatory */
843 src
= (void *)0xdeadbeef;
844 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
846 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
847 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
849 /* inverted rectangle */
850 SetRect(&rect
, 10, 0, 5, 5);
851 src
= (void *)0xdeadbeef;
852 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
854 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
855 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
857 SetRect(&rect
, 0, 10, 5, 0);
858 src
= (void *)0xdeadbeef;
859 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
861 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
862 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
864 /* valid rectangle, no target dc */
865 SetRect(&rect
, 0, 0, 5, 5);
866 src
= (void *)0xdeadbeef;
867 buffer
= pBeginBufferedPaint(NULL
, &rect
, BPBF_COMPATIBLEBITMAP
,
869 ok(buffer
== NULL
, "Unexpected buffer %p\n", buffer
);
870 ok(src
== NULL
, "Unexpected buffered dc %p\n", src
);
872 SetRect(&rect
, 0, 0, 5, 5);
874 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
876 ok(buffer
!= NULL
, "Unexpected buffer %p\n", buffer
);
877 ok(src
!= NULL
, "Expected buffered dc\n");
878 hr
= pEndBufferedPaint(buffer
, FALSE
);
879 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
881 SetRect(&rect
, 0, 0, 5, 5);
882 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
,
884 ok(buffer
!= NULL
, "Unexpected buffer %p\n", buffer
);
887 hr
= pBufferedPaintClear(NULL
, NULL
);
889 ok(hr
== E_FAIL
, "Unexpected return code %#x\n", hr
);
891 hr
= pBufferedPaintClear(buffer
, NULL
);
893 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
895 /* access buffer attributes */
896 hdc
= pGetBufferedPaintDC(buffer
);
897 ok(hdc
== src
, "Unexpected hdc, %p, buffered dc %p\n", hdc
, src
);
899 hdc
= pGetBufferedPaintTargetDC(buffer
);
900 ok(hdc
== target
, "Unexpected target hdc %p, original %p\n", hdc
, target
);
902 hr
= pGetBufferedPaintTargetRect(NULL
, NULL
);
903 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
905 hr
= pGetBufferedPaintTargetRect(buffer
, NULL
);
906 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
908 hr
= pGetBufferedPaintTargetRect(NULL
, &rect2
);
909 ok(hr
== E_FAIL
, "Unexpected return code %#x\n", hr
);
911 SetRectEmpty(&rect2
);
912 hr
= pGetBufferedPaintTargetRect(buffer
, &rect2
);
913 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
914 ok(EqualRect(&rect
, &rect2
), "Wrong target rect\n");
916 hr
= pEndBufferedPaint(buffer
, FALSE
);
917 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
919 /* invalid buffer handle */
920 hr
= pEndBufferedPaint(NULL
, FALSE
);
921 ok(hr
== E_INVALIDARG
, "Unexpected return code %#x\n", hr
);
923 hdc
= pGetBufferedPaintDC(NULL
);
924 ok(hdc
== NULL
, "Unexpected hdc %p\n", hdc
);
926 hdc
= pGetBufferedPaintTargetDC(NULL
);
927 ok(hdc
== NULL
, "Unexpected target hdc %p\n", hdc
);
929 hr
= pGetBufferedPaintTargetRect(NULL
, &rect2
);
930 ok(hr
== E_FAIL
, "Unexpected return code %#x\n", hr
);
932 hr
= pGetBufferedPaintTargetRect(NULL
, NULL
);
933 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
935 bits
= (void *)0xdeadbeef;
937 hr
= pGetBufferedPaintBits(NULL
, &bits
, &row
);
938 ok(hr
== E_FAIL
, "Unexpected return code %#x\n", hr
);
939 ok(row
== 10, "Unexpected row count %d\n", row
);
940 ok(bits
== (void *)0xdeadbeef, "Unexpected data pointer %p\n", bits
);
942 hr
= pGetBufferedPaintBits(NULL
, NULL
, NULL
);
943 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
945 hr
= pGetBufferedPaintBits(NULL
, &bits
, NULL
);
946 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
948 hr
= pGetBufferedPaintBits(NULL
, NULL
, &row
);
949 ok(hr
== E_POINTER
, "Unexpected return code %#x\n", hr
);
951 screen_dc
= GetDC(0);
953 hdc
= CreateCompatibleDC(screen_dc
);
954 ok(hdc
!= NULL
, "Failed to create a DC\n");
955 hbm
= CreateCompatibleBitmap(screen_dc
, 64, 64);
956 ok(hbm
!= NULL
, "Failed to create a bitmap\n");
957 SelectObject(hdc
, hbm
);
959 ReleaseDC(0, screen_dc
);
961 SetRect(&rect
, 1, 2, 34, 56);
963 buffer
= pBeginBufferedPaint(hdc
, &rect
, BPBF_COMPATIBLEBITMAP
, NULL
, &src
);
964 test_buffer_dc_props(src
, &rect
);
965 hr
= pEndBufferedPaint(buffer
, FALSE
);
966 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
971 buffer
= pBeginBufferedPaint(target
, &rect
, BPBF_COMPATIBLEBITMAP
, NULL
, &src
);
972 test_buffer_dc_props(src
, &rect
);
973 hr
= pEndBufferedPaint(buffer
, FALSE
);
974 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
976 /* access buffer bits */
977 for (format
= BPBF_COMPATIBLEBITMAP
; format
<= BPBF_TOPDOWNMONODIB
; format
++)
979 buffer
= pBeginBufferedPaint(target
, &rect
, format
, ¶ms
, &src
);
981 /* only works for DIB buffers */
984 hr
= pGetBufferedPaintBits(buffer
, &bits
, &row
);
985 if (format
== BPBF_COMPATIBLEBITMAP
)
986 ok(hr
== E_FAIL
, "Unexpected return code %#x\n", hr
);
989 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
990 ok(bits
!= NULL
, "Bitmap bits %p\n", bits
);
991 ok(row
>= (rect
.right
- rect
.left
), "format %d: bitmap width %d\n", format
, row
);
994 hr
= pEndBufferedPaint(buffer
, FALSE
);
995 ok(hr
== S_OK
, "Unexpected return code %#x\n", hr
);
1001 static void test_GetThemePartSize(void)
1003 static const DWORD enabled
= 1;
1004 DPI_AWARENESS_CONTEXT old_context
;
1005 unsigned int old_dpi
, current_dpi
;
1006 HTHEME htheme
= NULL
;
1013 if (!pSetThreadDpiAwarenessContext
)
1015 win_skip("SetThreadDpiAwarenessContext is unavailable.\n");
1019 /* Set IgnorePerProcessSystemDPIToast to 1 to disable "fix blurry apps popup" on Windows 10,
1020 * which may interfere other tests because it steals focus */
1021 RegOpenKeyA(HKEY_CURRENT_USER
, "Control Panel\\Desktop", &key
);
1022 RegSetValueExA(key
, "IgnorePerProcessSystemDPIToast", 0, REG_DWORD
, (const BYTE
*)&enabled
,
1025 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
);
1026 current_dpi
= get_primary_monitor_effective_dpi();
1027 old_dpi
= current_dpi
;
1028 /* DPI needs to be 50% larger than 96 to avoid the effect of TrueSizeStretchMark */
1029 if (current_dpi
< 192 && !set_primary_monitor_effective_dpi(192))
1031 skip("Failed to set primary monitor dpi to 192.\n");
1035 hwnd
= CreateWindowA("Button", "Test", WS_POPUP
, 100, 100, 100, 100, NULL
, NULL
, NULL
, NULL
);
1036 htheme
= OpenThemeData(hwnd
, WC_BUTTONW
);
1039 skip("Theming is inactive.\n");
1044 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size
);
1045 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1046 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1047 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1048 ok(size2
.cx
== size
.cx
&& size2
.cy
== size
.cy
, "Expected size %dx%d, got %dx%d.\n",
1049 size
.cx
, size
.cy
, size2
.cx
, size2
.cy
);
1050 ReleaseDC(hwnd
, hdc
);
1052 /* Test that theme part size doesn't change even if DPI is changed */
1053 if (!set_primary_monitor_effective_dpi(96))
1055 skip("Failed to set primary monitor dpi to 96.\n");
1060 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1061 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1062 ok(size2
.cx
== size
.cx
&& size2
.cy
== size
.cy
, "Expected size %dx%d, got %dx%d.\n", size
.cx
,
1063 size
.cy
, size2
.cx
, size2
.cy
);
1064 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1065 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1066 ok(size2
.cx
== size
.cx
&& size2
.cy
== size
.cy
, "Expected size %dx%d, got %dx%d.\n", size
.cx
,
1067 size
.cy
, size2
.cx
, size2
.cy
);
1069 /* Test that theme part size changes after DPI is changed and theme handle is reopened.
1070 * If DPI awareness context is not DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, theme part size
1071 * still doesn't change, even after the theme handle is reopened. */
1072 CloseThemeData(htheme
);
1073 htheme
= OpenThemeData(hwnd
, WC_BUTTONW
);
1075 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1076 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1077 ok(size2
.cx
!= size
.cx
|| size2
.cy
!= size
.cy
, "Expected size not equal to %dx%d.\n", size
.cx
,
1079 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1080 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1081 ok(size2
.cx
!= size
.cx
|| size2
.cy
!= size
.cy
, "Expected size not equal to %dx%d.\n", size
.cx
,
1083 ReleaseDC(hwnd
, hdc
);
1085 /* Test that OpenThemeData() without a window will assume the DPI is 96 */
1086 if (!set_primary_monitor_effective_dpi(192))
1088 skip("Failed to set primary monitor dpi to 192.\n");
1092 CloseThemeData(htheme
);
1093 htheme
= OpenThemeData(NULL
, WC_BUTTONW
);
1097 hr
= GetThemePartSize(htheme
, hdc
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1098 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1099 ok(size2
.cx
== size
.cx
&& size2
.cy
== size
.cy
, "Expected size %dx%d, got %dx%d.\n", size
.cx
,
1100 size
.cy
, size2
.cx
, size2
.cy
);
1101 hr
= GetThemePartSize(htheme
, NULL
, BP_CHECKBOX
, CBS_CHECKEDNORMAL
, NULL
, TS_DRAW
, &size2
);
1102 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1103 ok(size2
.cx
== size
.cx
&& size2
.cy
== size
.cy
, "Expected size %dx%d, got %dx%d.\n", size
.cx
,
1104 size
.cy
, size2
.cx
, size2
.cy
);
1105 ReleaseDC(hwnd
, hdc
);
1109 DestroyWindow(hwnd
);
1111 CloseThemeData(htheme
);
1112 if (get_primary_monitor_effective_dpi() != old_dpi
)
1113 set_primary_monitor_effective_dpi(old_dpi
);
1116 RegDeleteValueA(key
, "IgnorePerProcessSystemDPIToast");
1119 pSetThreadDpiAwarenessContext(old_context
);
1122 static void test_EnableTheming(void)
1124 WCHAR old_color_string
[13], new_color_string
[13], color_string
[13];
1125 BOOL old_gradient_caption
, new_gradient_caption
, gradient_caption
;
1126 BOOL old_flat_menu
, new_flat_menu
, flat_menu
;
1127 LOGFONTW old_logfont
, new_logfont
, logfont
;
1128 NONCLIENTMETRICSW old_ncm
, new_ncm
, ncm
;
1129 DPI_AWARENESS_CONTEXT old_context
= 0;
1130 COLORREF old_color
, new_color
;
1131 BOOL is_theme_active
, ret
;
1137 if (IsThemeActive())
1139 hr
= EnableTheming(TRUE
);
1140 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1141 ok(IsThemeActive(), "Expected theming active.\n");
1143 /* Only run in interactive mode because once theming is disabled, it can't be turned back on
1144 * via EnableTheming() */
1145 if (winetest_interactive
)
1147 if (pSetThreadDpiAwarenessContext
)
1149 old_context
= pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
1151 else if (get_primary_monitor_effective_dpi() != 96)
1153 skip("DPI isn't 96, skipping.\n");
1157 /* Read current system metrics */
1158 old_color
= GetSysColor(COLOR_SCROLLBAR
);
1159 swprintf(old_color_string
, ARRAY_SIZE(old_color_string
), L
"%d %d %d",
1160 GetRValue(old_color
), GetGValue(old_color
), GetBValue(old_color
));
1162 memset(&old_ncm
, 0, sizeof(old_ncm
));
1163 old_ncm
.cbSize
= FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
);
1164 ret
= SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(old_ncm
), &old_ncm
, 0);
1165 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1167 memset(&old_logfont
, 0, sizeof(old_logfont
));
1168 ret
= SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, sizeof(old_logfont
), &old_logfont
, 0);
1169 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1170 ret
= SystemParametersInfoW(SPI_GETFLATMENU
, 0, &old_flat_menu
, 0);
1171 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1172 ret
= SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS
, 0, &old_gradient_caption
, 0);
1173 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1175 /* Write new system metrics to the registry */
1176 new_color
= ~old_color
;
1177 new_flat_menu
= !old_flat_menu
;
1178 new_gradient_caption
= !old_gradient_caption
;
1179 memcpy(&new_ncm
, &old_ncm
, sizeof(new_ncm
));
1180 new_ncm
.iScrollWidth
+= 5;
1181 memcpy(&new_logfont
, &old_logfont
, sizeof(new_logfont
));
1182 new_logfont
.lfWidth
+= 5;
1184 ls
= RegOpenKeyExW(HKEY_CURRENT_USER
, L
"Control Panel\\Colors", 0, KEY_ALL_ACCESS
,
1186 ok(!ls
, "RegOpenKeyExW failed, ls %#x.\n", ls
);
1188 length
= swprintf(new_color_string
, ARRAY_SIZE(new_color_string
), L
"%d %d %d",
1189 GetRValue(new_color
), GetGValue(new_color
), GetBValue(new_color
));
1190 ls
= RegSetValueExW(hkey
, L
"Scrollbar", 0, REG_SZ
, (BYTE
*)new_color_string
,
1191 (length
+ 1) * sizeof(WCHAR
));
1192 ok(!ls
, "RegSetValueExW failed, ls %#x.\n", ls
);
1194 ret
= SystemParametersInfoW(SPI_SETNONCLIENTMETRICS
, sizeof(new_ncm
), &new_ncm
,
1195 SPIF_UPDATEINIFILE
);
1196 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1197 ret
= SystemParametersInfoW(SPI_SETICONTITLELOGFONT
, sizeof(new_logfont
), &new_logfont
,
1198 SPIF_UPDATEINIFILE
);
1199 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1200 ret
= SystemParametersInfoW(SPI_SETFLATMENU
, 0, (void *)(INT_PTR
)new_flat_menu
,
1201 SPIF_UPDATEINIFILE
);
1202 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1203 ret
= SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS
, 0,
1204 (void *)(INT_PTR
)new_gradient_caption
, SPIF_UPDATEINIFILE
);
1205 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1207 /* Change theming state */
1208 hr
= EnableTheming(FALSE
);
1209 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1210 is_theme_active
= IsThemeActive();
1211 ok(!is_theme_active
|| broken(is_theme_active
), /* Win8+ can no longer disable theming */
1212 "Expected theming inactive.\n");
1214 /* Test that system metrics are unchanged */
1215 size
= sizeof(color_string
);
1216 ls
= RegQueryValueExW(hkey
, L
"Scrollbar", NULL
, NULL
, (BYTE
*)color_string
, &size
);
1217 ok(!ls
, "RegQueryValueExW failed, ls %#x.\n", ls
);
1218 ok(!lstrcmpW(color_string
, new_color_string
), "Expected %s, got %s.\n",
1219 wine_dbgstr_w(new_color_string
), wine_dbgstr_w(color_string
));
1221 ret
= SystemParametersInfoW(SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1222 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1223 ok(flat_menu
== new_flat_menu
, "Expected %d, got %d.\n", new_flat_menu
, flat_menu
);
1224 ret
= SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS
, 0, &gradient_caption
, 0);
1225 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1226 ok(gradient_caption
== new_gradient_caption
, "Expected %d, got %d.\n",
1227 new_gradient_caption
, gradient_caption
);
1229 memset(&ncm
, 0, sizeof(ncm
));
1230 ncm
.cbSize
= FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
);
1231 ret
= SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0);
1232 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1233 ok(!memcmp(&ncm
, &new_ncm
, sizeof(ncm
)), "Expected non-client metrics unchanged.\n");
1235 memset(&logfont
, 0, sizeof(logfont
));
1236 ret
= SystemParametersInfoW(SPI_GETICONTITLELOGFONT
, sizeof(logfont
), &logfont
, 0);
1237 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1238 ok(!memcmp(&logfont
, &new_logfont
, sizeof(logfont
)),
1239 "Expected icon title font unchanged.\n");
1241 /* Test that theming cannot be turned on via EnableTheming() */
1242 hr
= EnableTheming(TRUE
);
1243 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1244 is_theme_active
= IsThemeActive();
1245 ok(!is_theme_active
|| broken(is_theme_active
), /* Win8+ can no longer disable theming */
1246 "Expected theming inactive.\n");
1248 /* Restore system metrics */
1249 ls
= RegSetValueExW(hkey
, L
"Scrollbar", 0, REG_SZ
, (BYTE
*)old_color_string
,
1250 (lstrlenW(old_color_string
) + 1) * sizeof(WCHAR
));
1251 ok(!ls
, "RegSetValueExW failed, ls %#x.\n", ls
);
1252 ret
= SystemParametersInfoW(SPI_SETFLATMENU
, 0, (void *)(INT_PTR
)old_flat_menu
,
1253 SPIF_UPDATEINIFILE
);
1254 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1255 ret
= SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS
, 0,
1256 (void *)(INT_PTR
)old_gradient_caption
, SPIF_UPDATEINIFILE
);
1257 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1258 ret
= SystemParametersInfoW(SPI_SETNONCLIENTMETRICS
, sizeof(old_ncm
), &old_ncm
,
1259 SPIF_UPDATEINIFILE
);
1260 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1261 ret
= SystemParametersInfoW(SPI_SETICONTITLELOGFONT
, sizeof(old_logfont
), &old_logfont
,
1262 SPIF_UPDATEINIFILE
);
1263 ok(ret
, "SystemParametersInfoW failed, error %u.\n", GetLastError());
1266 if (pSetThreadDpiAwarenessContext
)
1267 pSetThreadDpiAwarenessContext(old_context
);
1272 hr
= EnableTheming(FALSE
);
1273 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1274 ok(!IsThemeActive(), "Expected theming inactive.\n");
1276 hr
= EnableTheming(TRUE
);
1277 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1278 ok(!IsThemeActive(), "Expected theming inactive.\n");
1280 hr
= EnableTheming(FALSE
);
1281 ok(hr
== S_OK
, "EnableTheming failed, hr %#x.\n", hr
);
1282 ok(!IsThemeActive(), "Expected theming inactive.\n");
1286 static void test_GetThemeIntList(void)
1293 if (!pGetThemeIntList
)
1295 win_skip("GetThemeIntList is unavailable.\n");
1299 hwnd
= CreateWindowA("static", "", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
1300 theme
= OpenThemeData(hwnd
, L
"Button");
1303 skip("Theming is not active.\n");
1304 DestroyWindow(hwnd
);
1308 /* Check properties */
1309 /* TMT_TRANSITIONDURATIONS is a vista+ property */
1310 hr
= pGetThemeIntList(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1311 if (LOBYTE(LOWORD(GetVersion())) < 6)
1312 ok(hr
== E_PROP_ID_UNSUPPORTED
, "Expected %#x, got %#x.\n", E_PROP_ID_UNSUPPORTED
, hr
);
1314 ok(hr
== S_OK
, "GetThemeIntList failed, hr %#x.\n", hr
);
1316 CloseThemeData(theme
);
1317 DestroyWindow(hwnd
);
1320 static void test_GetThemeTransitionDuration(void)
1322 int from_state
, to_state
, expected
;
1329 if (!pGetThemeTransitionDuration
|| !pGetThemeIntList
)
1331 win_skip("GetThemeTransitionDuration or GetThemeIntList is unavailable.\n");
1335 hwnd
= CreateWindowA("static", "", WS_POPUP
, 0, 0, 100, 100, 0, 0, 0, NULL
);
1336 theme
= OpenThemeData(hwnd
, L
"Button");
1339 skip("Theming is not active.\n");
1340 DestroyWindow(hwnd
);
1344 /* Invalid parameter tests */
1345 duration
= 0xdeadbeef;
1346 hr
= pGetThemeTransitionDuration(NULL
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1347 TMT_TRANSITIONDURATIONS
, &duration
);
1348 ok(hr
== E_HANDLE
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1349 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#x.\n", 0xdeadbeef, duration
);
1351 /* Crash on Wine. HTHEME is not a pointer that can be directly referenced. */
1352 if (strcmp(winetest_platform
, "wine"))
1354 duration
= 0xdeadbeef;
1355 hr
= pGetThemeTransitionDuration((HTHEME
)0xdeadbeef, BP_PUSHBUTTON
, PBS_NORMAL
,
1356 PBS_DEFAULTED_ANIMATING
, TMT_TRANSITIONDURATIONS
, &duration
);
1358 ok(hr
== E_HANDLE
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1359 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#x.\n", 0xdeadbeef, duration
);
1362 duration
= 0xdeadbeef;
1363 hr
= pGetThemeTransitionDuration(theme
, 0xdeadbeef, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1364 TMT_TRANSITIONDURATIONS
, &duration
);
1365 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1366 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1368 duration
= 0xdeadbeef;
1369 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
- 1, PBS_DEFAULTED_ANIMATING
,
1370 TMT_TRANSITIONDURATIONS
, &duration
);
1371 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1372 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#x.\n", 0xdeadbeef, duration
);
1374 duration
= 0xdeadbeef;
1375 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_DEFAULTED_ANIMATING
+ 1,
1376 PBS_DEFAULTED_ANIMATING
, TMT_TRANSITIONDURATIONS
, &duration
);
1377 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1378 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1380 duration
= 0xdeadbeef;
1381 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_NORMAL
- 1,
1382 TMT_TRANSITIONDURATIONS
, &duration
);
1383 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1384 ok(duration
== 0xdeadbeef, "Expected duration %#x, got %#x.\n", 0xdeadbeef, duration
);
1386 duration
= 0xdeadbeef;
1387 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
+ 1,
1388 TMT_TRANSITIONDURATIONS
, &duration
);
1389 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1390 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1392 duration
= 0xdeadbeef;
1393 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1394 TMT_BACKGROUND
, &duration
);
1395 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1396 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1398 duration
= 0xdeadbeef;
1399 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1400 0xdeadbeef, &duration
);
1401 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1402 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1404 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, PBS_DEFAULTED_ANIMATING
,
1405 TMT_TRANSITIONDURATIONS
, NULL
);
1406 ok(hr
== E_INVALIDARG
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1408 /* Parts that don't have TMT_TRANSITIONDURATIONS */
1409 hr
= GetThemeIntList(theme
, BP_GROUPBOX
, GBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1410 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeIntList failed, hr %#x.\n", hr
);
1412 duration
= 0xdeadbeef;
1413 hr
= pGetThemeTransitionDuration(theme
, BP_GROUPBOX
, GBS_NORMAL
, GBS_DISABLED
,
1414 TMT_TRANSITIONDURATIONS
, &duration
);
1415 ok(hr
== E_PROP_ID_UNSUPPORTED
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1416 ok(duration
== 0, "Expected duration %#x, got %#x.\n", 0, duration
);
1418 /* Test parsing TMT_TRANSITIONDURATIONS property. TMT_TRANSITIONDURATIONS is a vista+ property */
1419 if (LOBYTE(LOWORD(GetVersion())) < 6)
1422 hr
= pGetThemeIntList(theme
, BP_PUSHBUTTON
, PBS_NORMAL
, TMT_TRANSITIONDURATIONS
, &intlist
);
1423 ok(hr
== S_OK
, "GetThemeIntList failed, hr %#x.\n", hr
);
1424 /* The first value is the theme part state count. The following are the values from every state
1425 * to every state. So the total value count should be 1 + state ^ 2 */
1426 expected
= PBS_DEFAULTED_ANIMATING
- PBS_NORMAL
+ 1;
1427 ok(intlist
.iValues
[0] == expected
, "Expected the first value %d, got %d.\n", expected
,
1428 intlist
.iValues
[0]);
1429 expected
= 1 + intlist
.iValues
[0] * intlist
.iValues
[0];
1430 ok(intlist
.iValueCount
== expected
, "Expected value count %d, got %d.\n", expected
,
1431 intlist
.iValueCount
);
1434 for (from_state
= PBS_NORMAL
; from_state
<= PBS_DEFAULTED_ANIMATING
; ++from_state
)
1436 for (to_state
= PBS_NORMAL
; to_state
<= PBS_DEFAULTED_ANIMATING
; ++to_state
)
1438 winetest_push_context("from state %d to %d", from_state
, to_state
);
1440 duration
= 0xdeadbeef;
1441 hr
= pGetThemeTransitionDuration(theme
, BP_PUSHBUTTON
, from_state
, to_state
,
1442 TMT_TRANSITIONDURATIONS
, &duration
);
1443 ok(hr
== S_OK
, "GetThemeTransitionDuration failed, hr %#x.\n", hr
);
1444 expected
= intlist
.iValues
[1 + intlist
.iValues
[0] * (from_state
- 1) + (to_state
- 1)];
1445 ok(duration
== expected
, "Expected duration %d, got %d.\n", expected
, duration
);
1447 winetest_pop_context();
1453 CloseThemeData(theme
);
1454 DestroyWindow(hwnd
);
1457 static const struct message DrawThemeParentBackground_seq
[] =
1459 {WM_ERASEBKGND
, sent
},
1460 {WM_PRINTCLIENT
, sent
| lparam
, 0, PRF_CLIENT
},
1464 static LRESULT WINAPI
test_DrawThemeParentBackground_proc(HWND hwnd
, UINT message
, WPARAM wp
,
1467 static LONG defwndproc_counter
;
1468 struct message msg
= {0};
1475 /* Test that DrawThemeParentBackground() doesn't change brush origins */
1477 case WM_PRINTCLIENT
:
1478 ret
= GetBrushOrgEx((HDC
)wp
, &org
);
1479 ok(ret
, "GetBrushOrgEx failed, error %d.\n", GetLastError());
1480 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1487 msg
.message
= message
;
1488 msg
.flags
= sent
| wparam
| lparam
;
1489 if (defwndproc_counter
)
1490 msg
.flags
|= defwinproc
;
1493 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
1495 InterlockedIncrement(&defwndproc_counter
);
1496 lr
= DefWindowProcA(hwnd
, message
, wp
, lp
);
1497 InterlockedDecrement(&defwndproc_counter
);
1501 static void test_DrawThemeParentBackground(void)
1511 memset(&cls
, 0, sizeof(cls
));
1512 cls
.hInstance
= GetModuleHandleA(0);
1513 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1514 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
1515 cls
.lpfnWndProc
= test_DrawThemeParentBackground_proc
;
1516 cls
.lpszClassName
= "TestDrawThemeParentBackgroundClass";
1517 RegisterClassA(&cls
);
1519 parent
= CreateWindowA("TestDrawThemeParentBackgroundClass", "parent", WS_POPUP
| WS_VISIBLE
, 0,
1520 0, 100, 100, 0, 0, 0, 0);
1521 ok(parent
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
1522 child
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 1, 2, 50, 50, parent
, 0, 0,
1524 ok(child
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
1526 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1529 ret
= GetBrushOrgEx(hdc
, &org
);
1530 ok(ret
, "GetBrushOrgEx failed, error %d.\n", GetLastError());
1531 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1533 hr
= DrawThemeParentBackground(child
, hdc
, NULL
);
1534 ok(SUCCEEDED(hr
), "DrawThemeParentBackground failed, hr %#x.\n", hr
);
1535 ok_sequence(sequences
, PARENT_SEQ_INDEX
, DrawThemeParentBackground_seq
,
1536 "DrawThemeParentBackground parent", FALSE
);
1537 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1539 GetClientRect(child
, &rect
);
1540 hr
= DrawThemeParentBackground(child
, hdc
, &rect
);
1541 ok(SUCCEEDED(hr
), "DrawThemeParentBackground failed, hr %#x.\n", hr
);
1542 ok_sequence(sequences
, PARENT_SEQ_INDEX
, DrawThemeParentBackground_seq
,
1543 "DrawThemeParentBackground parent", FALSE
);
1544 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1546 ReleaseDC(child
, hdc
);
1547 DestroyWindow(parent
);
1548 UnregisterClassA("TestDrawThemeParentBackgroundClass", GetModuleHandleA(0));
1551 struct test_EnableThemeDialogTexture_param
1553 const CHAR
*class_name
;
1557 static const struct message empty_seq
[] =
1562 static HWND dialog_child
;
1563 static DWORD dialog_init_flag
;
1564 static BOOL handle_WM_CTLCOLORSTATIC
;
1566 static INT_PTR CALLBACK
test_EnableThemeDialogTexture_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1568 struct test_EnableThemeDialogTexture_param
*param
;
1569 struct message message
= {0};
1571 message
.message
= msg
;
1572 message
.flags
= sent
| wparam
| lparam
;
1573 message
.wParam
= wp
;
1574 message
.lParam
= lp
;
1575 add_message(sequences
, PARENT_SEQ_INDEX
, &message
);
1580 param
= (struct test_EnableThemeDialogTexture_param
*)lp
;
1581 dialog_child
= CreateWindowA(param
->class_name
, "child",
1582 param
->style
| WS_CHILD
| WS_VISIBLE
, 1, 2, 50, 50, hwnd
,
1583 (HMENU
)100, 0, NULL
);
1584 ok(dialog_child
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
1585 if (dialog_init_flag
)
1586 EnableThemeDialogTexture(hwnd
, dialog_init_flag
);
1589 case WM_CTLCOLORSTATIC
:
1590 return (INT_PTR
)(handle_WM_CTLCOLORSTATIC
? GetSysColorBrush(COLOR_MENU
) : 0);
1593 DestroyWindow(dialog_child
);
1594 dialog_child
= NULL
;
1602 static void test_EnableThemeDialogTexture(void)
1604 struct test_EnableThemeDialogTexture_param param
;
1605 HWND dialog
, child
, hwnd
, hwnd2
;
1606 int mode
, old_mode
, count
, i
, j
;
1607 COLORREF color
, old_color
;
1608 HBRUSH brush
, brush2
;
1624 DLGTEMPLATE
template;
1630 static const DWORD flags
[] =
1635 ETDT_USEAEROWIZARDTABTEXTURE
,
1637 ETDT_ENABLEAEROWIZARDTAB
,
1640 ETDT_DISABLE
| ETDT_ENABLE
,
1641 ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
1644 static const struct invalid_flag_test
1649 invalid_flag_tests
[] =
1652 {ETDT_DISABLE
| ETDT_ENABLE
, FALSE
},
1653 {ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
, TRUE
},
1654 {ETDT_USETABTEXTURE
| ETDT_USEAEROWIZARDTABTEXTURE
, TRUE
},
1655 {ETDT_VALIDBITS
, FALSE
},
1656 {~ETDT_VALIDBITS
, FALSE
},
1657 {~ETDT_VALIDBITS
| ETDT_DISABLE
, FALSE
}
1660 static const struct class_test
1662 struct test_EnableThemeDialogTexture_param param
;
1663 BOOL texture_enabled
;
1668 {{WC_BUTTONA
, BS_PUSHBUTTON
}, TRUE
},
1669 {{WC_BUTTONA
, BS_DEFPUSHBUTTON
}, TRUE
},
1670 {{WC_BUTTONA
, BS_CHECKBOX
}, TRUE
},
1671 {{WC_BUTTONA
, BS_AUTOCHECKBOX
}, TRUE
},
1672 {{WC_BUTTONA
, BS_RADIOBUTTON
}, TRUE
},
1673 {{WC_BUTTONA
, BS_3STATE
}, TRUE
},
1674 {{WC_BUTTONA
, BS_AUTO3STATE
}, TRUE
},
1675 {{WC_BUTTONA
, BS_GROUPBOX
}, TRUE
},
1676 {{WC_BUTTONA
, BS_USERBUTTON
}, TRUE
},
1677 {{WC_BUTTONA
, BS_AUTORADIOBUTTON
}, TRUE
},
1678 {{WC_BUTTONA
, BS_PUSHBOX
}, TRUE
},
1679 {{WC_BUTTONA
, BS_OWNERDRAW
}, TRUE
},
1680 {{WC_BUTTONA
, BS_SPLITBUTTON
}, TRUE
},
1681 {{WC_BUTTONA
, BS_DEFSPLITBUTTON
}, TRUE
},
1682 {{WC_BUTTONA
, BS_COMMANDLINK
}, TRUE
},
1683 {{WC_BUTTONA
, BS_DEFCOMMANDLINK
}, TRUE
},
1686 {{DATETIMEPICK_CLASSA
}},
1693 {{MONTHCAL_CLASSA
}},
1694 {{WC_NATIVEFONTCTLA
}},
1695 {{WC_PAGESCROLLERA
}},
1696 {{PROGRESS_CLASSA
}},
1697 {{REBARCLASSNAMEA
}},
1698 {{WC_STATICA
, SS_LEFT
}, TRUE
},
1699 {{WC_STATICA
, SS_ICON
}, TRUE
},
1700 {{WC_STATICA
, SS_BLACKRECT
}, TRUE
},
1701 {{WC_STATICA
, SS_OWNERDRAW
}, TRUE
},
1702 {{WC_STATICA
, SS_BITMAP
}, TRUE
},
1703 {{WC_STATICA
, SS_ENHMETAFILE
}, TRUE
},
1704 {{WC_STATICA
, SS_ETCHEDHORZ
}, TRUE
},
1705 {{STATUSCLASSNAMEA
}},
1708 {{TOOLBARCLASSNAMEA
}},
1709 {{TOOLTIPS_CLASSA
}},
1710 {{TRACKBAR_CLASSA
}},
1716 if (!IsThemeActive())
1718 skip("Theming is inactive.\n");
1722 memset(&cls
, 0, sizeof(cls
));
1723 cls
.lpfnWndProc
= DefWindowProcA
;
1724 cls
.hInstance
= GetModuleHandleA(NULL
);
1725 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
1726 cls
.hbrBackground
= GetStockObject(GRAY_BRUSH
);
1727 cls
.lpszClassName
= "TestEnableThemeDialogTextureClass";
1728 RegisterClassA(&cls
);
1730 temp
.template.style
= WS_CHILD
| WS_VISIBLE
;
1731 temp
.template.cx
= 100;
1732 temp
.template.cy
= 100;
1733 param
.class_name
= cls
.lpszClassName
;
1735 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
1736 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
1737 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
1738 child
= GetDlgItem(dialog
, 100);
1739 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
1740 child_hdc
= GetDC(child
);
1742 /* Test that dialog procedure is unchanged */
1743 proc
= GetWindowLongPtrA(dialog
, DWLP_DLGPROC
);
1744 ok(proc
== (ULONG_PTR
)test_EnableThemeDialogTexture_proc
, "Unexpected proc %#lx.\n", proc
);
1746 /* Test dialog texture is disabled by default. EnableThemeDialogTexture() needs to be called */
1747 ret
= IsThemeDialogTextureEnabled(dialog
);
1748 ok(!ret
, "Expected theme dialog texture disabled.\n");
1749 ok(GetWindowTheme(dialog
) == NULL
, "Expected NULL theme handle.\n");
1751 /* Test ETDT_ENABLE | ETDT_USETABTEXTURE doesn't take effect immediately */
1752 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USETABTEXTURE
);
1753 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1754 ret
= IsThemeDialogTextureEnabled(dialog
);
1755 ok(ret
, "Expected theme dialog texture enabled.\n");
1757 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1758 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1759 GetSysColorBrush(COLOR_BTNFACE
), brush
);
1760 ret
= GetBrushOrgEx(child_hdc
, &org
);
1761 ok(ret
, "GetBrushOrgEx failed, error %u.\n", GetLastError());
1762 ok(org
.x
== 0 && org
.y
== 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org
));
1764 /* Test WM_THEMECHANGED doesn't make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
1765 lr
= SendMessageA(dialog
, WM_THEMECHANGED
, 0, 0);
1766 ok(lr
== 0, "WM_THEMECHANGED failed.\n");
1767 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1768 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1769 GetSysColorBrush(COLOR_BTNFACE
), brush
);
1771 /* Test WM_ERASEBKGND make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
1772 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
1773 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
1774 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1775 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected brush changed.\n");
1777 /* Test disabling theme dialog texture should change the brush immediately */
1778 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1779 hr
= EnableThemeDialogTexture(dialog
, ETDT_DISABLE
);
1780 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1781 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1782 ok(brush2
!= brush
, "Expected a different brush.\n");
1783 ok(brush2
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1784 GetSysColorBrush(COLOR_BTNFACE
), brush2
);
1786 /* Test re-enabling theme dialog texture with ETDT_ENABLE doesn't change the brush */
1787 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1788 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
);
1789 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1790 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1791 ok(brush2
== brush
, "Expected the same brush.\n");
1792 ok(brush2
== GetSysColorBrush(COLOR_BTNFACE
), "Expected brush %p, got %p.\n",
1793 GetSysColorBrush(COLOR_BTNFACE
), brush2
);
1795 /* Test adding ETDT_USETABTEXTURE should change the brush immediately */
1796 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1797 hr
= EnableThemeDialogTexture(dialog
, ETDT_USETABTEXTURE
);
1798 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1799 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1800 ok(brush2
!= brush
, "Expected a different brush.\n");
1802 /* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush immediately */
1803 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1804 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USEAEROWIZARDTABTEXTURE
);
1805 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1806 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1807 /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
1808 if (LOBYTE(LOWORD(GetVersion())) < 6)
1809 ok(brush2
== brush
, "Expected the same brush.\n");
1811 ok(brush2
!= brush
, "Expected a different brush.\n");
1813 hr
= EnableThemeDialogTexture(dialog
, ETDT_DISABLE
);
1814 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1815 hr
= EnableThemeDialogTexture(dialog
, ETDT_ENABLE
| ETDT_USETABTEXTURE
);
1816 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1818 /* Test that the dialog procedure should take precedence over DefDlgProc() for WM_CTLCOLORSTATIC */
1819 handle_WM_CTLCOLORSTATIC
= TRUE
;
1820 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1821 ok(brush
== GetSysColorBrush(COLOR_MENU
), "Expected brush %p, got %p.\n",
1822 GetSysColorBrush(COLOR_MENU
), brush
);
1823 handle_WM_CTLCOLORSTATIC
= FALSE
;
1825 /* Test that WM_CTLCOLORSTATIC changes brush origin when dialog texture is on */
1826 ret
= SetBrushOrgEx(child_hdc
, 0, 0, NULL
);
1827 ok(ret
, "SetBrushOrgEx failed, error %u.\n", GetLastError());
1828 SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1829 ret
= GetBrushOrgEx(child_hdc
, &org
);
1830 ok(ret
, "GetBrushOrgEx failed, error %u.\n", GetLastError());
1831 ok(org
.x
== -1 && org
.y
== -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org
));
1833 /* Test that WM_CTLCOLORSTATIC changes background mode when dialog texture is on */
1834 old_mode
= SetBkMode(child_hdc
, OPAQUE
);
1835 ok(old_mode
!= 0, "SetBkMode failed.\n");
1836 SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1837 mode
= SetBkMode(child_hdc
, old_mode
);
1838 ok(mode
== TRANSPARENT
, "Expected mode %#x, got %#x.\n", TRANSPARENT
, mode
);
1840 /* Test that WM_CTLCOLORSTATIC changes background color when dialog texture is on */
1841 old_color
= SetBkColor(child_hdc
, 0xaa5511);
1842 ok(old_color
!= CLR_INVALID
, "SetBkColor failed.\n");
1843 SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1844 color
= SetBkColor(child_hdc
, old_color
);
1845 ok(color
== GetSysColor(COLOR_BTNFACE
), "Expected background color %#x, got %#x.\n",
1846 GetSysColor(COLOR_BTNFACE
), color
);
1848 /* Test that dialog doesn't have theme handle opened for itself */
1849 ok(GetWindowTheme(dialog
) == NULL
, "Expected NULL theme handle.\n");
1851 /* Test that the returned brush is a pattern brush created from the tab body */
1852 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1853 memset(&log_brush
, 0, sizeof(log_brush
));
1854 count
= GetObjectA(brush
, sizeof(log_brush
), &log_brush
);
1855 ok(count
== sizeof(log_brush
), "GetObjectA failed, error %u.\n", GetLastError());
1856 ok(log_brush
.lbColor
== 0, "Expected brush color %#x, got %#x.\n", 0, log_brush
.lbColor
);
1857 ok(log_brush
.lbStyle
== BS_PATTERN
, "Expected brush style %#x, got %#x.\n", BS_PATTERN
,
1860 memset(&bmp
, 0, sizeof(bmp
));
1861 count
= GetObjectA((HBITMAP
)log_brush
.lbHatch
, sizeof(bmp
), &bmp
);
1862 ok(count
== sizeof(bmp
), "GetObjectA failed, error %u.\n", GetLastError());
1864 theme
= OpenThemeData(NULL
, L
"Tab");
1865 ok(theme
!= NULL
, "OpenThemeData failed.\n");
1869 hr
= GetThemePartSize(theme
, NULL
, TABP_BODY
, 0, NULL
, TS_TRUE
, &size
);
1870 ok(hr
== S_OK
, "GetThemePartSize failed, hr %#x.\n", hr
);
1871 ok(bmp
.bmWidth
== size
.cx
, "Expected width %d, got %d.\n", size
.cx
, bmp
.bmWidth
);
1872 ok(bmp
.bmHeight
== size
.cy
, "Expected height %d, got %d.\n", size
.cy
, bmp
.bmHeight
);
1874 CloseThemeData(theme
);
1876 /* Test that DefDlgProcA/W() are hooked for WM_CTLCOLORSTATIC */
1877 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1878 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
1879 brush2
= (HBRUSH
)DefDlgProcW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1880 ok(brush2
== brush
, "Expected the same brush.\n");
1881 brush2
= (HBRUSH
)DefDlgProcA(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1882 ok(brush2
== brush
, "Expected the same brush.\n");
1884 /* Test that DefWindowProcA/W() are also hooked for WM_CTLCOLORSTATIC */
1885 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1886 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
1887 brush2
= (HBRUSH
)DefWindowProcW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1889 ok(brush2
== brush
, "Expected the same brush.\n");
1890 brush2
= (HBRUSH
)DefWindowProcA(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1892 ok(brush2
== brush
, "Expected the same brush.\n");
1894 /* Test that DefWindowProcA/W() are not hooked for WM_ERASEBKGND. So the background is still
1895 * drawn with hbrBackground, which in this case, is GRAY_BRUSH.
1897 * This test means it could be that both DefWindowProc() and DefDlgProc() are hooked for
1898 * WM_CTLCOLORSTATIC and only DefDlgProc() is hooked for WM_ERASEBKGND. Or it could mean
1899 * DefWindowProc() is hooked for WM_CTLCOLORSTATIC and DefDlgProc() is hooked for WM_ERASEBKGND.
1900 * Considering the dialog theming needs a WM_ERASEBKGND to activate, it would be weird for let
1901 * only DefWindowProc() to hook WM_CTLCOLORSTATIC. For example, what's the point of hooking
1902 * WM_CTLCOLORSTATIC in DefWindowProc() for a feature that can only be activated in
1903 * DefDlgProc()? So I tend to believe both DefWindowProc() and DefDlgProc() are hooked for
1904 * WM_CTLCOLORSTATIC */
1905 hwnd
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 0, 0, 100, 100, 0, 0,
1907 ok(hwnd
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
1908 hwnd2
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 10, 10, 20, 20, hwnd
, NULL
, 0,
1910 hr
= EnableThemeDialogTexture(hwnd
, ETDT_ENABLETAB
);
1911 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1912 ret
= IsThemeDialogTextureEnabled(hwnd
);
1913 ok(ret
, "Wrong dialog texture status.\n");
1917 color
= GetPixel(hdc
, 0, 0);
1918 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
1919 "Expected color %#x, got %#x.\n", 0x808080, color
);
1920 color
= GetPixel(hdc
, 50, 50);
1921 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
1922 "Expected color %#x, got %#x.\n", 0x808080, color
);
1923 color
= GetPixel(hdc
, 99, 99);
1924 ok(color
== 0x808080 || broken(color
== 0xffffffff), /* Win 7 may report 0xffffffff */
1925 "Expected color %#x, got %#x.\n", 0x808080, color
);
1926 ReleaseDC(hwnd
, hdc
);
1928 /* Test EnableThemeDialogTexture() doesn't work for non-dialog windows */
1930 brush
= (HBRUSH
)SendMessageW(hwnd
, WM_CTLCOLORSTATIC
, (WPARAM
)hdc
, (LPARAM
)hwnd2
);
1931 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected a different brush.\n");
1932 ReleaseDC(hwnd2
, hdc
);
1934 DestroyWindow(hwnd
);
1936 /* Test that the brush is not a system object and has only one reference and shouldn't be freed */
1937 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1938 ret
= DeleteObject(brush
);
1939 ok(ret
, "DeleteObject failed, error %u.\n", GetLastError());
1940 SetLastError(0xdeadbeef);
1941 ret
= GetObjectA(brush
, sizeof(log_brush
), &log_brush
);
1942 error
= GetLastError();
1943 ok(!ret
|| broken(ret
) /* XP */, "GetObjectA succeeded.\n");
1945 ok(error
== ERROR_INVALID_PARAMETER
|| broken(error
== 0xdeadbeef) /* XP */,
1946 "Expected error %u, got %u.\n", ERROR_INVALID_PARAMETER
, error
);
1947 ret
= DeleteObject(brush
);
1948 ok(!ret
|| broken(ret
) /* XP */, "DeleteObject succeeded.\n");
1950 /* Should still report the same brush handle after the brush handle was freed */
1951 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1952 ok(brush2
== brush
, "Expected the same brush.\n");
1954 /* Test WM_THEMECHANGED can update the brush now that ETDT_ENABLE | ETDT_USETABTEXTURE is in
1955 * effect. This test needs to be ran last as it affect other tests for the same dialog for
1956 * unknown reason, causing the brush not to update */
1957 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1958 lr
= SendMessageA(dialog
, WM_THEMECHANGED
, 0, 0);
1959 ok(lr
== 0, "WM_THEMECHANGED failed.\n");
1960 brush2
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
1961 ok(brush2
!= brush
, "Expected a different brush.\n");
1963 ReleaseDC(child
, child_hdc
);
1964 EndDialog(dialog
, 0);
1966 /* Test invalid flags */
1967 for (i
= 0; i
< ARRAY_SIZE(invalid_flag_tests
); ++i
)
1969 winetest_push_context("%d flag %#x", i
, invalid_flag_tests
[i
].flag
);
1971 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
1972 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
1973 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
1974 hr
= EnableThemeDialogTexture(dialog
, invalid_flag_tests
[i
].flag
);
1975 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
1976 ret
= IsThemeDialogTextureEnabled(dialog
);
1977 ok(ret
== invalid_flag_tests
[i
].enabled
, "Wrong dialog texture status.\n");
1978 EndDialog(dialog
, 0);
1980 winetest_pop_context();
1983 /* Test different flag combinations */
1984 for (i
= 0; i
< ARRAY_SIZE(flags
); ++i
)
1986 for (j
= 0; j
< ARRAY_SIZE(flags
); ++j
)
1988 /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
1989 if (LOBYTE(LOWORD(GetVersion())) < 6
1990 && ((flags
[i
] | flags
[j
]) & ETDT_USEAEROWIZARDTABTEXTURE
))
1993 winetest_push_context("%#x to %#x", flags
[i
], flags
[j
]);
1995 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
1996 test_EnableThemeDialogTexture_proc
, (LPARAM
)¶m
);
1997 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
1999 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2001 hr
= EnableThemeDialogTexture(dialog
, flags
[i
]);
2002 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
2003 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2004 "EnableThemeDialogTexture first flag", FALSE
);
2005 ret
= IsThemeDialogTextureEnabled(dialog
);
2006 /* Non-zero flags without ETDT_DISABLE enables dialog texture */
2007 ok(ret
== (!(flags
[i
] & ETDT_DISABLE
) && flags
[i
]), "Wrong dialog texture status.\n");
2009 child
= GetDlgItem(dialog
, 100);
2010 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
2011 child_hdc
= GetDC(child
);
2012 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
2013 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
2014 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2015 if (flags
[i
] == ETDT_ENABLETAB
|| flags
[i
] == ETDT_ENABLEAEROWIZARDTAB
)
2016 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2018 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2019 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2021 hr
= EnableThemeDialogTexture(dialog
, flags
[j
]);
2022 ok(hr
== S_OK
, "EnableThemeDialogTexture failed, hr %#x.\n", hr
);
2023 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2024 "EnableThemeDialogTexture second flag", FALSE
);
2025 ret
= IsThemeDialogTextureEnabled(dialog
);
2026 /* If the flag is zero, it will have previous dialog texture status */
2028 ok(ret
== !(flags
[j
] & ETDT_DISABLE
), "Wrong dialog texture status.\n");
2030 ok(ret
== (!(flags
[i
] & ETDT_DISABLE
) && flags
[i
]), "Wrong dialog texture status.\n");
2031 lr
= SendMessageA(dialog
, WM_ERASEBKGND
, (WPARAM
)child_hdc
, 0);
2032 ok(lr
!= 0, "WM_ERASEBKGND failed.\n");
2033 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2034 /* Dialog texture is turned on when the flag contains ETDT_ENABLETAB or
2035 * ETDT_ENABLEAEROWIZARDTAB. The flag can be turned on in multiple steps, but you can't
2036 * do things like set ETDT_ENABLETAB and then ETDT_USEAEROWIZARDTABTEXTURE */
2037 if (((flags
[j
] == ETDT_ENABLETAB
|| flags
[j
] == ETDT_ENABLEAEROWIZARDTAB
)
2038 || ((((flags
[i
] | flags
[j
]) & ETDT_ENABLETAB
) == ETDT_ENABLETAB
2039 || ((flags
[i
] | flags
[j
]) & ETDT_ENABLEAEROWIZARDTAB
) == ETDT_ENABLEAEROWIZARDTAB
)
2040 && !((flags
[i
] | flags
[j
]) & ETDT_DISABLE
)))
2041 && (((flags
[i
] | flags
[j
]) & (ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
)) != (ETDT_ENABLETAB
| ETDT_ENABLEAEROWIZARDTAB
)))
2042 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2044 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2046 ReleaseDC(child
, child_hdc
);
2047 EndDialog(dialog
, 0);
2049 winetest_pop_context();
2053 /* Test that the dialog procedure should set ETDT_USETABTEXTURE/ETDT_USEAEROWIZARDTABTEXTURE and
2054 * find out which comctl32 class should set ETDT_ENABLE to turn on dialog texture */
2055 for (i
= 0; i
< ARRAY_SIZE(class_tests
); ++i
)
2057 winetest_push_context("%s %#x", wine_dbgstr_a(class_tests
[i
].param
.class_name
),
2058 class_tests
[i
].param
.style
);
2060 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2061 test_EnableThemeDialogTexture_proc
,
2062 (LPARAM
)&class_tests
[i
].param
);
2063 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
2064 /* GetDlgItem() fails to get the child control if the child is a tooltip */
2065 child
= dialog_child
;
2066 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
2067 child_hdc
= GetDC(child
);
2069 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2070 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2072 ReleaseDC(child
, child_hdc
);
2073 EndDialog(dialog
, 0);
2075 dialog_init_flag
= ETDT_ENABLE
;
2076 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2077 test_EnableThemeDialogTexture_proc
,
2078 (LPARAM
)&class_tests
[i
].param
);
2079 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
2080 child
= dialog_child
;
2081 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
2082 child_hdc
= GetDC(child
);
2084 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2085 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2087 ReleaseDC(child
, child_hdc
);
2088 EndDialog(dialog
, 0);
2090 dialog_init_flag
= ETDT_USETABTEXTURE
;
2091 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2092 test_EnableThemeDialogTexture_proc
,
2093 (LPARAM
)&class_tests
[i
].param
);
2094 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
2095 child
= dialog_child
;
2096 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
2097 child_hdc
= GetDC(child
);
2098 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2099 if (class_tests
[i
].texture_enabled
)
2100 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2102 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2103 ReleaseDC(child
, child_hdc
);
2104 EndDialog(dialog
, 0);
2106 if (LOBYTE(LOWORD(GetVersion())) < 6)
2108 dialog_init_flag
= 0;
2109 winetest_pop_context();
2113 dialog_init_flag
= ETDT_USEAEROWIZARDTABTEXTURE
;
2114 dialog
= CreateDialogIndirectParamA(NULL
, &temp
.template, GetDesktopWindow(),
2115 test_EnableThemeDialogTexture_proc
,
2116 (LPARAM
)&class_tests
[i
].param
);
2117 ok(dialog
!= NULL
, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
2118 child
= dialog_child
;
2119 ok(child
!= NULL
, "Failed to get child control, error %d.\n", GetLastError());
2120 child_hdc
= GetDC(child
);
2121 brush
= (HBRUSH
)SendMessageW(dialog
, WM_CTLCOLORSTATIC
, (WPARAM
)child_hdc
, (LPARAM
)child
);
2122 if (class_tests
[i
].texture_enabled
)
2123 ok(brush
!= GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture enabled.\n");
2125 ok(brush
== GetSysColorBrush(COLOR_BTNFACE
), "Expected tab texture disabled.\n");
2126 ReleaseDC(child
, child_hdc
);
2127 EndDialog(dialog
, 0);
2128 dialog_init_flag
= 0;
2130 winetest_pop_context();
2133 /* Test that EnableThemeDialogTexture() is called from child controls for its parent */
2134 hwnd
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 100, 100, 200, 200, 0,
2136 ok(hwnd
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
2137 ret
= IsThemeDialogTextureEnabled(hwnd
);
2138 ok(!ret
, "Wrong dialog texture status.\n");
2139 child
= CreateWindowA(WC_STATICA
, "child", WS_CHILD
| WS_VISIBLE
, 0, 0, 50, 50, hwnd
, 0, 0,
2141 ok(child
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
2142 ret
= IsThemeDialogTextureEnabled(hwnd
);
2143 ok(ret
, "Wrong dialog texture status.\n");
2145 /* Test that if you move the child control to another window, it doesn't enables tab texture for
2147 hwnd2
= CreateWindowA(cls
.lpszClassName
, "parent", WS_POPUP
| WS_VISIBLE
, 100, 100, 200, 200, 0,
2149 ok(hwnd2
!= NULL
, "CreateWindowA failed, error %d.\n", GetLastError());
2150 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2151 ok(!ret
, "Wrong dialog texture status.\n");
2153 SetParent(child
, hwnd2
);
2154 ok(GetParent(child
) == hwnd2
, "Wrong parent.\n");
2155 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2156 ok(!ret
, "Wrong dialog texture status.\n");
2157 InvalidateRect(child
, NULL
, TRUE
);
2159 ret
= IsThemeDialogTextureEnabled(hwnd2
);
2160 ok(!ret
, "Wrong dialog texture status.\n");
2162 DestroyWindow(hwnd2
);
2163 DestroyWindow(hwnd
);
2165 UnregisterClassA(cls
.lpszClassName
, GetModuleHandleA(NULL
));
2170 ULONG_PTR ctx_cookie
;
2174 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2176 /* No real functional theme API tests will be done (yet). The current tests
2177 * only show input/return behaviour
2181 test_GetWindowTheme();
2182 test_SetWindowTheme();
2183 test_OpenThemeData();
2184 test_OpenThemeDataEx();
2185 test_OpenThemeDataForDpi();
2186 test_GetCurrentThemeName();
2187 test_GetThemePartSize();
2188 test_CloseThemeData();
2189 test_buffered_paint();
2190 test_GetThemeIntList();
2191 test_GetThemeTransitionDuration();
2192 test_DrawThemeParentBackground();
2194 if (load_v6_module(&ctx_cookie
, &ctx
))
2196 test_EnableThemeDialogTexture();
2198 unload_v6_module(ctx_cookie
, ctx
);
2201 /* Test EnableTheming() in the end because it may disable theming */
2202 test_EnableTheming();