Load, validate and retrieve a few properties from an msstyles theme
Index: dlls/uxtheme/Makefile.in =================================================================== RCS file: /home/wine/wine/dlls/uxtheme/Makefile.in,v retrieving revision 1.3 diff -u -r1.3 Makefile.in --- dlls/uxtheme/Makefile.in 4 Dec 2003 20:55:30 -0000 1.3 +++ dlls/uxtheme/Makefile.in 6 Dec 2003 20:21:21 -0000 @@ -3,7 +3,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = uxtheme.dll -IMPORTS = gdi32 user32 advapi32 kernel32 ntdll +IMPORTS = gdi32 shlwapi user32 advapi32 kernel32 ntdll EXTRALIBS = $(LIBUNICODE) C_SRCS = \ @@ -11,7 +11,8 @@ main.c \ metric.c \ property.c \ - system.c + system.c \ + msstyles.c RC_SRCS = version.rc Index: dlls/uxtheme/system.c =================================================================== RCS file: /home/wine/wine/dlls/uxtheme/system.c,v retrieving revision 1.1 diff -u -r1.1 system.c --- dlls/uxtheme/system.c 4 Dec 2003 20:55:30 -0000 1.1 +++ dlls/uxtheme/system.c 6 Dec 2003 20:21:22 -0000 @@ -26,9 +26,12 @@ #include "winbase.h" #include "winuser.h" #include "wingdi.h" +#include "winreg.h" +#include "shlwapi.h" #include "uxtheme.h" #include "uxthemedll.h" +#include "msstyles.h" #include "wine/debug.h" @@ -38,11 +41,28 @@ * Defines and global variables */ +static const WCHAR szThemeManager[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'T','h','e','m','e','M','a','n','a','g','e','r','\0' +}; +static const WCHAR szThemeActive[] = {'T','h','e','m','e','A','c','t','i','v','e','\0'}; +static const WCHAR szSizeName[] = {'S','i','z','e','N','a','m','e','\0'}; +static const WCHAR szColorName[] = {'C','o','l','o','r','N','a','m','e','\0'}; +static const WCHAR szDllName[] = {'D','l','l','N','a','m','e','\0'}; + DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS; ATOM atWindowTheme; ATOM atSubAppName; ATOM atSubIdList; +BOOL bThemeActive = FALSE; +WCHAR szCurrentTheme[MAX_PATH]; +WCHAR szCurrentColor[64]; +WCHAR szCurrentSize[64]; + /***********************************************************************/ /*********************************************************************** @@ -59,10 +79,65 @@ const WCHAR szSubIdList[] = { 'u','x','_','s','u','b','i','d','l','s','t','\0' }; + HKEY hKey; + LONG buffsize; + HRESULT hr; + WCHAR tmp[10]; + PTHEME_FILE pt; atWindowTheme = GlobalAddAtomW(szWindowTheme); atSubAppName = GlobalAddAtomW(szSubAppName); atSubIdList = GlobalAddAtomW(szSubIdList); + + /* Get current theme configuration */ + if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) { + TRACE("Loading theme config\n"); + buffsize = sizeof(tmp)/sizeof(tmp[0]); + if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) { + bThemeActive = (tmp[0] != '0'); + } + else { + bThemeActive = FALSE; + TRACE("Failed to get ThemeActive: %ld\n", GetLastError()); + } + buffsize = sizeof(szCurrentColor)/sizeof(szCurrentColor[0]); + if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize)) + szCurrentColor[0] = '\0'; + buffsize = sizeof(szCurrentSize)/sizeof(szCurrentSize[0]); + if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize)) + szCurrentSize[0] = '\0'; + if(SHRegGetPathW(hKey, NULL, szDllName, szCurrentTheme, 0)) + szCurrentTheme[0] = '\0'; + RegCloseKey(hKey); + } + else + TRACE("Failed to open theme registry key\n"); + + if(bThemeActive) { + /* Make sure the theme requested is actually valid */ + hr = MSSTYLES_OpenThemeFile(szCurrentTheme, + szCurrentColor[0]?szCurrentColor:NULL, + szCurrentSize[0]?szCurrentSize:NULL, + &pt); + if(FAILED(hr)) { + bThemeActive = FALSE; + szCurrentTheme[0] = '\0'; + szCurrentColor[0] = '\0'; + szCurrentSize[0] = '\0'; + } + else { + /* Make sure the global color & size match the theme */ + lstrcpynW(szCurrentColor, pt->pszSelectedColor, sizeof(szCurrentColor)/sizeof(szCurrentColor[0])); + lstrcpynW(szCurrentSize, pt->pszSelectedSize, sizeof(szCurrentSize)/sizeof(szCurrentSize[0])); + MSSTYLES_CloseThemeFile(pt); + } + } + + if(!bThemeActive) + TRACE("Themeing not active\n"); + else + TRACE("Theme active: %s %s %s\n", debugstr_w(szCurrentTheme), + debugstr_w(szCurrentColor), debugstr_w(szCurrentSize)); } /*********************************************************************** @@ -70,8 +145,7 @@ */ BOOL WINAPI IsAppThemed(void) { - FIXME("stub\n"); - return FALSE; + return IsThemeActive(); } /*********************************************************************** @@ -79,8 +153,8 @@ */ BOOL WINAPI IsThemeActive(void) { - FIXME("stub\n"); - return FALSE; + TRACE("\n"); + return bThemeActive; } /*********************************************************************** @@ -91,8 +165,21 @@ */ HRESULT WINAPI EnableTheming(BOOL fEnable) { - FIXME("%d: stub\n", fEnable); - return ERROR_CALL_NOT_IMPLEMENTED; + HKEY hKey; + WCHAR szEnabled[] = {'0','\0'}; + + TRACE("(%d)\n", fEnable); + + if(fEnable != bThemeActive) { + bThemeActive = fEnable; + if(bThemeActive) szEnabled[0] = '1'; + if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) { + RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (LPBYTE)szEnabled, sizeof(WCHAR)); + RegCloseKey(hKey); + } + PostMessageW(HWND_BROADCAST, WM_THEMECHANGED, 0, 0); + } + return S_OK; } /*********************************************************************** @@ -151,7 +238,9 @@ debugstr_w(pszSubIdList)); hr = UXTHEME_SetWindowProperty(hwnd, atSubAppName, pszSubAppName); if(SUCCEEDED(hr)) - hr = UXTHEME_SetWindowProperty(hwnd, atSubIdList, pszSubIdList); + hr = UXTHEME_SetWindowProperty(hwnd, atSubIdList, pszSubIdList); + if(SUCCEEDED(hr)) + PostMessageW(hwnd, WM_THEMECHANGED, 0, 0); return hr; } @@ -162,8 +251,12 @@ LPWSTR pszColorBuff, int cchMaxColorChars, LPWSTR pszSizeBuff, int cchMaxSizeChars) { - FIXME("stub\n"); - return ERROR_CALL_NOT_IMPLEMENTED; + if(!bThemeActive) + return E_PROP_ID_UNSUPPORTED; + if(pszThemeFileName) lstrcpynW(pszThemeFileName, szCurrentTheme, dwMaxNameChars); + if(pszColorBuff) lstrcpynW(pszColorBuff, szCurrentColor, cchMaxColorChars); + if(pszSizeBuff) lstrcpynW(pszSizeBuff, szCurrentSize, cchMaxSizeChars); + return S_OK; } /*********************************************************************** @@ -249,10 +342,10 @@ LPCWSTR pszSizeName, HTHEMEFILE *hThemeFile, DWORD unknown) { - FIXME("%s,%s,%s,%ld: stub\n", debugstr_w(pszThemeFileName), - debugstr_w(pszColorName), - debugstr_w(pszSizeName), unknown); - return ERROR_CALL_NOT_IMPLEMENTED; + TRACE("(%s,%s,%s,%p,%ld)\n", debugstr_w(pszThemeFileName), + debugstr_w(pszColorName), debugstr_w(pszSizeName), + hThemeFile, unknown); + return MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, (PTHEME_FILE*)hThemeFile); } /********************************************************************** @@ -265,7 +358,8 @@ */ HRESULT WINAPI CloseThemeFile(HTHEMEFILE hThemeFile) { - FIXME("stub\n"); + TRACE("(%p)\n", hThemeFile); + MSSTYLES_CloseThemeFile(hThemeFile); return S_OK; } @@ -311,8 +405,20 @@ DWORD dwColorNameLen, LPWSTR pszSizeName, DWORD dwSizeNameLen) { - FIXME("%s: stub\n", debugstr_w(pszThemeFileName)); - return ERROR_CALL_NOT_IMPLEMENTED; + PTHEME_FILE pt; + HRESULT hr; + TRACE("(%s,%p,%ld,%p,%ld)\n", debugstr_w(pszThemeFileName), + pszColorName, dwColorNameLen, + pszSizeName, dwSizeNameLen); + + hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, NULL, &pt); + if(FAILED(hr)) return hr; + + lstrcpynW(pszColorName, pt->pszSelectedColor, dwColorNameLen); + lstrcpynW(pszSizeName, pt->pszSelectedSize, dwSizeNameLen); + + MSSTYLES_CloseThemeFile(pt); + return S_OK; } /********************************************************************** @@ -354,13 +460,37 @@ * NOTES * XP fails with E_POINTER when pszColorName points to a buffer smaller then 605 * characters + * + * Not very efficient that I'm opening & validating the theme every call, but + * this is undocumented and almost never called.. + * (and this is how windows works too) */ HRESULT WINAPI EnumThemeColors(LPWSTR pszThemeFileName, LPWSTR pszSizeName, DWORD dwColorNum, LPWSTR pszColorName) { - FIXME("%s %s %ld: stub\n", debugstr_w(pszThemeFileName), + PTHEME_FILE pt; + HRESULT hr; + LPWSTR tmp; + TRACE("(%s,%s,%ld)\n", debugstr_w(pszThemeFileName), debugstr_w(pszSizeName), dwColorNum); - return ERROR_CALL_NOT_IMPLEMENTED; + + hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, pszSizeName, &pt); + if(FAILED(hr)) return hr; + + tmp = pt->pszAvailColors; + while(dwColorNum && *tmp) { + dwColorNum--; + tmp += lstrlenW(tmp)+1; + } + if(!dwColorNum && *tmp) { + TRACE("%s\n", debugstr_w(tmp)); + lstrcpyW(pszColorName, tmp); + } + else + hr = E_PROP_ID_UNSUPPORTED; + + MSSTYLES_CloseThemeFile(pt); + return hr; } /********************************************************************** @@ -383,12 +513,37 @@ * NOTES * XP fails with E_POINTER when pszSizeName points to a buffer smaller then 605 * characters + * + * Not very efficient that I'm opening & validating the theme every call, but + * this is undocumented and almost never called.. + * (and this is how windows works too) */ HRESULT WINAPI EnumThemeSizes(LPWSTR pszThemeFileName, LPWSTR pszColorName, DWORD dwSizeNum, LPWSTR pszSizeName) { - FIXME("%s %s %ld: stub\n", debugstr_w(pszThemeFileName), debugstr_w(pszColorName), dwSizeNum); - return ERROR_CALL_NOT_IMPLEMENTED; + PTHEME_FILE pt; + HRESULT hr; + LPWSTR tmp; + TRACE("(%s,%s,%ld)\n", debugstr_w(pszThemeFileName), + debugstr_w(pszColorName), dwSizeNum); + + hr = MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, NULL, &pt); + if(FAILED(hr)) return hr; + + tmp = pt->pszAvailSizes; + while(dwSizeNum && *tmp) { + dwSizeNum--; + tmp += lstrlenW(tmp)+1; + } + if(!dwSizeNum && *tmp) { + TRACE("%s\n", debugstr_w(tmp)); + lstrcpyW(pszSizeName, tmp); + } + else + hr = E_PROP_ID_UNSUPPORTED; + + MSSTYLES_CloseThemeFile(pt); + return hr; } /********************************************************************** --- /dev/null 1969-12-31 19:00:00.000000000 -0500 +++ dlls/uxtheme/msstyles.c 2003-12-06 14:12:48.000000000 -0500 @@ -0,0 +1,172 @@ +/* + * Win32 5.1 msstyles theme format + * + * Copyright (C) 2003 Kevin Koltzau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wingdi.h" +#include "uxtheme.h" + +#include "uxthemedll.h" +#include "msstyles.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(uxtheme); + +#define MSSTYLES_VERSION 0x0003 + +/********************************************************************** + * MSSTYLES_OpenThemeFile + * + * Load and validate a theme + * + * PARAMS + * lpThemeFile Path to theme file to load + * pszColorName Color name wanted, can be NULL + * pszSizeName Size name wanted, can be NULL + * + * NOTES + * If pszColorName or pszSizeName are NULL, the default color/size will be used. + * If one/both are provided, they are validated against valid color/sizes and if + * a match is not found, the function fails. + */ +HRESULT MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile, LPCWSTR pszColorName, LPCWSTR pszSizeName, PTHEME_FILE *tf) +{ + HMODULE hTheme; + HRSRC hrsc; + HRESULT hr = S_OK; + WCHAR szPackThemVersionResource[] = { + 'P','A','C','K','T','H','E','M','_','V','E','R','S','I','O','N', '\0' + }; + WCHAR szColorNamesResource[] = { + 'C','O','L','O','R','N','A','M','E','S','\0' + }; + WCHAR szSizeNamesResource[] = { + 'S','I','Z','E','N','A','M','E','S','\0' + }; + + WORD version; + DWORD versize; + LPWSTR pszColors; + LPWSTR pszSelectedColor = NULL; + LPWSTR pszSizes; + LPWSTR pszSelectedSize = NULL; + LPWSTR tmp; + + TRACE("Opening %s\n", debugstr_w(lpThemeFile)); + + hTheme = LoadLibraryExW(lpThemeFile, NULL, LOAD_LIBRARY_AS_DATAFILE); + + /* Validate that this is really a theme */ + if(!hTheme) goto invalid_theme; + if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szPackThemVersionResource))) { + TRACE("No version resource found\n"); + goto invalid_theme; + } + if((versize = SizeofResource(hTheme, hrsc)) != 2) + { + TRACE("Version resource found, but wrong size: %ld\n", versize); + goto invalid_theme; + } + version = *(WORD*)LoadResource(hTheme, hrsc); + if(version != MSSTYLES_VERSION) + { + TRACE("Version of theme file is unsupported: 0x%04x\n", version); + goto invalid_theme; + } + + if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szColorNamesResource))) { + TRACE("Color names resource not found\n"); + goto invalid_theme; + } + pszColors = (LPWSTR)LoadResource(hTheme, hrsc); + + if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szSizeNamesResource))) { + TRACE("Size names resource not found\n"); + goto invalid_theme; + } + pszSizes = (LPWSTR)LoadResource(hTheme, hrsc); + + /* Validate requested color against whats available from the theme */ + if(pszColorName) { + tmp = pszColors; + while(*tmp) { + if(!lstrcmpiW(pszColorName, tmp)) { + pszSelectedColor = tmp; + break; + } + tmp += lstrlenW(tmp)+1; + } + } + else + pszSelectedColor = pszColors; /* Use the default color */ + + /* Validate requested size against whats available from the theme */ + if(pszSizeName) { + tmp = pszSizes; + while(*tmp) { + if(!lstrcmpiW(pszSizeName, tmp)) { + pszSelectedSize = tmp; + break; + } + tmp += lstrlenW(tmp)+1; + } + } + else + pszSelectedSize = pszSizes; /* Use the default size */ + + if(!pszSelectedColor || !pszSelectedSize) { + TRACE("Requested color/size (%s/%s) not found in theme\n", + debugstr_w(pszColorName), debugstr_w(pszSizeName)); + hr = E_PROP_ID_UNSUPPORTED; + goto invalid_theme; + } + + *tf = HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_FILE)); + (*tf)->hTheme = hTheme; + (*tf)->pszAvailColors = pszColors; + (*tf)->pszAvailSizes = pszSizes; + (*tf)->pszSelectedColor = pszSelectedColor; + (*tf)->pszSelectedSize = pszSelectedSize; + return S_OK; + +invalid_theme: + if(hTheme) FreeLibrary(hTheme); + if(!hr) hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; +} + +/*********************************************************************** + * MSSTYLES_CloseThemeFile + * + * Close theme file and free resources + */ +void MSSTYLES_CloseThemeFile(PTHEME_FILE tf) +{ + if(tf) { + if(tf->hTheme) FreeLibrary(tf->hTheme); + HeapFree(GetProcessHeap(), 0, tf); + } +} --- /dev/null 1969-12-31 19:00:00.000000000 -0500 +++ dlls/uxtheme/msstyles.h 2003-12-05 21:31:49.000000000 -0500 @@ -0,0 +1,37 @@ +/* + * Internal msstyles related defines & declarations + * + * Copyright (C) 2003 Kevin Koltzau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_MSSTYLES_H +#define __WINE_MSSTYLES_H + +typedef struct _THEME_FILE { + HMODULE hTheme; + LPWSTR pszAvailColors; + LPWSTR pszAvailSizes; + + LPWSTR pszSelectedColor; + LPWSTR pszSelectedSize; +} THEME_FILE, *PTHEME_FILE; + +HRESULT MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile, LPCWSTR pszColorName, LPCWSTR pszSizeName, PTHEME_FILE *tf); +void MSSTYLES_CloseThemeFile(PTHEME_FILE tf); + + +#endif