xref: /reactos/dll/win32/uxtheme/system.c (revision 1b5f6c2d)
1 /*
2  * Win32 5.1 Theme system
3  *
4  * Copyright (C) 2003 Kevin Koltzau
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include "uxthemep.h"
22 
23 #include <stdio.h>
24 #include <winreg.h>
25 #include <uxundoc.h>
26 
27 DWORD gdwErrorInfoTlsIndex = TLS_OUT_OF_INDEXES;
28 
29 /***********************************************************************
30  * Defines and global variables
31  */
32 
33 static const WCHAR szThemeManager[] = {
34     'S','o','f','t','w','a','r','e','\\',
35     'M','i','c','r','o','s','o','f','t','\\',
36     'W','i','n','d','o','w','s','\\',
37     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
38     'T','h','e','m','e','M','a','n','a','g','e','r','\0'
39 };
40 static const WCHAR szThemeActive[] = {'T','h','e','m','e','A','c','t','i','v','e','\0'};
41 static const WCHAR szSizeName[] = {'S','i','z','e','N','a','m','e','\0'};
42 static const WCHAR szColorName[] = {'C','o','l','o','r','N','a','m','e','\0'};
43 static const WCHAR szDllName[] = {'D','l','l','N','a','m','e','\0'};
44 
45 static const WCHAR szIniDocumentation[] = {'d','o','c','u','m','e','n','t','a','t','i','o','n','\0'};
46 
47 HINSTANCE hDllInst;
48 ATOM atDialogThemeEnabled;
49 
50 static DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
51 ATOM atWindowTheme;
52 static ATOM atSubAppName;
53 static ATOM atSubIdList;
54 ATOM atWndContext;
55 
56 PTHEME_FILE g_ActiveThemeFile;
57 
58 RTL_HANDLE_TABLE g_UxThemeHandleTable;
59 int g_cHandles;
60 
61 /***********************************************************************/
62 
UXTHEME_send_theme_changed(HWND hWnd,LPARAM enable)63 static BOOL CALLBACK UXTHEME_send_theme_changed (HWND hWnd, LPARAM enable)
64 {
65     SendMessageW(hWnd, WM_THEMECHANGED, enable, 0);
66     return TRUE;
67 }
68 
69 /* Broadcast WM_THEMECHANGED to *all* windows, including children */
UXTHEME_broadcast_theme_changed(HWND hWnd,LPARAM enable)70 BOOL CALLBACK UXTHEME_broadcast_theme_changed (HWND hWnd, LPARAM enable)
71 {
72     if (hWnd == NULL)
73     {
74         EnumWindows (UXTHEME_broadcast_theme_changed, enable);
75     }
76     else
77     {
78         UXTHEME_send_theme_changed(hWnd, enable);
79         EnumChildWindows (hWnd, UXTHEME_send_theme_changed, enable);
80     }
81     return TRUE;
82 }
83 
84 /* At the end of the day this is a subset of what SHRegGetPath() does - copied
85  * here to avoid linking against shlwapi. */
query_reg_path(HKEY hKey,LPCWSTR lpszValue,LPVOID pvData)86 static DWORD query_reg_path (HKEY hKey, LPCWSTR lpszValue,
87                              LPVOID pvData)
88 {
89   DWORD dwRet, dwType, dwUnExpDataLen = MAX_PATH * sizeof(WCHAR), dwExpDataLen;
90 
91   TRACE("(hkey=%p,%s,%p)\n", hKey, debugstr_w(lpszValue),
92         pvData);
93 
94   dwRet = RegQueryValueExW(hKey, lpszValue, 0, &dwType, pvData, &dwUnExpDataLen);
95   if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA)
96       return dwRet;
97 
98   if (dwType == REG_EXPAND_SZ)
99   {
100     DWORD nBytesToAlloc;
101 
102     /* Expand type REG_EXPAND_SZ into REG_SZ */
103     LPWSTR szData;
104 
105     /* If the caller didn't supply a buffer or the buffer is too small we have
106      * to allocate our own
107      */
108     if (dwRet == ERROR_MORE_DATA)
109     {
110       WCHAR cNull = '\0';
111       nBytesToAlloc = dwUnExpDataLen;
112 
113       szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
114       RegQueryValueExW (hKey, lpszValue, 0, NULL, (LPBYTE)szData, &nBytesToAlloc);
115       dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
116       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
117       LocalFree(szData);
118     }
119     else
120     {
121       nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR);
122       szData = LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc );
123       lstrcpyW(szData, pvData);
124       dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, MAX_PATH );
125       if (dwExpDataLen > MAX_PATH) dwRet = ERROR_MORE_DATA;
126       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
127       LocalFree(szData);
128     }
129   }
130 
131   return dwRet;
132 }
133 
UXTHEME_SetActiveTheme(PTHEME_FILE tf)134 static HRESULT UXTHEME_SetActiveTheme(PTHEME_FILE tf)
135 {
136     if(g_ActiveThemeFile)
137         MSSTYLES_CloseThemeFile(g_ActiveThemeFile);
138     g_ActiveThemeFile = tf;
139     if (g_ActiveThemeFile)
140     {
141         MSSTYLES_ReferenceTheme(g_ActiveThemeFile);
142         MSSTYLES_ParseThemeIni(g_ActiveThemeFile);
143     }
144     return S_OK;
145 }
146 
bIsThemeActive(LPCWSTR pszTheme,LPCWSTR pszColor,LPCWSTR pszSize)147 static BOOL bIsThemeActive(LPCWSTR pszTheme, LPCWSTR pszColor, LPCWSTR pszSize)
148 {
149     if (g_ActiveThemeFile == NULL)
150         return FALSE;
151 
152     if (wcscmp(pszTheme, g_ActiveThemeFile->szThemeFile) != 0)
153         return FALSE;
154 
155     if (!pszColor[0])
156     {
157         if (g_ActiveThemeFile->pszAvailColors != g_ActiveThemeFile->pszSelectedColor)
158             return FALSE;
159     }
160     else
161     {
162         if (wcscmp(pszColor, g_ActiveThemeFile->pszSelectedColor) != 0)
163             return FALSE;
164     }
165 
166     if (!pszSize[0])
167     {
168         if (g_ActiveThemeFile->pszAvailSizes != g_ActiveThemeFile->pszSelectedSize)
169             return FALSE;
170     }
171     else
172     {
173         if (wcscmp(pszSize, g_ActiveThemeFile->pszSelectedSize) != 0)
174             return FALSE;
175     }
176 
177     return TRUE;
178 }
179 
180 /***********************************************************************
181  *      UXTHEME_LoadTheme
182  *
183  * Set the current active theme from the registry
184  */
UXTHEME_LoadTheme(BOOL bLoad)185 void UXTHEME_LoadTheme(BOOL bLoad)
186 {
187     HKEY hKey;
188     DWORD buffsize;
189     HRESULT hr;
190     WCHAR tmp[10];
191     PTHEME_FILE pt;
192     WCHAR szCurrentTheme[MAX_PATH];
193     WCHAR szCurrentColor[64];
194     WCHAR szCurrentSize[64];
195     BOOL bThemeActive = FALSE;
196 
197     if ((bLoad != FALSE) && g_bThemeHooksActive)
198     {
199         /* Get current theme configuration */
200         if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
201             TRACE("Loading theme config\n");
202             buffsize = sizeof(tmp);
203             if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) {
204                 bThemeActive = (tmp[0] != '0');
205             }
206             else {
207                 bThemeActive = FALSE;
208                 TRACE("Failed to get ThemeActive: %d\n", GetLastError());
209             }
210             buffsize = sizeof(szCurrentColor);
211             if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize))
212                 szCurrentColor[0] = '\0';
213             buffsize = sizeof(szCurrentSize);
214             if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize))
215                 szCurrentSize[0] = '\0';
216             if (query_reg_path (hKey, szDllName, szCurrentTheme))
217                 szCurrentTheme[0] = '\0';
218             RegCloseKey(hKey);
219         }
220         else
221             TRACE("Failed to open theme registry key\n");
222     }
223     else
224     {
225         bThemeActive = FALSE;
226     }
227 
228     if(bThemeActive)
229     {
230         if( bIsThemeActive(szCurrentTheme, szCurrentColor, szCurrentSize) )
231         {
232             TRACE("Tried to load active theme again\n");
233             return;
234         }
235 
236         /* Make sure the theme requested is actually valid */
237         hr = MSSTYLES_OpenThemeFile(szCurrentTheme,
238                                     szCurrentColor[0]?szCurrentColor:NULL,
239                                     szCurrentSize[0]?szCurrentSize:NULL,
240                                     &pt);
241         if(FAILED(hr)) {
242             bThemeActive = FALSE;
243         }
244         else {
245             TRACE("Theme active: %s %s %s\n", debugstr_w(szCurrentTheme),
246                 debugstr_w(szCurrentColor), debugstr_w(szCurrentSize));
247 
248             UXTHEME_SetActiveTheme(pt);
249             MSSTYLES_CloseThemeFile(pt);
250         }
251     }
252     if(!bThemeActive) {
253         UXTHEME_SetActiveTheme(NULL);
254         TRACE("Theming not active\n");
255     }
256 }
257 
258 /***********************************************************************/
259 
260 static const char * const SysColorsNames[] =
261 {
262     "Scrollbar",                /* COLOR_SCROLLBAR */
263     "Background",               /* COLOR_BACKGROUND */
264     "ActiveTitle",              /* COLOR_ACTIVECAPTION */
265     "InactiveTitle",            /* COLOR_INACTIVECAPTION */
266     "Menu",                     /* COLOR_MENU */
267     "Window",                   /* COLOR_WINDOW */
268     "WindowFrame",              /* COLOR_WINDOWFRAME */
269     "MenuText",                 /* COLOR_MENUTEXT */
270     "WindowText",               /* COLOR_WINDOWTEXT */
271     "TitleText",                /* COLOR_CAPTIONTEXT */
272     "ActiveBorder",             /* COLOR_ACTIVEBORDER */
273     "InactiveBorder",           /* COLOR_INACTIVEBORDER */
274     "AppWorkSpace",             /* COLOR_APPWORKSPACE */
275     "Hilight",                  /* COLOR_HIGHLIGHT */
276     "HilightText",              /* COLOR_HIGHLIGHTTEXT */
277     "ButtonFace",               /* COLOR_BTNFACE */
278     "ButtonShadow",             /* COLOR_BTNSHADOW */
279     "GrayText",                 /* COLOR_GRAYTEXT */
280     "ButtonText",               /* COLOR_BTNTEXT */
281     "InactiveTitleText",        /* COLOR_INACTIVECAPTIONTEXT */
282     "ButtonHilight",            /* COLOR_BTNHIGHLIGHT */
283     "ButtonDkShadow",           /* COLOR_3DDKSHADOW */
284     "ButtonLight",              /* COLOR_3DLIGHT */
285     "InfoText",                 /* COLOR_INFOTEXT */
286     "InfoWindow",               /* COLOR_INFOBK */
287     "ButtonAlternateFace",      /* COLOR_ALTERNATEBTNFACE */
288     "HotTrackingColor",         /* COLOR_HOTLIGHT */
289     "GradientActiveTitle",      /* COLOR_GRADIENTACTIVECAPTION */
290     "GradientInactiveTitle",    /* COLOR_GRADIENTINACTIVECAPTION */
291     "MenuHilight",              /* COLOR_MENUHILIGHT */
292     "MenuBar",                  /* COLOR_MENUBAR */
293 };
294 static const WCHAR strColorKey[] =
295     { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
296       'C','o','l','o','r','s',0 };
297 static const WCHAR keyFlatMenus[] = { 'F','l','a','t','M','e','n','u', 0};
298 static const WCHAR keyGradientCaption[] = { 'G','r','a','d','i','e','n','t',
299                                             'C','a','p','t','i','o','n', 0 };
300 static const WCHAR keyNonClientMetrics[] = { 'N','o','n','C','l','i','e','n','t',
301                                              'M','e','t','r','i','c','s',0 };
302 static const WCHAR keyIconTitleFont[] = { 'I','c','o','n','T','i','t','l','e',
303 					  'F','o','n','t',0 };
304 
305 static const struct BackupSysParam
306 {
307     int spiGet, spiSet;
308     const WCHAR* keyName;
309 } backupSysParams[] =
310 {
311     {SPI_GETFLATMENU, SPI_SETFLATMENU, keyFlatMenus},
312     {SPI_GETGRADIENTCAPTIONS, SPI_SETGRADIENTCAPTIONS, keyGradientCaption},
313     {-1, -1, 0}
314 };
315 
316 #define NUM_SYS_COLORS     (COLOR_MENUBAR+1)
317 
save_sys_colors(HKEY baseKey)318 static void save_sys_colors (HKEY baseKey)
319 {
320     char colorStr[13];
321     HKEY hKey;
322     int i;
323 
324     if (RegCreateKeyExW( baseKey, strColorKey,
325                          0, 0, 0, KEY_ALL_ACCESS,
326                          0, &hKey, 0 ) == ERROR_SUCCESS)
327     {
328         for (i = 0; i < NUM_SYS_COLORS; i++)
329         {
330             COLORREF col = GetSysColor (i);
331 
332             sprintf (colorStr, "%d %d %d",
333                 GetRValue (col), GetGValue (col), GetBValue (col));
334 
335             RegSetValueExA (hKey, SysColorsNames[i], 0, REG_SZ,
336                 (BYTE*)colorStr, strlen (colorStr)+1);
337         }
338         RegCloseKey (hKey);
339     }
340 }
341 
342 /* Before activating a theme, query current system colors, certain settings
343  * and backup them in the registry, so they can be restored when the theme
344  * is deactivated */
UXTHEME_BackupSystemMetrics(void)345 static void UXTHEME_BackupSystemMetrics(void)
346 {
347     HKEY hKey;
348     const struct BackupSysParam* bsp = backupSysParams;
349 
350     if (RegCreateKeyExW( HKEY_CURRENT_USER, szThemeManager,
351                          0, 0, 0, KEY_ALL_ACCESS,
352                          0, &hKey, 0) == ERROR_SUCCESS)
353     {
354         NONCLIENTMETRICSW ncm;
355         LOGFONTW iconTitleFont;
356 
357         /* back up colors */
358         save_sys_colors (hKey);
359 
360         /* back up "other" settings */
361         while (bsp->spiGet >= 0)
362         {
363             DWORD value;
364 
365             SystemParametersInfoW (bsp->spiGet, 0, &value, 0);
366             RegSetValueExW (hKey, bsp->keyName, 0, REG_DWORD,
367                 (LPBYTE)&value, sizeof (value));
368 
369             bsp++;
370         }
371 
372 	/* back up non-client metrics */
373         memset (&ncm, 0, sizeof (ncm));
374         ncm.cbSize = sizeof (ncm);
375         SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof (ncm), &ncm, 0);
376         RegSetValueExW (hKey, keyNonClientMetrics, 0, REG_BINARY, (LPBYTE)&ncm,
377             sizeof (ncm));
378 	memset (&iconTitleFont, 0, sizeof (iconTitleFont));
379 	SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof (iconTitleFont),
380 	    &iconTitleFont, 0);
381 	RegSetValueExW (hKey, keyIconTitleFont, 0, REG_BINARY,
382 	    (LPBYTE)&iconTitleFont, sizeof (iconTitleFont));
383 
384         RegCloseKey (hKey);
385     }
386 }
387 
388 /* Read back old settings after a theme was deactivated */
UXTHEME_RestoreSystemMetrics(void)389 static void UXTHEME_RestoreSystemMetrics(void)
390 {
391     HKEY hKey;
392     const struct BackupSysParam* bsp = backupSysParams;
393 
394     if (RegOpenKeyExW (HKEY_CURRENT_USER, szThemeManager,
395                        0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
396     {
397         HKEY colorKey;
398 
399         /* read backed-up colors */
400         if (RegOpenKeyExW (hKey, strColorKey,
401                            0, KEY_QUERY_VALUE, &colorKey) == ERROR_SUCCESS)
402         {
403             int i;
404             COLORREF sysCols[NUM_SYS_COLORS];
405             int sysColsIndices[NUM_SYS_COLORS];
406             int sysColCount = 0;
407 
408             for (i = 0; i < NUM_SYS_COLORS; i++)
409             {
410                 DWORD type;
411                 char colorStr[13];
412                 DWORD count = sizeof(colorStr);
413 
414                 if (RegQueryValueExA (colorKey, SysColorsNames[i], 0,
415                     &type, (LPBYTE) colorStr, &count) == ERROR_SUCCESS)
416                 {
417                     int r, g, b;
418                     if (sscanf (colorStr, "%d %d %d", &r, &g, &b) == 3)
419                     {
420                         sysColsIndices[sysColCount] = i;
421                         sysCols[sysColCount] = RGB(r, g, b);
422                         sysColCount++;
423                     }
424                 }
425             }
426             RegCloseKey (colorKey);
427 
428             SetSysColors (sysColCount, sysColsIndices, sysCols);
429         }
430 
431         /* read backed-up other settings */
432         while (bsp->spiGet >= 0)
433         {
434             DWORD value;
435             DWORD count = sizeof(value);
436             DWORD type;
437 
438             if (RegQueryValueExW (hKey, bsp->keyName, 0,
439                 &type, (LPBYTE)&value, &count) == ERROR_SUCCESS)
440             {
441                 SystemParametersInfoW (bsp->spiSet, 0, UlongToPtr(value), SPIF_UPDATEINIFILE);
442             }
443 
444             bsp++;
445         }
446 
447         /* read backed-up non-client metrics */
448         {
449             NONCLIENTMETRICSW ncm;
450             LOGFONTW iconTitleFont;
451             DWORD count = sizeof(ncm);
452             DWORD type;
453 
454 	    if (RegQueryValueExW (hKey, keyNonClientMetrics, 0,
455 		&type, (LPBYTE)&ncm, &count) == ERROR_SUCCESS)
456 	    {
457 		SystemParametersInfoW (SPI_SETNONCLIENTMETRICS,
458                     count, &ncm, SPIF_UPDATEINIFILE);
459 	    }
460 
461             count = sizeof(iconTitleFont);
462 
463 	    if (RegQueryValueExW (hKey, keyIconTitleFont, 0,
464 		&type, (LPBYTE)&iconTitleFont, &count) == ERROR_SUCCESS)
465 	    {
466 		SystemParametersInfoW (SPI_SETICONTITLELOGFONT,
467                     count, &iconTitleFont, SPIF_UPDATEINIFILE);
468 	    }
469 	}
470 
471         RegCloseKey (hKey);
472     }
473 }
474 
475 /* Make system settings persistent, so they're in effect even w/o uxtheme
476  * loaded.
477  * For efficiency reasons, only the last SystemParametersInfoW sets
478  * SPIF_SENDCHANGE */
UXTHEME_SaveSystemMetrics(void)479 static void UXTHEME_SaveSystemMetrics(void)
480 {
481     const struct BackupSysParam* bsp = backupSysParams;
482     NONCLIENTMETRICSW ncm;
483     LOGFONTW iconTitleFont;
484 
485     save_sys_colors (HKEY_CURRENT_USER);
486 
487     while (bsp->spiGet >= 0)
488     {
489         DWORD value;
490 
491         SystemParametersInfoW (bsp->spiGet, 0, &value, 0);
492         SystemParametersInfoW (bsp->spiSet, 0, UlongToPtr(value), SPIF_UPDATEINIFILE);
493         bsp++;
494     }
495 
496     memset (&ncm, 0, sizeof (ncm));
497     ncm.cbSize = sizeof (ncm);
498     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof (ncm), &ncm, 0);
499     SystemParametersInfoW (SPI_SETNONCLIENTMETRICS, sizeof (ncm), &ncm,
500         SPIF_UPDATEINIFILE);
501 
502     memset (&iconTitleFont, 0, sizeof (iconTitleFont));
503     SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof (iconTitleFont),
504         &iconTitleFont, 0);
505     SystemParametersInfoW (SPI_SETICONTITLELOGFONT, sizeof (iconTitleFont),
506         &iconTitleFont, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
507 }
508 
509 /***********************************************************************
510  *      UXTHEME_ApplyTheme
511  *
512  * Change the current active theme
513  */
UXTHEME_ApplyTheme(PTHEME_FILE tf)514 static HRESULT UXTHEME_ApplyTheme(PTHEME_FILE tf)
515 {
516     HKEY hKey;
517     WCHAR tmp[2];
518     HRESULT hr;
519 
520     TRACE("UXTHEME_ApplyTheme\n");
521 
522     if (tf && !g_ActiveThemeFile)
523     {
524         UXTHEME_BackupSystemMetrics();
525     }
526 
527     hr = UXTHEME_SetActiveTheme(tf);
528     if (FAILED(hr))
529         return hr;
530 
531     if (!tf)
532     {
533         UXTHEME_RestoreSystemMetrics();
534     }
535 
536     TRACE("Writing theme config to registry\n");
537     if(!RegCreateKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
538         tmp[0] = g_ActiveThemeFile ? '1' : '0';
539         tmp[1] = '\0';
540         RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (const BYTE*)tmp, sizeof(WCHAR)*2);
541         if (g_ActiveThemeFile) {
542             RegSetValueExW(hKey, szColorName, 0, REG_SZ, (const BYTE*)tf->pszSelectedColor,
543 		(lstrlenW(tf->pszSelectedColor)+1)*sizeof(WCHAR));
544             RegSetValueExW(hKey, szSizeName, 0, REG_SZ, (const BYTE*)tf->pszSelectedSize,
545 		(lstrlenW(tf->pszSelectedSize)+1)*sizeof(WCHAR));
546             RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*)tf->szThemeFile,
547 		(lstrlenW(tf->szThemeFile)+1)*sizeof(WCHAR));
548         }
549         else {
550             RegDeleteValueW(hKey, szColorName);
551             RegDeleteValueW(hKey, szSizeName);
552             RegDeleteValueW(hKey, szDllName);
553 
554         }
555         RegCloseKey(hKey);
556     }
557     else
558         TRACE("Failed to open theme registry key\n");
559 
560     UXTHEME_SaveSystemMetrics ();
561 
562     return hr;
563 }
564 
565 /***********************************************************************
566  *      UXTHEME_InitSystem
567  */
UXTHEME_InitSystem(HINSTANCE hInst)568 void UXTHEME_InitSystem(HINSTANCE hInst)
569 {
570     static const WCHAR szWindowTheme[] = {
571         'u','x','_','t','h','e','m','e','\0'
572     };
573     static const WCHAR szSubAppName[] = {
574         'u','x','_','s','u','b','a','p','p','\0'
575     };
576     static const WCHAR szSubIdList[] = {
577         'u','x','_','s','u','b','i','d','l','s','t','\0'
578     };
579     static const WCHAR szDialogThemeEnabled[] = {
580         'u','x','_','d','i','a','l','o','g','t','h','e','m','e','\0'
581     };
582 
583     hDllInst = hInst;
584 
585     atWindowTheme        = GlobalAddAtomW(szWindowTheme);
586     atSubAppName         = GlobalAddAtomW(szSubAppName);
587     atSubIdList          = GlobalAddAtomW(szSubIdList);
588     atDialogThemeEnabled = GlobalAddAtomW(szDialogThemeEnabled);
589     atWndContext        = GlobalAddAtomW(L"ux_WndContext");
590 
591     RtlInitializeHandleTable(0xFFF, sizeof(UXTHEME_HANDLE), &g_UxThemeHandleTable);
592     g_cHandles = 0;
593 
594     gdwErrorInfoTlsIndex = TlsAlloc();
595 }
596 
597 /***********************************************************************
598  *      UXTHEME_UnInitSystem
599  */
UXTHEME_UnInitSystem(HINSTANCE hInst)600 void UXTHEME_UnInitSystem(HINSTANCE hInst)
601 {
602     UXTHEME_DeleteParseErrorInfo();
603 
604     TlsFree(gdwErrorInfoTlsIndex);
605     gdwErrorInfoTlsIndex = TLS_OUT_OF_INDEXES;
606 }
607 
608 /***********************************************************************
609  *      IsAppThemed                                         (UXTHEME.@)
610  */
IsAppThemed(void)611 BOOL WINAPI IsAppThemed(void)
612 {
613     TRACE("\n");
614     SetLastError(ERROR_SUCCESS);
615     return (g_ActiveThemeFile != NULL);
616 }
617 
618 /***********************************************************************
619  *      IsThemeActive                                       (UXTHEME.@)
620  */
IsThemeActive(void)621 BOOL WINAPI IsThemeActive(void)
622 {
623     BOOL bActive;
624     LRESULT Result;
625     HKEY hKey;
626     WCHAR tmp[10];
627     DWORD buffsize;
628 
629     TRACE("IsThemeActive\n");
630     SetLastError(ERROR_SUCCESS);
631 
632     if (g_ActiveThemeFile)
633         return TRUE;
634 
635     if (g_bThemeHooksActive)
636         return FALSE;
637 
638     bActive = FALSE;
639     Result = RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey);
640     if (Result == ERROR_SUCCESS)
641     {
642         buffsize = sizeof(tmp);
643         if (!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize))
644             bActive = (tmp[0] != '0');
645         RegCloseKey(hKey);
646     }
647 
648     return bActive;
649 }
650 
651 /***********************************************************************
652  *      EnableTheming                                       (UXTHEME.@)
653  *
654  * NOTES
655  * This is a global and persistent change
656  */
EnableTheming(BOOL fEnable)657 HRESULT WINAPI EnableTheming(BOOL fEnable)
658 {
659     HKEY hKey;
660     WCHAR szEnabled[] = {'0','\0'};
661 
662     TRACE("(%d)\n", fEnable);
663 
664     if (fEnable != (g_ActiveThemeFile != NULL)) {
665         if(fEnable)
666             UXTHEME_BackupSystemMetrics();
667         else
668             UXTHEME_RestoreSystemMetrics();
669         UXTHEME_SaveSystemMetrics ();
670 
671         if (fEnable) szEnabled[0] = '1';
672         if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
673             RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (LPBYTE)szEnabled, sizeof(WCHAR));
674             RegCloseKey(hKey);
675         }
676 	UXTHEME_broadcast_theme_changed (NULL, fEnable);
677     }
678     return S_OK;
679 }
680 
681 /***********************************************************************
682  *      UXTHEME_SetWindowProperty
683  *
684  * I'm using atoms as there may be large numbers of duplicated strings
685  * and they do the work of keeping memory down as a cause of that quite nicely
686  */
UXTHEME_SetWindowProperty(HWND hwnd,ATOM aProp,LPCWSTR pszValue)687 static HRESULT UXTHEME_SetWindowProperty(HWND hwnd, ATOM aProp, LPCWSTR pszValue)
688 {
689     ATOM oldValue = (ATOM)(size_t)RemovePropW(hwnd, (LPCWSTR)MAKEINTATOM(aProp));
690     if(oldValue)
691     {
692         DeleteAtom(oldValue);
693     }
694 
695     if(pszValue)
696     {
697         ATOM atValue;
698 
699         /* A string with zero lenght is not acceptatble in AddAtomW but we want to support
700            users passing an empty string meaning they want no theme for the specified window */
701         if(!pszValue[0])
702             pszValue = L"0";
703 
704         atValue = AddAtomW(pszValue);
705         if (!atValue)
706         {
707             ERR("AddAtomW for %S failed with last error %d!\n", pszValue, GetLastError());
708             return HRESULT_FROM_WIN32(GetLastError());
709         }
710 
711         if (!SetPropW(hwnd, (LPCWSTR)MAKEINTATOM(aProp), (LPWSTR)MAKEINTATOM(atValue)))
712         {
713             ERR("SetPropW for atom %d failed with last error %d\n", aProp, GetLastError());
714             if(atValue) DeleteAtom(atValue);
715             return HRESULT_FROM_WIN32(GetLastError());
716         }
717     }
718     return S_OK;
719 }
720 
UXTHEME_GetWindowProperty(HWND hwnd,ATOM aProp,LPWSTR pszBuffer,int dwLen)721 static LPWSTR UXTHEME_GetWindowProperty(HWND hwnd, ATOM aProp, LPWSTR pszBuffer, int dwLen)
722 {
723     ATOM atValue = (ATOM)(size_t)GetPropW(hwnd, (LPCWSTR)MAKEINTATOM(aProp));
724     if(atValue) {
725         if(GetAtomNameW(atValue, pszBuffer, dwLen))
726             return pszBuffer;
727         TRACE("property defined, but unable to get value\n");
728     }
729     return NULL;
730 }
731 
ValidateHandle(HTHEME hTheme)732 PTHEME_CLASS ValidateHandle(HTHEME hTheme)
733 {
734     PUXTHEME_HANDLE pHandle;
735 
736     if (!g_bThemeHooksActive || !hTheme || hTheme == INVALID_HANDLE_VALUE)
737         return NULL;
738 
739     if (!RtlIsValidHandle(&g_UxThemeHandleTable, (PRTL_HANDLE_TABLE_ENTRY)hTheme))
740     {
741         ERR("Invalid handle 0x%x!\n", hTheme);
742         return NULL;
743     }
744 
745     pHandle = hTheme;
746     return pHandle->pClass;
747 }
748 
749 static HTHEME WINAPI
OpenThemeDataInternal(PTHEME_FILE ThemeFile,HWND hwnd,LPCWSTR pszClassList,DWORD flags)750 OpenThemeDataInternal(PTHEME_FILE ThemeFile, HWND hwnd, LPCWSTR pszClassList, DWORD flags)
751 {
752     WCHAR szAppBuff[256];
753     WCHAR szClassBuff[256];
754     LPCWSTR pszAppName;
755     LPCWSTR pszUseClassList;
756     HTHEME hTheme = NULL;
757     TRACE("(%p,%s, %x)\n", hwnd, debugstr_w(pszClassList), flags);
758 
759     if(!pszClassList)
760     {
761         SetLastError(E_POINTER);
762         return NULL;
763     }
764 
765     if ((flags & OTD_NONCLIENT) && !(dwThemeAppProperties & STAP_ALLOW_NONCLIENT))
766     {
767         SetLastError(E_PROP_ID_UNSUPPORTED);
768         return NULL;
769     }
770 
771     if (!(flags & OTD_NONCLIENT) && !(dwThemeAppProperties & STAP_ALLOW_CONTROLS))
772     {
773         SetLastError(E_PROP_ID_UNSUPPORTED);
774         return NULL;
775     }
776 
777     if (ThemeFile)
778     {
779         pszAppName = UXTHEME_GetWindowProperty(hwnd, atSubAppName, szAppBuff, sizeof(szAppBuff)/sizeof(szAppBuff[0]));
780         /* If SetWindowTheme was used on the window, that overrides the class list passed to this function */
781         pszUseClassList = UXTHEME_GetWindowProperty(hwnd, atSubIdList, szClassBuff, sizeof(szClassBuff)/sizeof(szClassBuff[0]));
782         if(!pszUseClassList)
783             pszUseClassList = pszClassList;
784 
785          if (pszUseClassList)
786          {
787             PTHEME_CLASS pClass;
788             PUXTHEME_HANDLE pHandle;
789 
790              if (!ThemeFile->classes)
791                  MSSTYLES_ParseThemeIni(ThemeFile);
792             pClass = MSSTYLES_OpenThemeClass(ThemeFile, pszAppName, pszUseClassList);
793 
794             if (pClass)
795             {
796                 pHandle = (PUXTHEME_HANDLE)RtlAllocateHandle(&g_UxThemeHandleTable, NULL);
797                 if (pHandle)
798                 {
799                     g_cHandles++;
800                     TRACE("Created handle 0x%x for class 0x%x, app %S, class %S. Count: %d\n", pHandle, pClass, pszAppName, pszUseClassList, g_cHandles);
801                     pHandle->pClass = pClass;
802                     pHandle->Handle.Flags = RTL_HANDLE_VALID;
803                     hTheme = pHandle;
804                 }
805                 else
806                 {
807                     MSSTYLES_CloseThemeClass(pClass);
808                 }
809             }
810         }
811     }
812 
813     if(IsWindow(hwnd))
814     {
815         if ((flags & OTD_NONCLIENT) == 0)
816         {
817             SetPropW(hwnd, (LPCWSTR)MAKEINTATOM(atWindowTheme), hTheme);
818         }
819     }
820     else
821     {
822         SetLastError(E_PROP_ID_UNSUPPORTED);
823     }
824 
825     SetLastError(hTheme ? ERROR_SUCCESS : E_PROP_ID_UNSUPPORTED);
826 
827     TRACE(" = %p\n", hTheme);
828     return hTheme;
829 }
830 
831 /***********************************************************************
832  *      OpenThemeDataEx                                     (UXTHEME.61)
833  */
OpenThemeDataEx(HWND hwnd,LPCWSTR pszClassList,DWORD flags)834 HTHEME WINAPI OpenThemeDataEx(HWND hwnd, LPCWSTR pszClassList, DWORD flags)
835 {
836     return OpenThemeDataInternal(g_ActiveThemeFile, hwnd, pszClassList, flags);
837 }
838 
839 /***********************************************************************
840  *      OpenThemeDataFromFile                               (UXTHEME.16)
841  */
OpenThemeDataFromFile(HTHEMEFILE hThemeFile,HWND hwnd,LPCWSTR pszClassList,DWORD flags)842 HTHEME WINAPI OpenThemeDataFromFile(HTHEMEFILE hThemeFile, HWND hwnd, LPCWSTR pszClassList, DWORD flags)
843 {
844     return OpenThemeDataInternal((PTHEME_FILE)hThemeFile, hwnd, pszClassList, flags);
845 }
846 
847 /***********************************************************************
848  *      OpenThemeData                                       (UXTHEME.@)
849  */
OpenThemeData(HWND hwnd,LPCWSTR classlist)850 HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR classlist)
851 {
852     return OpenThemeDataInternal(g_ActiveThemeFile, hwnd, classlist, 0);
853 }
854 
855 /***********************************************************************
856  *      GetWindowTheme                                      (UXTHEME.@)
857  *
858  * Retrieve the last theme opened for a window.
859  *
860  * PARAMS
861  *  hwnd  [I] window to retrieve the theme for
862  *
863  * RETURNS
864  *  The most recent theme.
865  */
GetWindowTheme(HWND hwnd)866 HTHEME WINAPI GetWindowTheme(HWND hwnd)
867 {
868     TRACE("(%p)\n", hwnd);
869 
870 	if(!IsWindow(hwnd))
871     {
872 		SetLastError(E_HANDLE);
873         return NULL;
874     }
875 
876     return GetPropW(hwnd, (LPCWSTR)MAKEINTATOM(atWindowTheme));
877 }
878 
879 /***********************************************************************
880  *      SetWindowTheme                                      (UXTHEME.@)
881  *
882  * Persistent through the life of the window, even after themes change
883  */
SetWindowTheme(HWND hwnd,LPCWSTR pszSubAppName,LPCWSTR pszSubIdList)884 HRESULT WINAPI SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName,
885                               LPCWSTR pszSubIdList)
886 {
887     HRESULT hr;
888     TRACE("(%p,%s,%s)\n", hwnd, debugstr_w(pszSubAppName),
889         debugstr_w(pszSubIdList));
890 
891     if(!IsWindow(hwnd))
892         return E_HANDLE;
893 
894     hr = UXTHEME_SetWindowProperty(hwnd, atSubAppName, pszSubAppName);
895     if (!SUCCEEDED(hr))
896         return hr;
897 
898     hr = UXTHEME_SetWindowProperty(hwnd, atSubIdList, pszSubIdList);
899     if (!SUCCEEDED(hr))
900         return hr;
901 
902     UXTHEME_broadcast_theme_changed (hwnd, TRUE);
903     return hr;
904 }
905 
906 /***********************************************************************
907  *      GetCurrentThemeName                                 (UXTHEME.@)
908  */
GetCurrentThemeName(LPWSTR pszThemeFileName,int dwMaxNameChars,LPWSTR pszColorBuff,int cchMaxColorChars,LPWSTR pszSizeBuff,int cchMaxSizeChars)909 HRESULT WINAPI GetCurrentThemeName(LPWSTR pszThemeFileName, int dwMaxNameChars,
910                                    LPWSTR pszColorBuff, int cchMaxColorChars,
911                                    LPWSTR pszSizeBuff, int cchMaxSizeChars)
912 {
913     int cchar;
914 
915     if(g_ActiveThemeFile == NULL)
916          return E_PROP_ID_UNSUPPORTED;
917 
918     if (pszThemeFileName && dwMaxNameChars)
919     {
920         cchar = lstrlenW(g_ActiveThemeFile->szThemeFile) + 1;
921         if(cchar > dwMaxNameChars)
922            return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
923         lstrcpynW(pszThemeFileName, g_ActiveThemeFile->szThemeFile, cchar);
924     }
925 
926     if (pszColorBuff && cchMaxColorChars)
927     {
928         cchar = lstrlenW(g_ActiveThemeFile->pszSelectedColor) + 1;
929         if(cchar > cchMaxColorChars)
930             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
931         lstrcpynW(pszColorBuff, g_ActiveThemeFile->pszSelectedColor, cchar);
932     }
933 
934    if (pszSizeBuff && cchMaxSizeChars)
935     {
936         cchar = lstrlenW(g_ActiveThemeFile->pszSelectedSize) + 1;
937         if(cchar > cchMaxSizeChars)
938             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
939         lstrcpynW(pszSizeBuff, g_ActiveThemeFile->pszSelectedSize, cchar);
940     }
941 
942     return S_OK;
943 }
944 
945 /***********************************************************************
946  *      GetThemeAppProperties                               (UXTHEME.@)
947  */
GetThemeAppProperties(void)948 DWORD WINAPI GetThemeAppProperties(void)
949 {
950     return dwThemeAppProperties;
951 }
952 
953 /***********************************************************************
954  *      SetThemeAppProperties                               (UXTHEME.@)
955  */
SetThemeAppProperties(DWORD dwFlags)956 void WINAPI SetThemeAppProperties(DWORD dwFlags)
957 {
958     TRACE("(0x%08x)\n", dwFlags);
959     dwThemeAppProperties = dwFlags;
960 }
961 
962 /***********************************************************************
963  *      CloseThemeData                                      (UXTHEME.@)
964  */
CloseThemeData(HTHEME hTheme)965 HRESULT WINAPI CloseThemeData(HTHEME hTheme)
966 {
967     PUXTHEME_HANDLE pHandle = hTheme;
968     HRESULT hr;
969 
970     TRACE("(%p)\n", hTheme);
971 
972     if (!RtlIsValidHandle(&g_UxThemeHandleTable, (PRTL_HANDLE_TABLE_ENTRY)hTheme))
973         return E_HANDLE;
974 
975     hr = MSSTYLES_CloseThemeClass(pHandle->pClass);
976     if (SUCCEEDED(hr))
977     {
978         RtlFreeHandle(&g_UxThemeHandleTable, (PRTL_HANDLE_TABLE_ENTRY)pHandle);
979         g_cHandles--;
980         TRACE("Destroying handle 0x%x for class 0x%x. Count: %d\n", pHandle, pHandle->pClass, g_cHandles);
981     }
982     return hr;
983 }
984 
985 /***********************************************************************
986  *      HitTestThemeBackground                              (UXTHEME.@)
987  */
HitTestThemeBackground(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,DWORD dwOptions,const RECT * pRect,HRGN hrgn,POINT ptTest,WORD * pwHitTestCode)988 HRESULT WINAPI HitTestThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
989                                      int iStateId, DWORD dwOptions,
990                                      const RECT *pRect, HRGN hrgn,
991                                      POINT ptTest, WORD *pwHitTestCode)
992 {
993     FIXME("%d %d 0x%08x: stub\n", iPartId, iStateId, dwOptions);
994     if (!ValidateHandle(hTheme))
995         return E_HANDLE;
996     return E_NOTIMPL;
997 }
998 
999 /***********************************************************************
1000  *      IsThemePartDefined                                  (UXTHEME.@)
1001  */
IsThemePartDefined(HTHEME hTheme,int iPartId,int iStateId)1002 BOOL WINAPI IsThemePartDefined(HTHEME hTheme, int iPartId, int iStateId)
1003 {
1004     PTHEME_CLASS pClass;
1005 
1006     TRACE("(%p,%d,%d)\n", hTheme, iPartId, iStateId);
1007 
1008     pClass = ValidateHandle(hTheme);
1009     if (!pClass)
1010     {
1011         SetLastError(E_HANDLE);
1012         return FALSE;
1013     }
1014     if(MSSTYLES_FindPartState(pClass, iPartId, iStateId, NULL))
1015         return TRUE;
1016     return FALSE;
1017 }
1018 
1019 /***********************************************************************
1020  *      GetThemeDocumentationProperty                       (UXTHEME.@)
1021  *
1022  * Try and retrieve the documentation property from string resources
1023  * if that fails, get it from the [documentation] section of themes.ini
1024  */
GetThemeDocumentationProperty(LPCWSTR pszThemeName,LPCWSTR pszPropertyName,LPWSTR pszValueBuff,int cchMaxValChars)1025 HRESULT WINAPI GetThemeDocumentationProperty(LPCWSTR pszThemeName,
1026                                              LPCWSTR pszPropertyName,
1027                                              LPWSTR pszValueBuff,
1028                                              int cchMaxValChars)
1029 {
1030     const WORD wDocToRes[] = {
1031         TMT_DISPLAYNAME,5000,
1032         TMT_TOOLTIP,5001,
1033         TMT_COMPANY,5002,
1034         TMT_AUTHOR,5003,
1035         TMT_COPYRIGHT,5004,
1036         TMT_URL,5005,
1037         TMT_VERSION,5006,
1038         TMT_DESCRIPTION,5007
1039     };
1040 
1041     PTHEME_FILE pt;
1042     HRESULT hr;
1043     unsigned int i;
1044     int iDocId;
1045     TRACE("(%s,%s,%p,%d)\n", debugstr_w(pszThemeName), debugstr_w(pszPropertyName),
1046           pszValueBuff, cchMaxValChars);
1047 
1048     if (!g_bThemeHooksActive)
1049         return E_FAIL;
1050 
1051     hr = MSSTYLES_OpenThemeFile(pszThemeName, NULL, NULL, &pt);
1052     if(FAILED(hr)) return hr;
1053 
1054     /* Try to load from string resources */
1055     hr = E_PROP_ID_UNSUPPORTED;
1056     if(MSSTYLES_LookupProperty(pszPropertyName, NULL, &iDocId)) {
1057         for(i=0; i<sizeof(wDocToRes)/sizeof(wDocToRes[0]); i+=2) {
1058             if(wDocToRes[i] == iDocId) {
1059                 if(LoadStringW(pt->hTheme, wDocToRes[i+1], pszValueBuff, cchMaxValChars)) {
1060                     hr = S_OK;
1061                     break;
1062                 }
1063             }
1064         }
1065     }
1066     /* If loading from string resource failed, try getting it from the theme.ini */
1067     if(FAILED(hr)) {
1068         PUXINI_FILE uf = MSSTYLES_GetThemeIni(pt);
1069         if(UXINI_FindSection(uf, szIniDocumentation)) {
1070             LPCWSTR lpValue;
1071             DWORD dwLen;
1072             if(UXINI_FindValue(uf, pszPropertyName, &lpValue, &dwLen)) {
1073                 lstrcpynW(pszValueBuff, lpValue, min(dwLen+1,cchMaxValChars));
1074                 hr = S_OK;
1075             }
1076         }
1077         UXINI_CloseINI(uf);
1078     }
1079 
1080     MSSTYLES_CloseThemeFile(pt);
1081     return hr;
1082 }
1083 
1084 /**********************************************************************
1085  *      Undocumented functions
1086  */
1087 
1088 /**********************************************************************
1089  *      QueryThemeServices                                 (UXTHEME.1)
1090  *
1091  * RETURNS
1092  *     some kind of status flag
1093  */
QueryThemeServices(void)1094 DWORD WINAPI QueryThemeServices(void)
1095 {
1096     FIXME("stub\n");
1097     return 3; /* This is what is returned under XP in most cases */
1098 }
1099 
1100 
1101 /**********************************************************************
1102  *      OpenThemeFile                                      (UXTHEME.2)
1103  *
1104  * Opens a theme file, which can be used to change the current theme, etc
1105  *
1106  * PARAMS
1107  *     pszThemeFileName    Path to a msstyles theme file
1108  *     pszColorName        Color defined in the theme, eg. NormalColor
1109  *     pszSizeName         Size defined in the theme, eg. NormalSize
1110  *     hThemeFile          Handle to theme file
1111  *
1112  * RETURNS
1113  *     Success: S_OK
1114  *     Failure: HRESULT error-code
1115  */
OpenThemeFile(LPCWSTR pszThemeFileName,LPCWSTR pszColorName,LPCWSTR pszSizeName,HTHEMEFILE * hThemeFile,DWORD unknown)1116 HRESULT WINAPI OpenThemeFile(LPCWSTR pszThemeFileName, LPCWSTR pszColorName,
1117                              LPCWSTR pszSizeName, HTHEMEFILE *hThemeFile,
1118                              DWORD unknown)
1119 {
1120     TRACE("(%s,%s,%s,%p,%d)\n", debugstr_w(pszThemeFileName),
1121           debugstr_w(pszColorName), debugstr_w(pszSizeName),
1122           hThemeFile, unknown);
1123 
1124     if (!g_bThemeHooksActive)
1125         return E_FAIL;
1126 
1127     return MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, (PTHEME_FILE*)hThemeFile);
1128 }
1129 
1130 /**********************************************************************
1131  *      CloseThemeFile                                     (UXTHEME.3)
1132  *
1133  * Releases theme file handle returned by OpenThemeFile
1134  *
1135  * PARAMS
1136  *     hThemeFile           Handle to theme file
1137  *
1138  * RETURNS
1139  *     Success: S_OK
1140  *     Failure: HRESULT error-code
1141  */
CloseThemeFile(HTHEMEFILE hThemeFile)1142 HRESULT WINAPI CloseThemeFile(HTHEMEFILE hThemeFile)
1143 {
1144     TRACE("(%p)\n", hThemeFile);
1145     MSSTYLES_CloseThemeFile(hThemeFile);
1146     return S_OK;
1147 }
1148 
1149 /**********************************************************************
1150  *      ApplyTheme                                         (UXTHEME.4)
1151  *
1152  * Set a theme file to be the currently active theme
1153  *
1154  * PARAMS
1155  *     hThemeFile           Handle to theme file
1156  *     unknown              See notes
1157  *     hWnd                 Window requesting the theme change
1158  *
1159  * RETURNS
1160  *     Success: S_OK
1161  *     Failure: HRESULT error-code
1162  *
1163  * NOTES
1164  * I'm not sure what the second parameter is (the datatype is likely wrong), other then this:
1165  * Under XP if I pass
1166  * char b[] = "";
1167  *   the theme is applied with the screen redrawing really badly (flickers)
1168  * char b[] = "\0"; where \0 can be one or more of any character, makes no difference
1169  *   the theme is applied smoothly (screen does not flicker)
1170  * char *b = "\0" or NULL; where \0 can be zero or more of any character, makes no difference
1171  *   the function fails returning invalid parameter... very strange
1172  */
ApplyTheme(HTHEMEFILE hThemeFile,char * unknown,HWND hWnd)1173 HRESULT WINAPI ApplyTheme(HTHEMEFILE hThemeFile, char *unknown, HWND hWnd)
1174 {
1175     HRESULT hr;
1176     TRACE("(%p,%s,%p)\n", hThemeFile, unknown, hWnd);
1177     hr = UXTHEME_ApplyTheme(hThemeFile);
1178     UXTHEME_broadcast_theme_changed (NULL, (g_ActiveThemeFile != NULL));
1179     return hr;
1180 }
1181 
1182 /**********************************************************************
1183  *      GetThemeDefaults                                   (UXTHEME.7)
1184  *
1185  * Get the default color & size for a theme
1186  *
1187  * PARAMS
1188  *     pszThemeFileName    Path to a msstyles theme file
1189  *     pszColorName        Buffer to receive the default color name
1190  *     dwColorNameLen      Length, in characters, of color name buffer
1191  *     pszSizeName         Buffer to receive the default size name
1192  *     dwSizeNameLen       Length, in characters, of size name buffer
1193  *
1194  * RETURNS
1195  *     Success: S_OK
1196  *     Failure: HRESULT error-code
1197  */
GetThemeDefaults(LPCWSTR pszThemeFileName,LPWSTR pszColorName,DWORD dwColorNameLen,LPWSTR pszSizeName,DWORD dwSizeNameLen)1198 HRESULT WINAPI GetThemeDefaults(LPCWSTR pszThemeFileName, LPWSTR pszColorName,
1199                                 DWORD dwColorNameLen, LPWSTR pszSizeName,
1200                                 DWORD dwSizeNameLen)
1201 {
1202     PTHEME_FILE pt;
1203     HRESULT hr;
1204     TRACE("(%s,%p,%d,%p,%d)\n", debugstr_w(pszThemeFileName),
1205           pszColorName, dwColorNameLen,
1206           pszSizeName, dwSizeNameLen);
1207 
1208     if (!g_bThemeHooksActive)
1209         return E_FAIL;
1210 
1211     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, NULL, &pt);
1212     if(FAILED(hr)) return hr;
1213 
1214     lstrcpynW(pszColorName, pt->pszSelectedColor, dwColorNameLen);
1215     lstrcpynW(pszSizeName, pt->pszSelectedSize, dwSizeNameLen);
1216 
1217     MSSTYLES_CloseThemeFile(pt);
1218     return S_OK;
1219 }
1220 
1221 /**********************************************************************
1222  *      EnumThemes                                         (UXTHEME.8)
1223  *
1224  * Enumerate available themes, calls specified EnumThemeProc for each
1225  * theme found. Passes lpData through to callback function.
1226  *
1227  * PARAMS
1228  *     pszThemePath        Path containing themes
1229  *     callback            Called for each theme found in path
1230  *     lpData              Passed through to callback
1231  *
1232  * RETURNS
1233  *     Success: S_OK
1234  *     Failure: HRESULT error-code
1235  */
EnumThemes(LPCWSTR pszThemePath,ENUMTHEMEPROC callback,LPVOID lpData)1236 HRESULT WINAPI EnumThemes(LPCWSTR pszThemePath, ENUMTHEMEPROC callback,
1237                           LPVOID lpData)
1238 {
1239     WCHAR szDir[MAX_PATH];
1240     WCHAR szPath[MAX_PATH];
1241     static const WCHAR szStar[] = {'*','.','*','\0'};
1242     static const WCHAR szFormat[] = {'%','s','%','s','\\','%','s','.','m','s','s','t','y','l','e','s','\0'};
1243     static const WCHAR szDisplayName[] = {'d','i','s','p','l','a','y','n','a','m','e','\0'};
1244     static const WCHAR szTooltip[] = {'t','o','o','l','t','i','p','\0'};
1245     WCHAR szName[60];
1246     WCHAR szTip[60];
1247     HANDLE hFind;
1248     WIN32_FIND_DATAW wfd;
1249     HRESULT hr;
1250     size_t pathLen;
1251 
1252     TRACE("(%s,%p,%p)\n", debugstr_w(pszThemePath), callback, lpData);
1253 
1254     if(!pszThemePath || !callback)
1255         return E_POINTER;
1256 
1257     lstrcpyW(szDir, pszThemePath);
1258     pathLen = lstrlenW (szDir);
1259     if ((pathLen > 0) && (pathLen < MAX_PATH-1) && (szDir[pathLen - 1] != '\\'))
1260     {
1261         szDir[pathLen] = '\\';
1262         szDir[pathLen+1] = 0;
1263     }
1264 
1265     lstrcpyW(szPath, szDir);
1266     lstrcatW(szPath, szStar);
1267     TRACE("searching %s\n", debugstr_w(szPath));
1268 
1269     hFind = FindFirstFileW(szPath, &wfd);
1270     if(hFind != INVALID_HANDLE_VALUE) {
1271         do {
1272             if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
1273                && !(wfd.cFileName[0] == '.' && ((wfd.cFileName[1] == '.' && wfd.cFileName[2] == 0) || wfd.cFileName[1] == 0))) {
1274                 wsprintfW(szPath, szFormat, szDir, wfd.cFileName, wfd.cFileName);
1275 
1276                 hr = GetThemeDocumentationProperty(szPath, szDisplayName, szName, sizeof(szName)/sizeof(szName[0]));
1277                 if(FAILED(hr))
1278                 {
1279                     ERR("Failed to get theme name from %S\n", szPath);
1280                     continue;
1281                 }
1282 
1283                 hr = GetThemeDocumentationProperty(szPath, szTooltip, szTip, sizeof(szTip)/sizeof(szTip[0]));
1284                 if (FAILED(hr))
1285                     szTip[0] = 0;
1286 
1287                 TRACE("callback(%s,%s,%s,%p)\n", debugstr_w(szPath), debugstr_w(szName), debugstr_w(szTip), lpData);
1288                 if(!callback(NULL, szPath, szName, szTip, NULL, lpData)) {
1289                     TRACE("callback ended enum\n");
1290                     break;
1291                 }
1292             }
1293         } while(FindNextFileW(hFind, &wfd));
1294         FindClose(hFind);
1295     }
1296     return S_OK;
1297 }
1298 
1299 
1300 /**********************************************************************
1301  *      EnumThemeColors                                    (UXTHEME.9)
1302  *
1303  * Enumerate theme colors available with a particular size
1304  *
1305  * PARAMS
1306  *     pszThemeFileName    Path to a msstyles theme file
1307  *     pszSizeName         Theme size to enumerate available colors
1308  *                         If NULL the default theme size is used
1309  *     dwColorNum          Color index to retrieve, increment from 0
1310  *     pszColorNames       Output color names
1311  *
1312  * RETURNS
1313  *     S_OK on success
1314  *     E_PROP_ID_UNSUPPORTED when dwColorName does not refer to a color
1315  *          or when pszSizeName does not refer to a valid size
1316  *
1317  * NOTES
1318  * XP fails with E_POINTER when pszColorNames points to a buffer smaller than
1319  * sizeof(THEMENAMES).
1320  *
1321  * Not very efficient that I'm opening & validating the theme every call, but
1322  * this is undocumented and almost never called..
1323  * (and this is how windows works too)
1324  */
EnumThemeColors(LPWSTR pszThemeFileName,LPWSTR pszSizeName,DWORD dwColorNum,PTHEMENAMES pszColorNames)1325 HRESULT WINAPI EnumThemeColors(LPWSTR pszThemeFileName, LPWSTR pszSizeName,
1326                                DWORD dwColorNum, PTHEMENAMES pszColorNames)
1327 {
1328     PTHEME_FILE pt;
1329     HRESULT hr;
1330     LPWSTR tmp;
1331     UINT resourceId = dwColorNum + 1000;
1332     TRACE("(%s,%s,%d)\n", debugstr_w(pszThemeFileName),
1333           debugstr_w(pszSizeName), dwColorNum);
1334 
1335     if (!g_bThemeHooksActive)
1336         return E_FAIL;
1337 
1338     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, pszSizeName, &pt);
1339     if(FAILED(hr)) return hr;
1340 
1341     tmp = pt->pszAvailColors;
1342     while(dwColorNum && *tmp) {
1343         dwColorNum--;
1344         tmp += lstrlenW(tmp)+1;
1345     }
1346     if(!dwColorNum && *tmp) {
1347         TRACE("%s\n", debugstr_w(tmp));
1348         lstrcpyW(pszColorNames->szName, tmp);
1349         LoadStringW (pt->hTheme, resourceId,
1350             pszColorNames->szDisplayName,
1351             sizeof (pszColorNames->szDisplayName) / sizeof (WCHAR));
1352         LoadStringW (pt->hTheme, resourceId+1000,
1353             pszColorNames->szTooltip,
1354             sizeof (pszColorNames->szTooltip) / sizeof (WCHAR));
1355     }
1356     else
1357         hr = E_PROP_ID_UNSUPPORTED;
1358 
1359     MSSTYLES_CloseThemeFile(pt);
1360     return hr;
1361 }
1362 
1363 /**********************************************************************
1364  *      EnumThemeSizes                                     (UXTHEME.10)
1365  *
1366  * Enumerate theme colors available with a particular size
1367  *
1368  * PARAMS
1369  *     pszThemeFileName    Path to a msstyles theme file
1370  *     pszColorName        Theme color to enumerate available sizes
1371  *                         If NULL the default theme color is used
1372  *     dwSizeNum           Size index to retrieve, increment from 0
1373  *     pszSizeNames        Output size names
1374  *
1375  * RETURNS
1376  *     S_OK on success
1377  *     E_PROP_ID_UNSUPPORTED when dwSizeName does not refer to a size
1378  *          or when pszColorName does not refer to a valid color
1379  *
1380  * NOTES
1381  * XP fails with E_POINTER when pszSizeNames points to a buffer smaller than
1382  * sizeof(THEMENAMES).
1383  *
1384  * Not very efficient that I'm opening & validating the theme every call, but
1385  * this is undocumented and almost never called..
1386  * (and this is how windows works too)
1387  */
EnumThemeSizes(LPWSTR pszThemeFileName,LPWSTR pszColorName,DWORD dwSizeNum,PTHEMENAMES pszSizeNames)1388 HRESULT WINAPI EnumThemeSizes(LPWSTR pszThemeFileName, LPWSTR pszColorName,
1389                               DWORD dwSizeNum, PTHEMENAMES pszSizeNames)
1390 {
1391     PTHEME_FILE pt;
1392     HRESULT hr;
1393     LPWSTR tmp;
1394     UINT resourceId = dwSizeNum + 3000;
1395     TRACE("(%s,%s,%d)\n", debugstr_w(pszThemeFileName),
1396           debugstr_w(pszColorName), dwSizeNum);
1397 
1398     if (!g_bThemeHooksActive)
1399         return E_FAIL;
1400 
1401     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, NULL, &pt);
1402     if(FAILED(hr)) return hr;
1403 
1404     tmp = pt->pszAvailSizes;
1405     while(dwSizeNum && *tmp) {
1406         dwSizeNum--;
1407         tmp += lstrlenW(tmp)+1;
1408     }
1409     if(!dwSizeNum && *tmp) {
1410         TRACE("%s\n", debugstr_w(tmp));
1411         lstrcpyW(pszSizeNames->szName, tmp);
1412         LoadStringW (pt->hTheme, resourceId,
1413             pszSizeNames->szDisplayName,
1414             sizeof (pszSizeNames->szDisplayName) / sizeof (WCHAR));
1415         LoadStringW (pt->hTheme, resourceId+1000,
1416             pszSizeNames->szTooltip,
1417             sizeof (pszSizeNames->szTooltip) / sizeof (WCHAR));
1418     }
1419     else
1420         hr = E_PROP_ID_UNSUPPORTED;
1421 
1422     MSSTYLES_CloseThemeFile(pt);
1423     return hr;
1424 }
1425 
1426 /**********************************************************************
1427  *      ParseThemeIniFile                                  (UXTHEME.11)
1428  *
1429  * Enumerate data in a theme INI file.
1430  *
1431  * PARAMS
1432  *     pszIniFileName      Path to a theme ini file
1433  *     pszUnknown          Cannot be NULL, L"" is valid
1434  *     callback            Called for each found entry
1435  *     lpData              Passed through to callback
1436  *
1437  * RETURNS
1438  *     S_OK on success
1439  *     0x800706488 (Unknown property) when enumeration is canceled from callback
1440  *
1441  * NOTES
1442  * When pszUnknown is NULL the callback is never called, the value does not seem to serve
1443  * any other purpose
1444  */
ParseThemeIniFile(LPCWSTR pszIniFileName,LPWSTR pszUnknown,PARSETHEMEINIFILEPROC callback,LPVOID lpData)1445 HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown,
1446                                  PARSETHEMEINIFILEPROC callback, LPVOID lpData)
1447 {
1448     FIXME("%s %s: stub\n", debugstr_w(pszIniFileName), debugstr_w(pszUnknown));
1449     return E_NOTIMPL;
1450 }
1451 
1452 /**********************************************************************
1453  *      CheckThemeSignature                                (UXTHEME.29)
1454  *
1455  * Validates the signature of a theme file
1456  *
1457  * PARAMS
1458  *     pszIniFileName      Path to a theme file
1459  *
1460  * RETURNS
1461  *     Success: S_OK
1462  *     Failure: HRESULT error-code
1463  */
CheckThemeSignature(LPCWSTR pszThemeFileName)1464 HRESULT WINAPI CheckThemeSignature(LPCWSTR pszThemeFileName)
1465 {
1466     PTHEME_FILE pt;
1467     HRESULT hr;
1468     TRACE("(%s)\n", debugstr_w(pszThemeFileName));
1469 
1470     if (!g_bThemeHooksActive)
1471         return E_FAIL;
1472 
1473     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, NULL, &pt);
1474     if(FAILED(hr))
1475         return hr;
1476     MSSTYLES_CloseThemeFile(pt);
1477     return S_OK;
1478 }
1479