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