These tests show that it's the themed property sheet page window procedure that sets device contexts transparent and return a pattern brush created from the tab body part in a theme. Combined with test_WM_CTLCOLORSTATIC() in dlls/comctl32/tests/static.c, we can conclude that UXTHEME_DefDlgProc() shouldn't handle WM_CTLCOLORSTATIC.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/comctl32/tests/propsheet.c | 326 +++++++++++++++++++++++++++++++- 1 file changed, 324 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/tests/propsheet.c b/dlls/comctl32/tests/propsheet.c index 3089454d18d..eaaa00efe97 100644 --- a/dlls/comctl32/tests/propsheet.c +++ b/dlls/comctl32/tests/propsheet.c @@ -20,18 +20,24 @@
#include <windows.h> #include <commctrl.h> +#include <uxtheme.h> +#include <vsstyle.h> #include "msg.h"
#include "resources.h"
#include "wine/test.h"
+#include "v6util.h" + static HWND parenthwnd; static HWND sheethwnd;
static BOOL rtl; static LONG active_page = -1;
+static BOOL is_v6, is_theme_active; + #define IDC_APPLY_BUTTON 12321
static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageA)(const PROPSHEETPAGEA *desc); @@ -39,6 +45,14 @@ static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageW)(const PROPSHEETPAGEW * static BOOL (WINAPI *pDestroyPropertySheetPage)(HPROPSHEETPAGE proppage); static INT_PTR (WINAPI *pPropertySheetA)(const PROPSHEETHEADERA *header);
+static HRESULT (WINAPI *pCloseThemeData)(HTHEME); +static HRESULT (WINAPI *pEnableThemeDialogTexture)(HWND, DWORD); +static HRESULT (WINAPI *pGetThemePartSize)(HTHEME, HDC, int, int, RECT *, THEMESIZE, SIZE *); +static HTHEME (WINAPI *pGetWindowTheme)(HWND); +static BOOL (WINAPI *pIsThemeActive)(void); +static BOOL (WINAPI *pIsThemeDialogTextureEnabled)(HWND); +static HTHEME (WINAPI *pOpenThemeData)(HWND, LPCWSTR); + static void detect_locale(void) { DWORD reading_layout; @@ -1180,7 +1194,284 @@ static void test_bad_control_class(void) DestroyWindow((HWND)ret); }
-static void init_functions(void) +static BOOL handle_WM_CTLCOLORSTATIC; + +static INT_PTR CALLBACK test_WM_CTLCOLORSTATIC_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + static HWND child; + + switch(msg) + { + case WM_INITDIALOG: + sheethwnd = hwnd; + child = CreateWindowA(WC_STATICA, "child", WS_CHILD | WS_VISIBLE, 1, 2, 50, 50, hwnd, + (HMENU)100, 0, NULL); + ok(child != NULL, "CreateWindowA failed, error %d.\n", GetLastError()); + return FALSE; + + case WM_CTLCOLORSTATIC: + return (INT_PTR)(handle_WM_CTLCOLORSTATIC ? GetSysColorBrush(COLOR_MENU) : 0); + + case WM_CLOSE: + DestroyWindow(child); + return FALSE; + + default: + return FALSE; + } +} + +static void test_WM_CTLCOLORSTATIC(void) +{ + HWND hdlg, child, parent, hwnd; + COLORREF color, old_color; + int mode, old_mode, count; + HBRUSH hbrush, hbrush2; + HPROPSHEETPAGE hpsp[1]; + PROPSHEETHEADERA psh; + HDC child_hdc, hdc; + LOGBRUSH log_brush; + PROPSHEETPAGEA psp; + ULONG_PTR dlgproc; + WNDCLASSA cls; + HTHEME theme; + DWORD error; + BITMAP bmp; + HRESULT hr; + POINT org; + SIZE size; + BOOL ret; + + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.hInstance = GetModuleHandleA(NULL); + U(psp).pszTemplate = "prop_page1"; + psp.pfnDlgProc = test_WM_CTLCOLORSTATIC_proc; + hpsp[0] = pCreatePropertySheetPageA(&psp); + + memset(&psh, 0, sizeof(psh)); + psh.dwSize = PROPSHEETHEADERA_V1_SIZE; + psh.dwFlags = PSH_MODELESS; + psh.pszCaption = "caption"; + psh.nPages = 1; + psh.hwndParent = GetDesktopWindow(); + U3(psh).phpage = hpsp; + + hdlg = (HWND)pPropertySheetA(&psh); + ok(hdlg != INVALID_HANDLE_VALUE, "Got invalid handle value %p.\n", hdlg); + flush_events(); + + child = GetDlgItem(sheethwnd, 100); + ok(child != NULL, "Failed to get child static control, error %d.\n", GetLastError()); + parent = GetParent(child); + ok(parent == sheethwnd, "Expected parent %p, got %p.\n", sheethwnd, parent); + ok(sheethwnd != hdlg, "Expected handles not equal.\n"); + + /* Test that page dialog procedure is unchanged */ + dlgproc = GetWindowLongPtrA(sheethwnd, DWLP_DLGPROC); + ok(dlgproc == (ULONG_PTR)test_WM_CTLCOLORSTATIC_proc, "Unexpected dlgproc %#lx.\n", dlgproc); + + child_hdc = GetDC(child); + old_mode = SetBkMode(child_hdc, OPAQUE); + ok(old_mode != 0, "SetBkMode failed.\n"); + old_color = SetBkColor(child_hdc, 0xaa5511); + ok(old_color != CLR_INVALID, "SetBkColor failed.\n"); + + /* Test that brush origin is at (0,0) */ + ret = GetBrushOrgEx(child_hdc, &org); + ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError()); + ok(org.x == 0 && org.y == 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org)); + + /* Test that theme dialog texture is enabled for comctl32 v6, even when theming is off */ + ret = pIsThemeDialogTextureEnabled(sheethwnd); + todo_wine_if(!is_v6) + ok(ret == is_v6, "Wrong theme dialog texture status.\n"); + + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + if (is_v6 && is_theme_active) + { + /* Test that brush origin is changed after WM_CTLCOLORSTATIC */ + ret = GetBrushOrgEx(child_hdc, &org); + ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError()); + todo_wine + ok(org.x == -1 && org.y == -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org)); + + /* Test that device context is set to transparent after WM_CTLCOLORSTATIC */ + mode = SetBkMode(child_hdc, old_mode); + todo_wine_if(pGetWindowTheme(sheethwnd) == NULL) + ok(mode == TRANSPARENT, "Expected mode %#x, got %#x.\n", TRANSPARENT, mode); + + /* Test that the brush is a pattern brush created from the tab body bitmap in the theme */ + todo_wine_if(pGetWindowTheme(sheethwnd) == NULL) + ok(hbrush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n"); + todo_wine_if(pGetWindowTheme(sheethwnd) != NULL) + ok(hbrush != GetStockObject(NULL_BRUSH), "Expected a different brush.\n"); + hbrush2 = SelectObject(child_hdc, GetSysColorBrush(COLOR_BTNFACE)); + ok(hbrush2 != hbrush, "Expected a different brush.\n"); + + memset(&log_brush, 0, sizeof(log_brush)); + count = GetObjectA(hbrush, sizeof(log_brush), &log_brush); + ok(count == sizeof(log_brush), "GetObjectA failed, error %u.\n", GetLastError()); + todo_wine_if(pGetWindowTheme(sheethwnd) == NULL) + ok(log_brush.lbColor == 0, "Expected brush color %#x, got %#x.\n", 0, log_brush.lbColor); + todo_wine + ok(log_brush.lbStyle == BS_PATTERN, "Expected brush style %#x, got %#x.\n", BS_PATTERN, + log_brush.lbStyle); + + memset(&bmp, 0, sizeof(bmp)); + count = GetObjectA((HBITMAP)log_brush.lbHatch, sizeof(bmp), &bmp); + todo_wine + ok(count == sizeof(bmp), "GetObjectA failed, error %u.\n", GetLastError()); + + todo_wine_if(pGetWindowTheme(hdlg) != NULL) + ok(pGetWindowTheme(hdlg) == NULL, "Expected NULL theme handle.\n"); + todo_wine_if(pGetWindowTheme(sheethwnd) != NULL) + ok(pGetWindowTheme(sheethwnd) == NULL, "Expected NULL theme handle.\n"); + + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = DefWindowProcA; + cls.hInstance = GetModuleHandleA(NULL); + cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszClassName = "TestClass"; + RegisterClassA(&cls); + + hwnd = CreateWindowA("TestClass", "test", WS_POPUP | WS_VISIBLE, 0, 0, 4, 4, 0, 0, 0, NULL); + ok(hwnd != NULL, "CreateWindowA failed, error %d.\n", GetLastError()); + theme = pOpenThemeData(hwnd, L"Tab"); + /* Light theme triggers a double free bug in uxtheme */ + todo_wine_if(!theme) + ok(theme != NULL, "OpenThemeData failed.\n"); + + size.cx = 0; + size.cy = 0; + hr = pGetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size); + todo_wine_if(!theme) + ok(hr == S_OK, "GetThemePartSize failed, hr %#x.\n", hr); + todo_wine_if(theme) + ok(bmp.bmWidth == size.cx, "Expected width %d, got %d.\n", size.cx, bmp.bmWidth); + todo_wine_if(theme) + ok(bmp.bmHeight == size.cy, "Expected height %d, got %d.\n", size.cy, bmp.bmHeight); + + pCloseThemeData(theme); + + /* Test that other controls besides static controls also get the same brush */ + hdc = GetDC(hwnd); + old_mode = SetBkMode(hdc, OPAQUE); + ok(old_mode != 0, "SetBkMode failed.\n"); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd); + todo_wine_if(pGetWindowTheme(sheethwnd) != NULL) + ok(hbrush2 == hbrush, "Expected the same brush.\n"); + mode = SetBkMode(hdc, old_mode); + todo_wine + ok(mode == TRANSPARENT, "Expected mode %#x, got %#x.\n", TRANSPARENT, mode); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + UnregisterClassA("TestClass", GetModuleHandleA(NULL)); + + /* Test disabling theme dialog texture should change the brush */ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_DISABLE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine_if(pGetWindowTheme(sheethwnd) == NULL) + ok(hbrush2 != hbrush, "Expected a different brush.\n"); + ok(hbrush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n", + GetSysColorBrush(COLOR_BTNFACE), hbrush2); + + /* Test re-enabling theme dialog texture with ETDT_ENABLE doesn't change the brush*/ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_ENABLE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine_if(hbrush2 != hbrush) + ok(hbrush2 == hbrush, "Expected the same brush.\n"); + + /* Test ETDT_ENABLE | ETDT_USETABTEXTURE should change the brush */ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_ENABLE | ETDT_USETABTEXTURE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine_if(hbrush2 == hbrush) + ok(hbrush2 != hbrush, "Expected a different brush.\n"); + + /* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush */ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */ + if (LOBYTE(LOWORD(GetVersion())) < 6) + ok(hbrush2 == hbrush, "Expected the same brush.\n"); + else + todo_wine_if(hbrush2 == hbrush) + ok(hbrush2 != hbrush, "Expected a different brush.\n"); + + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_DISABLE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + hr = pEnableThemeDialogTexture(sheethwnd, ETDT_ENABLE | ETDT_USETABTEXTURE); + ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); + + /* Test that the page procedure should take precedence if WM_CTLCOLORSTATIC is handled */ + handle_WM_CTLCOLORSTATIC = TRUE; + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + ok(hbrush == GetSysColorBrush(COLOR_MENU), "Expected brush %p, got %p.\n", + GetSysColorBrush(COLOR_MENU), hbrush); + handle_WM_CTLCOLORSTATIC = FALSE; + + /* Test that the brush is not a system object and has only one reference and shouldn't be freed */ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + ret = DeleteObject(hbrush); + ok(ret, "DeleteObject failed, error %u.\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetObjectA(hbrush, sizeof(log_brush), &log_brush); + error = GetLastError(); + todo_wine + ok(!ret, "GetObjectA succeeded.\n"); + todo_wine + ok(error == ERROR_INVALID_PARAMETER, "Expected error %u, got %u.\n", + ERROR_INVALID_PARAMETER, error); + ret = DeleteObject(hbrush); + todo_wine + ok(!ret, "DeleteObject succeeded.\n"); + + /* Should still report the same brush handle after the brush handle was freed */ + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + ok(hbrush2 == hbrush, "Expected the same brush.\n"); + + /* Test that WM_THEMECHANGED should recreate the brush */ + hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + SendMessageW(sheethwnd, WM_THEMECHANGED, 0, 0); + hbrush2 = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine_if(is_theme_active) + ok(hbrush2 != hbrush, "Expected a different brush.\n"); + ret = GetObjectA(hbrush, sizeof(log_brush), &log_brush); + todo_wine + ok(!ret, "GetObjectA succeeded.\n"); + } + else + { + /* Test that brush origin is at (0,0) */ + ret = GetBrushOrgEx(child_hdc, &org); + ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError()); + ok(org.x == 0 && org.y == 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org)); + + todo_wine_if(pGetWindowTheme(sheethwnd) != NULL) + ok(hbrush == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n", + GetSysColorBrush(COLOR_BTNFACE), hbrush); + mode = SetBkMode(child_hdc, old_mode); + todo_wine_if(pGetWindowTheme(sheethwnd) != NULL) + ok(mode == OPAQUE, "Expected mode %#x, got %#x.\n", OPAQUE, mode); + } + color = SetBkColor(child_hdc, old_color); + ok(color == GetSysColor(COLOR_BTNFACE), "Expected background color %#x, got %#x.\n", + GetSysColor(COLOR_BTNFACE), color); + + ReleaseDC(child, child_hdc); + DestroyWindow(hdlg); +} + +static void init_comctl32_functions(void) { HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
@@ -1192,8 +1483,26 @@ static void init_functions(void) #undef X }
+static void init_uxtheme_functions(void) +{ + HMODULE uxtheme = LoadLibraryA("uxtheme.dll"); + +#define X(f) p##f = (void *)GetProcAddress(uxtheme, #f); + X(CloseThemeData) + X(EnableThemeDialogTexture) + X(GetThemePartSize) + X(GetWindowTheme) + X(IsThemeActive) + X(IsThemeDialogTextureEnabled) + X(OpenThemeData) +#undef X +} + START_TEST(propsheet) { + ULONG_PTR ctx_cookie; + HANDLE ctx; + detect_locale(); if (rtl) { @@ -1203,7 +1512,9 @@ START_TEST(propsheet) SetProcessDefaultLayout(LAYOUT_RTL); }
- init_functions(); + init_comctl32_functions(); + init_uxtheme_functions(); + is_theme_active = pIsThemeActive();
test_bad_control_class(); test_title(); @@ -1216,4 +1527,15 @@ START_TEST(propsheet) test_PSM_ADDPAGE(); test_PSM_INSERTPAGE(); test_CreatePropertySheetPage(); + test_WM_CTLCOLORSTATIC(); + + if (!load_v6_module(&ctx_cookie, &ctx)) + return; + + init_comctl32_functions(); + is_v6 = TRUE; + + test_WM_CTLCOLORSTATIC(); + + unload_v6_module(ctx_cookie, ctx); }