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