Do filename postprocessing in GetDisplayNameOf (Hide filename
[wine] / dlls / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "shlwapi.h"
31 #include "uxtheme.h"
32 #include "tmschema.h"
33
34 #include "uxthemedll.h"
35 #include "msstyles.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
40
41 /***********************************************************************
42  * Defines and global variables
43  */
44
45 static const WCHAR szThemeManager[] = {
46     'S','o','f','t','w','a','r','e','\\',
47     'M','i','c','r','o','s','o','f','t','\\',
48     'W','i','n','d','o','w','s','\\',
49     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
50     'T','h','e','m','e','M','a','n','a','g','e','r','\0'
51 };
52 static const WCHAR szThemeActive[] = {'T','h','e','m','e','A','c','t','i','v','e','\0'};
53 static const WCHAR szSizeName[] = {'S','i','z','e','N','a','m','e','\0'};
54 static const WCHAR szColorName[] = {'C','o','l','o','r','N','a','m','e','\0'};
55 static const WCHAR szDllName[] = {'D','l','l','N','a','m','e','\0'};
56
57 static const WCHAR szIniDocumentation[] = {'d','o','c','u','m','e','n','t','a','t','i','o','n','\0'};
58
59 HINSTANCE hDllInst;
60
61 DWORD dwThemeAppProperties = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS;
62 ATOM atWindowTheme;
63 ATOM atSubAppName;
64 ATOM atSubIdList;
65
66 BOOL bThemeActive = FALSE;
67 WCHAR szCurrentTheme[MAX_PATH];
68 WCHAR szCurrentColor[64];
69 WCHAR szCurrentSize[64];
70
71 /***********************************************************************/
72
73 static BOOL CALLBACK UXTHEME_broadcast_msg_enumchild (HWND hWnd, LPARAM msg)
74 {
75     PostMessageW(hWnd, msg, 0, 0);
76     return TRUE;
77 }
78
79 /* Broadcast a message to *all* windows, including children */
80 static BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg)
81 {
82     if (hWnd == NULL)
83     {
84         EnumWindows (UXTHEME_broadcast_msg, msg);
85     }
86     else
87     {
88         PostMessageW(hWnd, msg, 0, 0);
89         EnumChildWindows (hWnd, UXTHEME_broadcast_msg_enumchild, msg);
90     }
91     return TRUE;
92 }
93
94 /***********************************************************************
95  *      UXTHEME_LoadTheme
96  *
97  * Set the current active theme from the registry
98  */
99 static void UXTHEME_LoadTheme(void)
100 {
101     HKEY hKey;
102     DWORD buffsize;
103     HRESULT hr;
104     WCHAR tmp[10];
105     PTHEME_FILE pt;
106
107     /* Get current theme configuration */
108     if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
109         TRACE("Loading theme config\n");
110         buffsize = sizeof(tmp)/sizeof(tmp[0]);
111         if(!RegQueryValueExW(hKey, szThemeActive, NULL, NULL, (LPBYTE)tmp, &buffsize)) {
112             bThemeActive = (tmp[0] != '0');
113         }
114         else {
115             bThemeActive = FALSE;
116             TRACE("Failed to get ThemeActive: %ld\n", GetLastError());
117         }
118         buffsize = sizeof(szCurrentColor)/sizeof(szCurrentColor[0]);
119         if(RegQueryValueExW(hKey, szColorName, NULL, NULL, (LPBYTE)szCurrentColor, &buffsize))
120             szCurrentColor[0] = '\0';
121         buffsize = sizeof(szCurrentSize)/sizeof(szCurrentSize[0]);
122         if(RegQueryValueExW(hKey, szSizeName, NULL, NULL, (LPBYTE)szCurrentSize, &buffsize))
123             szCurrentSize[0] = '\0';
124         if(SHRegGetPathW(hKey, NULL, szDllName, szCurrentTheme, 0))
125             szCurrentTheme[0] = '\0';
126         RegCloseKey(hKey);
127     }
128     else
129         TRACE("Failed to open theme registry key\n");
130
131     if(bThemeActive) {
132         /* Make sure the theme requested is actually valid */
133         hr = MSSTYLES_OpenThemeFile(szCurrentTheme,
134                                     szCurrentColor[0]?szCurrentColor:NULL,
135                                     szCurrentSize[0]?szCurrentSize:NULL,
136                                     &pt);
137         if(FAILED(hr)) {
138             bThemeActive = FALSE;
139             szCurrentTheme[0] = '\0';
140             szCurrentColor[0] = '\0';
141             szCurrentSize[0] = '\0';
142         }
143         else {
144             /* Make sure the global color & size match the theme */
145             lstrcpynW(szCurrentColor, pt->pszSelectedColor, sizeof(szCurrentColor)/sizeof(szCurrentColor[0]));
146             lstrcpynW(szCurrentSize, pt->pszSelectedSize, sizeof(szCurrentSize)/sizeof(szCurrentSize[0]));
147
148             MSSTYLES_SetActiveTheme(pt);
149             TRACE("Theme active: %s %s %s\n", debugstr_w(szCurrentTheme),
150                 debugstr_w(szCurrentColor), debugstr_w(szCurrentSize));
151             MSSTYLES_CloseThemeFile(pt);
152         }
153     }
154     if(!bThemeActive) {
155         MSSTYLES_SetActiveTheme(NULL);
156         TRACE("Themeing not active\n");
157     }
158 }
159
160 /***********************************************************************
161  *      UXTHEME_SetActiveTheme
162  *
163  * Change the current active theme
164  */
165 HRESULT UXTHEME_SetActiveTheme(PTHEME_FILE tf)
166 {
167     HKEY hKey;
168     WCHAR tmp[2];
169     HRESULT hr;
170
171     hr = MSSTYLES_SetActiveTheme(tf);
172     if(FAILED(hr))
173         return hr;
174     if(tf) {
175         bThemeActive = TRUE;
176         lstrcpynW(szCurrentTheme, tf->szThemeFile, sizeof(szCurrentTheme)/sizeof(szCurrentTheme[0]));
177         lstrcpynW(szCurrentColor, tf->pszSelectedColor, sizeof(szCurrentColor)/sizeof(szCurrentColor[0]));
178         lstrcpynW(szCurrentSize, tf->pszSelectedSize, sizeof(szCurrentSize)/sizeof(szCurrentSize[0]));
179     }
180     else {
181         bThemeActive = FALSE;
182         szCurrentTheme[0] = '\0';
183         szCurrentColor[0] = '\0';
184         szCurrentSize[0] = '\0';
185     }
186
187     TRACE("Writing theme config to registry\n");
188     if(!RegCreateKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
189         tmp[0] = bThemeActive?'1':'0';
190         tmp[1] = '\0';
191         RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (const BYTE*)tmp, sizeof(WCHAR)*2);
192         if(bThemeActive) {
193             RegSetValueExW(hKey, szColorName, 0, REG_SZ, (const BYTE*)szCurrentColor, 
194                 (lstrlenW(szCurrentColor)+1)*sizeof(WCHAR));
195             RegSetValueExW(hKey, szSizeName, 0, REG_SZ, (const BYTE*)szCurrentSize, 
196                 (lstrlenW(szCurrentSize)+1)*sizeof(WCHAR));
197             RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*)szCurrentTheme, 
198                 (lstrlenW(szCurrentTheme)+1)*sizeof(WCHAR));
199         }
200         else {
201             RegDeleteValueW(hKey, szColorName);
202             RegDeleteValueW(hKey, szSizeName);
203             RegDeleteValueW(hKey, szDllName);
204
205         }
206         RegCloseKey(hKey);
207     }
208     else
209         TRACE("Failed to open theme registry key\n");
210     return hr;
211 }
212
213 /***********************************************************************
214  *      UXTHEME_InitSystem
215  */
216 void UXTHEME_InitSystem(HINSTANCE hInst)
217 {
218     static const WCHAR szWindowTheme[] = {
219         'u','x','_','t','h','e','m','e','\0'
220     };
221     static const WCHAR szSubAppName[] = {
222         'u','x','_','s','u','b','a','p','p','\0'
223     };
224     static const WCHAR szSubIdList[] = {
225         'u','x','_','s','u','b','i','d','l','s','t','\0'
226     };
227
228     hDllInst = hInst;
229
230     atWindowTheme = GlobalAddAtomW(szWindowTheme);
231     atSubAppName  = GlobalAddAtomW(szSubAppName);
232     atSubIdList   = GlobalAddAtomW(szSubIdList);
233
234     UXTHEME_LoadTheme();
235 }
236
237 /***********************************************************************
238  *      IsAppThemed                                         (UXTHEME.@)
239  */
240 BOOL WINAPI IsAppThemed(void)
241 {
242     return IsThemeActive();
243 }
244
245 /***********************************************************************
246  *      IsThemeActive                                       (UXTHEME.@)
247  */
248 BOOL WINAPI IsThemeActive(void)
249 {
250     TRACE("\n");
251     return bThemeActive;
252 }
253
254 /***********************************************************************
255  *      EnableTheming                                       (UXTHEME.@)
256  *
257  * NOTES
258  * This is a global and persistent change
259  */
260 HRESULT WINAPI EnableTheming(BOOL fEnable)
261 {
262     HKEY hKey;
263     WCHAR szEnabled[] = {'0','\0'};
264
265     TRACE("(%d)\n", fEnable);
266
267     if(fEnable != bThemeActive) {
268         bThemeActive = fEnable;
269         if(bThemeActive) szEnabled[0] = '1';
270         if(!RegOpenKeyW(HKEY_CURRENT_USER, szThemeManager, &hKey)) {
271             RegSetValueExW(hKey, szThemeActive, 0, REG_SZ, (LPBYTE)szEnabled, sizeof(WCHAR));
272             RegCloseKey(hKey);
273         }
274         UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
275     }
276     return S_OK;
277 }
278
279 /***********************************************************************
280  *      UXTHEME_SetWindowProperty
281  *
282  * I'm using atoms as there may be large numbers of duplicated strings
283  * and they do the work of keeping memory down as a cause of that quite nicely
284  */
285 HRESULT UXTHEME_SetWindowProperty(HWND hwnd, ATOM aProp, LPCWSTR pszValue)
286 {
287     ATOM oldValue = (ATOM)(size_t)RemovePropW(hwnd, MAKEINTATOMW(aProp));
288     if(oldValue)
289         DeleteAtom(oldValue);
290     if(pszValue) {
291         ATOM atValue = AddAtomW(pszValue);
292         if(!atValue
293            || !SetPropW(hwnd, MAKEINTATOMW(aProp), (LPWSTR)MAKEINTATOMW(atValue))) {
294             HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
295             if(atValue) DeleteAtom(atValue);
296             return hr;
297         }
298     }
299     return S_OK;
300 }
301
302 LPWSTR UXTHEME_GetWindowProperty(HWND hwnd, ATOM aProp, LPWSTR pszBuffer, int dwLen)
303 {
304     ATOM atValue = (ATOM)(size_t)GetPropW(hwnd, MAKEINTATOMW(aProp));
305     if(atValue) {
306         if(GetAtomNameW(atValue, pszBuffer, dwLen))
307             return pszBuffer;
308         TRACE("property defined, but unable to get value\n");
309     }
310     return NULL;
311 }
312
313 /***********************************************************************
314  *      OpenThemeData                                       (UXTHEME.@)
315  */
316 HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR pszClassList)
317 {
318     WCHAR szAppBuff[256];
319     WCHAR szClassBuff[256];
320     LPCWSTR pszAppName;
321     LPCWSTR pszUseClassList;
322     HTHEME hTheme;
323     TRACE("(%p,%s)\n", hwnd, debugstr_w(pszClassList));
324     if(!bThemeActive)
325         return NULL;
326
327     pszAppName = UXTHEME_GetWindowProperty(hwnd, atSubAppName, szAppBuff, sizeof(szAppBuff)/sizeof(szAppBuff[0]));
328     /* If SetWindowTheme was used on the window, that overrides the class list passed to this function */
329     pszUseClassList = UXTHEME_GetWindowProperty(hwnd, atSubIdList, szClassBuff, sizeof(szClassBuff)/sizeof(szClassBuff[0]));
330     if(!pszUseClassList)
331         pszUseClassList = pszClassList;
332
333     if (!pszClassList) return NULL;
334     
335     hTheme = MSSTYLES_OpenThemeClass(pszAppName, pszUseClassList);
336     if(IsWindow(hwnd))
337         SetPropW(hwnd, MAKEINTATOMW(atWindowTheme), hTheme);
338     return hTheme;
339 }
340
341 /***********************************************************************
342  *      GetWindowTheme                                      (UXTHEME.@)
343  *
344  * Retrieve the last theme opened for a window
345  */
346 HTHEME WINAPI GetWindowTheme(HWND hwnd)
347 {
348     TRACE("(%p)\n", hwnd);
349     return GetPropW(hwnd, MAKEINTATOMW(atWindowTheme));
350 }
351
352 /***********************************************************************
353  *      SetWindowTheme                                      (UXTHEME.@)
354  *
355  * Persistent through the life of the window, even after themes change
356  */
357 HRESULT WINAPI SetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName,
358                               LPCWSTR pszSubIdList)
359 {
360     HRESULT hr;
361     TRACE("(%p,%s,%s)\n", hwnd, debugstr_w(pszSubAppName),
362           debugstr_w(pszSubIdList));
363     hr = UXTHEME_SetWindowProperty(hwnd, atSubAppName, pszSubAppName);
364     if(SUCCEEDED(hr))
365         hr = UXTHEME_SetWindowProperty(hwnd, atSubIdList, pszSubIdList);
366     if(SUCCEEDED(hr))
367         UXTHEME_broadcast_msg (hwnd, WM_THEMECHANGED);
368     return hr;
369 }
370
371 /***********************************************************************
372  *      GetCurrentThemeName                                 (UXTHEME.@)
373  */
374 HRESULT WINAPI GetCurrentThemeName(LPWSTR pszThemeFileName, int dwMaxNameChars,
375                                    LPWSTR pszColorBuff, int cchMaxColorChars,
376                                    LPWSTR pszSizeBuff, int cchMaxSizeChars)
377 {
378     if(!bThemeActive)
379         return E_PROP_ID_UNSUPPORTED;
380     if(pszThemeFileName) lstrcpynW(pszThemeFileName, szCurrentTheme, dwMaxNameChars);
381     if(pszColorBuff) lstrcpynW(pszColorBuff, szCurrentColor, cchMaxColorChars);
382     if(pszSizeBuff) lstrcpynW(pszSizeBuff, szCurrentSize, cchMaxSizeChars);
383     return S_OK;
384 }
385
386 /***********************************************************************
387  *      GetThemeAppProperties                               (UXTHEME.@)
388  */
389 DWORD WINAPI GetThemeAppProperties(void)
390 {
391     return dwThemeAppProperties;
392 }
393
394 /***********************************************************************
395  *      SetThemeAppProperties                               (UXTHEME.@)
396  */
397 void WINAPI SetThemeAppProperties(DWORD dwFlags)
398 {
399     TRACE("(0x%08lx)\n", dwFlags);
400     dwThemeAppProperties = dwFlags;
401 }
402
403 /***********************************************************************
404  *      CloseThemeData                                      (UXTHEME.@)
405  */
406 HRESULT WINAPI CloseThemeData(HTHEME hTheme)
407 {
408     TRACE("(%p)\n", hTheme);
409     if(!hTheme)
410         return E_HANDLE;
411     return MSSTYLES_CloseThemeClass(hTheme);
412 }
413
414 /***********************************************************************
415  *      HitTestThemeBackground                              (UXTHEME.@)
416  */
417 HRESULT WINAPI HitTestThemeBackground(HTHEME hTheme, HDC hdc, int iPartId,
418                                      int iStateId, DWORD dwOptions,
419                                      const RECT *pRect, HRGN hrgn,
420                                      POINT ptTest, WORD *pwHitTestCode)
421 {
422     FIXME("%d %d 0x%08lx: stub\n", iPartId, iStateId, dwOptions);
423     if(!hTheme)
424         return E_HANDLE;
425     return ERROR_CALL_NOT_IMPLEMENTED;
426 }
427
428 /***********************************************************************
429  *      IsThemePartDefined                                  (UXTHEME.@)
430  */
431 BOOL WINAPI IsThemePartDefined(HTHEME hTheme, int iPartId, int iStateId)
432 {
433     TRACE("(%p,%d,%d)\n", hTheme, iPartId, iStateId);
434     if(!hTheme) {
435         SetLastError(E_HANDLE);
436         return FALSE;
437     }
438     if(MSSTYLES_FindPartState(hTheme, iPartId, iStateId, NULL))
439         return TRUE;
440     return FALSE;
441 }
442
443 /***********************************************************************
444  *      GetThemeDocumentationProperty                       (UXTHEME.@)
445  *
446  * Try and retrieve the documentation property from string resources
447  * if that fails, get it from the [documentation] section of themes.ini
448  */
449 HRESULT WINAPI GetThemeDocumentationProperty(LPCWSTR pszThemeName,
450                                              LPCWSTR pszPropertyName,
451                                              LPWSTR pszValueBuff,
452                                              int cchMaxValChars)
453 {
454     const WORD wDocToRes[] = {
455         TMT_DISPLAYNAME,5000,
456         TMT_TOOLTIP,5001,
457         TMT_COMPANY,5002,
458         TMT_AUTHOR,5003,
459         TMT_COPYRIGHT,5004,
460         TMT_URL,5005,
461         TMT_VERSION,5006,
462         TMT_DESCRIPTION,5007
463     };
464
465     PTHEME_FILE pt;
466     HRESULT hr;
467     unsigned int i;
468     int iDocId;
469     TRACE("(%s,%s,%p,%d)\n", debugstr_w(pszThemeName), debugstr_w(pszPropertyName),
470           pszValueBuff, cchMaxValChars);
471
472     hr = MSSTYLES_OpenThemeFile(pszThemeName, NULL, NULL, &pt);
473     if(FAILED(hr)) return hr;
474
475     /* Try to load from string resources */
476     hr = E_PROP_ID_UNSUPPORTED;
477     if(MSSTYLES_LookupProperty(pszPropertyName, NULL, &iDocId)) {
478         for(i=0; i<sizeof(wDocToRes)/sizeof(wDocToRes[0]); i+=2) {
479             if(wDocToRes[i] == iDocId) {
480                 if(LoadStringW(pt->hTheme, wDocToRes[i+1], pszValueBuff, cchMaxValChars)) {
481                     hr = S_OK;
482                     break;
483                 }
484             }
485         }
486     }
487     /* If loading from string resource failed, try getting it from the theme.ini */
488     if(FAILED(hr)) {
489         PUXINI_FILE uf = MSSTYLES_GetThemeIni(pt);
490         if(UXINI_FindSection(uf, szIniDocumentation)) {
491             LPCWSTR lpValue;
492             DWORD dwLen;
493             if(UXINI_FindValue(uf, pszPropertyName, &lpValue, &dwLen)) {
494                 lstrcpynW(pszValueBuff, lpValue, min(dwLen+1,cchMaxValChars));
495                 hr = S_OK;
496             }
497         }
498         UXINI_CloseINI(uf);
499     }
500
501     MSSTYLES_CloseThemeFile(pt);
502     return hr;
503 }
504
505 /**********************************************************************
506  *      Undocumented functions
507  */
508
509 /**********************************************************************
510  *      QueryThemeServices                                 (UXTHEME.1)
511  *
512  * RETURNS
513  *     some kind of status flag
514  */
515 DWORD WINAPI QueryThemeServices()
516 {
517     FIXME("stub\n");
518     return 3; /* This is what is returned under XP in most cases */
519 }
520
521
522 /**********************************************************************
523  *      OpenThemeFile                                      (UXTHEME.2)
524  *
525  * Opens a theme file, which can be used to change the current theme, etc
526  *
527  * PARAMS
528  *     pszThemeFileName    Path to a msstyles theme file
529  *     pszColorName        Color defined in the theme, eg. NormalColor
530  *     pszSizeName         Size defined in the theme, eg. NormalSize
531  *     hThemeFile          Handle to theme file
532  */
533 HRESULT WINAPI OpenThemeFile(LPCWSTR pszThemeFileName, LPCWSTR pszColorName,
534                              LPCWSTR pszSizeName, HTHEMEFILE *hThemeFile,
535                              DWORD unknown)
536 {
537     TRACE("(%s,%s,%s,%p,%ld)\n", debugstr_w(pszThemeFileName),
538           debugstr_w(pszColorName), debugstr_w(pszSizeName),
539           hThemeFile, unknown);
540     return MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, (PTHEME_FILE*)hThemeFile);
541 }
542
543 /**********************************************************************
544  *      CloseThemeFile                                     (UXTHEME.3)
545  *
546  * Releases theme file handle returned by OpenThemeFile
547  *
548  * PARAMS
549  *     hThemeFile           Handle to theme file
550  */
551 HRESULT WINAPI CloseThemeFile(HTHEMEFILE hThemeFile)
552 {
553     TRACE("(%p)\n", hThemeFile);
554     MSSTYLES_CloseThemeFile(hThemeFile);
555     return S_OK;
556 }
557
558 /**********************************************************************
559  *      ApplyTheme                                         (UXTHEME.4)
560  *
561  * Set a theme file to be the currently active theme
562  *
563  * PARAMS
564  *     hThemeFile           Handle to theme file
565  *     unknown              See notes
566  *     hWnd                 Window requesting the theme change
567  *
568  * NOTES
569  * I'm not sure what the second parameter is (the datatype is likely wrong), other then this:
570  * Under XP if I pass
571  * char b[] = "";
572  *   the theme is applied with the screen redrawing really badly (flickers)
573  * char b[] = "\0"; where \0 can be one or more of any character, makes no difference
574  *   the theme is applied smoothly (screen does not flicker)
575  * char *b = "\0" or NULL; where \0 can be zero or more of any character, makes no difference
576  *   the function fails returning invalid parameter...very strange
577  */
578 HRESULT WINAPI ApplyTheme(HTHEMEFILE hThemeFile, char *unknown, HWND hWnd)
579 {
580     HRESULT hr;
581     TRACE("(%p,%s,%p)\n", hThemeFile, unknown, hWnd);
582     hr = UXTHEME_SetActiveTheme(hThemeFile);
583     UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
584     return hr;
585 }
586
587 /**********************************************************************
588  *      GetThemeDefaults                                   (UXTHEME.7)
589  *
590  * Get the default color & size for a theme
591  *
592  * PARAMS
593  *     pszThemeFileName    Path to a msstyles theme file
594  *     pszColorName        Buffer to receive the default color name
595  *     dwColorNameLen      Length, in characters, of color name buffer
596  *     pszSizeName         Buffer to receive the default size name
597  *     dwSizeNameLen       Length, in characters, of size name buffer
598  */
599 HRESULT WINAPI GetThemeDefaults(LPCWSTR pszThemeFileName, LPWSTR pszColorName,
600                                 DWORD dwColorNameLen, LPWSTR pszSizeName,
601                                 DWORD dwSizeNameLen)
602 {
603     PTHEME_FILE pt;
604     HRESULT hr;
605     TRACE("(%s,%p,%ld,%p,%ld)\n", debugstr_w(pszThemeFileName),
606           pszColorName, dwColorNameLen,
607           pszSizeName, dwSizeNameLen);
608
609     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, NULL, &pt);
610     if(FAILED(hr)) return hr;
611
612     lstrcpynW(pszColorName, pt->pszSelectedColor, dwColorNameLen);
613     lstrcpynW(pszSizeName, pt->pszSelectedSize, dwSizeNameLen);
614
615     MSSTYLES_CloseThemeFile(pt);
616     return S_OK;
617 }
618
619 /**********************************************************************
620  *      EnumThemes                                         (UXTHEME.8)
621  *
622  * Enumerate available themes, calls specified EnumThemeProc for each
623  * theme found. Passes lpData through to callback function.
624  *
625  * PARAMS
626  *     pszThemePath        Path containing themes
627  *     callback            Called for each theme found in path
628  *     lpData              Passed through to callback
629  */
630 HRESULT WINAPI EnumThemes(LPCWSTR pszThemePath, EnumThemeProc callback,
631                           LPVOID lpData)
632 {
633     WCHAR szDir[MAX_PATH];
634     WCHAR szPath[MAX_PATH];
635     static const WCHAR szStar[] = {'*','.','*','\0'};
636     static const WCHAR szFormat[] = {'%','s','%','s','\\','%','s','.','m','s','s','t','y','l','e','s','\0'};
637     static const WCHAR szDisplayName[] = {'d','i','s','p','l','a','y','n','a','m','e','\0'};
638     static const WCHAR szTooltip[] = {'t','o','o','l','t','i','p','\0'};
639     WCHAR szName[60];
640     WCHAR szTip[60];
641     HANDLE hFind;
642     WIN32_FIND_DATAW wfd;
643     HRESULT hr;
644
645     TRACE("(%s,%p,%p)\n", debugstr_w(pszThemePath), callback, lpData);
646
647     if(!pszThemePath || !callback)
648         return E_POINTER;
649
650     lstrcpyW(szDir, pszThemePath);
651     PathAddBackslashW(szDir);
652
653     lstrcpyW(szPath, szDir);
654     lstrcatW(szPath, szStar);
655     TRACE("searching %s\n", debugstr_w(szPath));
656
657     hFind = FindFirstFileW(szPath, &wfd);
658     if(hFind != INVALID_HANDLE_VALUE) {
659         do {
660             if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
661                && !(wfd.cFileName[0] == '.' && ((wfd.cFileName[1] == '.' && wfd.cFileName[2] == 0) || wfd.cFileName[1] == 0))) {
662                 wsprintfW(szPath, szFormat, szDir, wfd.cFileName, wfd.cFileName);
663
664                 hr = GetThemeDocumentationProperty(szPath, szDisplayName, szName, sizeof(szName)/sizeof(szName[0]));
665                 if(SUCCEEDED(hr))
666                     hr = GetThemeDocumentationProperty(szPath, szTooltip, szTip, sizeof(szTip)/sizeof(szTip[0]));
667                 if(SUCCEEDED(hr)) {
668                     TRACE("callback(%s,%s,%s,%p)\n", debugstr_w(szPath), debugstr_w(szName), debugstr_w(szTip), lpData);
669                     if(!callback(NULL, szPath, szName, szTip, NULL, lpData)) {
670                         TRACE("callback ended enum\n");
671                         break;
672                     }
673                 }
674             }
675         } while(FindNextFileW(hFind, &wfd));
676         FindClose(hFind);
677     }
678     return S_OK;
679 }
680
681
682 /**********************************************************************
683  *      EnumThemeColors                                    (UXTHEME.9)
684  *
685  * Enumerate theme colors available with a particular size
686  *
687  * PARAMS
688  *     pszThemeFileName    Path to a msstyles theme file
689  *     pszSizeName         Theme size to enumerate available colors
690  *                         If NULL the default theme size is used
691  *     dwColorNum          Color index to retrieve, increment from 0
692  *     pszColorName        Output color name
693  *
694  * RETURNS
695  *     S_OK on success
696  *     E_PROP_ID_UNSUPPORTED when dwColorName does not refer to a color
697  *          or when pszSizeName does not refer to a valid size
698  *
699  * NOTES
700  * XP fails with E_POINTER when pszColorName points to a buffer smaller then 605
701  * characters
702  *
703  * Not very efficient that I'm opening & validating the theme every call, but
704  * this is undocumented and almost never called..
705  * (and this is how windows works too)
706  */
707 HRESULT WINAPI EnumThemeColors(LPWSTR pszThemeFileName, LPWSTR pszSizeName,
708                                DWORD dwColorNum, LPWSTR pszColorName)
709 {
710     PTHEME_FILE pt;
711     HRESULT hr;
712     LPWSTR tmp;
713     TRACE("(%s,%s,%ld)\n", debugstr_w(pszThemeFileName),
714           debugstr_w(pszSizeName), dwColorNum);
715
716     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, pszSizeName, &pt);
717     if(FAILED(hr)) return hr;
718
719     tmp = pt->pszAvailColors;
720     while(dwColorNum && *tmp) {
721         dwColorNum--;
722         tmp += lstrlenW(tmp)+1;
723     }
724     if(!dwColorNum && *tmp) {
725         TRACE("%s\n", debugstr_w(tmp));
726         lstrcpyW(pszColorName, tmp);
727     }
728     else
729         hr = E_PROP_ID_UNSUPPORTED;
730
731     MSSTYLES_CloseThemeFile(pt);
732     return hr;
733 }
734
735 /**********************************************************************
736  *      EnumThemeSizes                                     (UXTHEME.10)
737  *
738  * Enumerate theme colors available with a particular size
739  *
740  * PARAMS
741  *     pszThemeFileName    Path to a msstyles theme file
742  *     pszColorName        Theme color to enumerate available sizes
743  *                         If NULL the default theme color is used
744  *     dwSizeNum           Size index to retrieve, increment from 0
745  *     pszSizeName         Output size name
746  *
747  * RETURNS
748  *     S_OK on success
749  *     E_PROP_ID_UNSUPPORTED when dwSizeName does not refer to a size
750  *          or when pszColorName does not refer to a valid color
751  *
752  * NOTES
753  * XP fails with E_POINTER when pszSizeName points to a buffer smaller then 605
754  * characters
755  *
756  * Not very efficient that I'm opening & validating the theme every call, but
757  * this is undocumented and almost never called..
758  * (and this is how windows works too)
759  */
760 HRESULT WINAPI EnumThemeSizes(LPWSTR pszThemeFileName, LPWSTR pszColorName,
761                               DWORD dwSizeNum, LPWSTR pszSizeName)
762 {
763     PTHEME_FILE pt;
764     HRESULT hr;
765     LPWSTR tmp;
766     TRACE("(%s,%s,%ld)\n", debugstr_w(pszThemeFileName),
767           debugstr_w(pszColorName), dwSizeNum);
768
769     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, pszColorName, NULL, &pt);
770     if(FAILED(hr)) return hr;
771
772     tmp = pt->pszAvailSizes;
773     while(dwSizeNum && *tmp) {
774         dwSizeNum--;
775         tmp += lstrlenW(tmp)+1;
776     }
777     if(!dwSizeNum && *tmp) {
778         TRACE("%s\n", debugstr_w(tmp));
779         lstrcpyW(pszSizeName, tmp);
780     }
781     else
782         hr = E_PROP_ID_UNSUPPORTED;
783
784     MSSTYLES_CloseThemeFile(pt);
785     return hr;
786 }
787
788 /**********************************************************************
789  *      ParseThemeIniFile                                  (UXTHEME.11)
790  *
791  * Enumerate data in a theme INI file.
792  *
793  * PARAMS
794  *     pszIniFileName      Path to a theme ini file
795  *     pszUnknown          Cannot be NULL, L"" is valid
796  *     callback            Called for each found entry
797  *     lpData              Passed through to callback
798  *
799  * RETURNS
800  *     S_OK on success
801  *     0x800706488 (Unknown property) when enumeration is canceled from callback
802  *
803  * NOTES
804  * When pszUnknown is NULL the callback is never called, the value does not seem to surve
805  * any other purpose
806  */
807 HRESULT WINAPI ParseThemeIniFile(LPCWSTR pszIniFileName, LPWSTR pszUnknown,
808                                  ParseThemeIniFileProc callback, LPVOID lpData)
809 {
810     FIXME("%s %s: stub\n", debugstr_w(pszIniFileName), debugstr_w(pszUnknown));
811     return ERROR_CALL_NOT_IMPLEMENTED;
812 }
813
814 /**********************************************************************
815  *      CheckThemeSignature                                (UXTHEME.29)
816  *
817  * Validates the signature of a theme file
818  *
819  * PARAMS
820  *     pszIniFileName      Path to a theme file
821  */
822 HRESULT WINAPI CheckThemeSignature(LPCWSTR pszThemeFileName)
823 {
824     PTHEME_FILE pt;
825     HRESULT hr;
826     TRACE("(%s)\n", debugstr_w(pszThemeFileName));
827     hr = MSSTYLES_OpenThemeFile(pszThemeFileName, NULL, NULL, &pt);
828     if(FAILED(hr))
829         return hr;
830     MSSTYLES_CloseThemeFile(pt);
831     return S_OK;
832 }