wined3d: Set 3D device caps in adapter_gl_get_wined3d_caps().
[wine.git] / dlls / uxtheme / msstyles.c
blobbc8eca7b3476db4203002606f96d5b1a2dc51f64
1 /*
2 * Win32 5.1 msstyles theme format
4 * Copyright (C) 2003 Kevin Koltzau
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.
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.
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
21 #include "config.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "vfwmsgs.h"
32 #include "uxtheme.h"
33 #include "tmschema.h"
35 #include "msstyles.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39 #include "wine/heap.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
43 /***********************************************************************
44 * Defines and global variables
47 static BOOL MSSTYLES_GetNextInteger(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, int *value);
48 static BOOL MSSTYLES_GetNextToken(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, LPWSTR lpBuff, DWORD buffSize);
49 static void MSSTYLES_ParseThemeIni(PTHEME_FILE tf, BOOL setMetrics);
50 static HRESULT MSSTYLES_GetFont (LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, LOGFONTW* logfont);
52 extern int alphaBlendMode;
54 #define MSSTYLES_VERSION 0x0003
56 static const WCHAR szThemesIniResource[] = {
57 't','h','e','m','e','s','_','i','n','i','\0'
60 static PTHEME_FILE tfActiveTheme;
62 /***********************************************************************/
64 /**********************************************************************
65 * MSSTYLES_OpenThemeFile
67 * Load and validate a theme
69 * PARAMS
70 * lpThemeFile Path to theme file to load
71 * pszColorName Color name wanted, can be NULL
72 * pszSizeName Size name wanted, can be NULL
74 * NOTES
75 * If pszColorName or pszSizeName are NULL, the default color/size will be used.
76 * If one/both are provided, they are validated against valid color/sizes and if
77 * a match is not found, the function fails.
79 HRESULT MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile, LPCWSTR pszColorName, LPCWSTR pszSizeName, PTHEME_FILE *tf)
81 HMODULE hTheme;
82 HRSRC hrsc;
83 HRESULT hr = S_OK;
84 static const WCHAR szPackThemVersionResource[] = {
85 'P','A','C','K','T','H','E','M','_','V','E','R','S','I','O','N', '\0'
87 static const WCHAR szColorNamesResource[] = {
88 'C','O','L','O','R','N','A','M','E','S','\0'
90 static const WCHAR szSizeNamesResource[] = {
91 'S','I','Z','E','N','A','M','E','S','\0'
94 WORD version;
95 DWORD versize;
96 LPWSTR pszColors;
97 LPWSTR pszSelectedColor = NULL;
98 LPWSTR pszSizes;
99 LPWSTR pszSelectedSize = NULL;
100 LPWSTR tmp;
102 TRACE("Opening %s\n", debugstr_w(lpThemeFile));
104 hTheme = LoadLibraryExW(lpThemeFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
106 /* Validate that this is really a theme */
107 if(!hTheme) {
108 hr = HRESULT_FROM_WIN32(GetLastError());
109 goto invalid_theme;
111 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szPackThemVersionResource))) {
112 TRACE("No version resource found\n");
113 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
114 goto invalid_theme;
116 if((versize = SizeofResource(hTheme, hrsc)) != 2)
118 TRACE("Version resource found, but wrong size: %d\n", versize);
119 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
120 goto invalid_theme;
122 version = *(WORD*)LoadResource(hTheme, hrsc);
123 if(version != MSSTYLES_VERSION)
125 TRACE("Version of theme file is unsupported: 0x%04x\n", version);
126 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
127 goto invalid_theme;
130 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szColorNamesResource))) {
131 TRACE("Color names resource not found\n");
132 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
133 goto invalid_theme;
135 pszColors = LoadResource(hTheme, hrsc);
137 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szSizeNamesResource))) {
138 TRACE("Size names resource not found\n");
139 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
140 goto invalid_theme;
142 pszSizes = LoadResource(hTheme, hrsc);
144 /* Validate requested color against what's available from the theme */
145 if(pszColorName) {
146 tmp = pszColors;
147 while(*tmp) {
148 if(!lstrcmpiW(pszColorName, tmp)) {
149 pszSelectedColor = tmp;
150 break;
152 tmp += lstrlenW(tmp)+1;
155 else
156 pszSelectedColor = pszColors; /* Use the default color */
158 /* Validate requested size against what's available from the theme */
159 if(pszSizeName) {
160 tmp = pszSizes;
161 while(*tmp) {
162 if(!lstrcmpiW(pszSizeName, tmp)) {
163 pszSelectedSize = tmp;
164 break;
166 tmp += lstrlenW(tmp)+1;
169 else
170 pszSelectedSize = pszSizes; /* Use the default size */
172 if(!pszSelectedColor || !pszSelectedSize) {
173 TRACE("Requested color/size (%s/%s) not found in theme\n",
174 debugstr_w(pszColorName), debugstr_w(pszSizeName));
175 hr = E_PROP_ID_UNSUPPORTED;
176 goto invalid_theme;
179 *tf = heap_alloc_zero(sizeof(THEME_FILE));
180 (*tf)->hTheme = hTheme;
182 GetFullPathNameW(lpThemeFile, MAX_PATH, (*tf)->szThemeFile, NULL);
184 (*tf)->pszAvailColors = pszColors;
185 (*tf)->pszAvailSizes = pszSizes;
186 (*tf)->pszSelectedColor = pszSelectedColor;
187 (*tf)->pszSelectedSize = pszSelectedSize;
188 (*tf)->dwRefCount = 1;
189 return S_OK;
191 invalid_theme:
192 *tf = NULL;
193 if(hTheme) FreeLibrary(hTheme);
194 return hr;
197 /***********************************************************************
198 * MSSTYLES_CloseThemeFile
200 * Close theme file and free resources
202 void MSSTYLES_CloseThemeFile(PTHEME_FILE tf)
204 if(tf) {
205 tf->dwRefCount--;
206 if(!tf->dwRefCount) {
207 if(tf->hTheme) FreeLibrary(tf->hTheme);
208 if(tf->classes) {
209 while(tf->classes) {
210 PTHEME_CLASS pcls = tf->classes;
211 tf->classes = pcls->next;
212 while(pcls->partstate) {
213 PTHEME_PARTSTATE ps = pcls->partstate;
215 while(ps->properties) {
216 PTHEME_PROPERTY prop = ps->properties;
217 ps->properties = prop->next;
218 heap_free(prop);
221 pcls->partstate = ps->next;
222 heap_free(ps);
224 heap_free(pcls);
227 while (tf->images)
229 PTHEME_IMAGE img = tf->images;
230 tf->images = img->next;
231 DeleteObject (img->image);
232 heap_free(img);
234 heap_free(tf);
239 /***********************************************************************
240 * MSSTYLES_SetActiveTheme
242 * Set the current active theme
244 HRESULT MSSTYLES_SetActiveTheme(PTHEME_FILE tf, BOOL setMetrics)
246 if(tfActiveTheme)
247 MSSTYLES_CloseThemeFile(tfActiveTheme);
248 tfActiveTheme = tf;
249 if (tfActiveTheme)
251 tfActiveTheme->dwRefCount++;
252 if(!tfActiveTheme->classes)
253 MSSTYLES_ParseThemeIni(tfActiveTheme, setMetrics);
255 return S_OK;
258 /***********************************************************************
259 * MSSTYLES_GetThemeIni
261 * Retrieves themes.ini from a theme
263 PUXINI_FILE MSSTYLES_GetThemeIni(PTHEME_FILE tf)
265 return UXINI_LoadINI(tf->hTheme, szThemesIniResource);
268 /***********************************************************************
269 * MSSTYLES_GetActiveThemeIni
271 * Retrieve the ini file for the selected color/style
273 static PUXINI_FILE MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf)
275 static const WCHAR szFileResNamesResource[] = {
276 'F','I','L','E','R','E','S','N','A','M','E','S','\0'
278 DWORD dwColorCount = 0;
279 DWORD dwSizeCount = 0;
280 DWORD dwColorNum = 0;
281 DWORD dwSizeNum = 0;
282 DWORD i;
283 DWORD dwResourceIndex;
284 LPWSTR tmp;
285 HRSRC hrsc;
287 /* Count the number of available colors & styles, and determine the index number
288 of the color/style we are interested in
290 tmp = tf->pszAvailColors;
291 while(*tmp) {
292 if(!lstrcmpiW(tf->pszSelectedColor, tmp))
293 dwColorNum = dwColorCount;
294 tmp += lstrlenW(tmp)+1;
295 dwColorCount++;
297 tmp = tf->pszAvailSizes;
298 while(*tmp) {
299 if(!lstrcmpiW(tf->pszSelectedSize, tmp))
300 dwSizeNum = dwSizeCount;
301 tmp += lstrlenW(tmp)+1;
302 dwSizeCount++;
305 if(!(hrsc = FindResourceW(tf->hTheme, MAKEINTRESOURCEW(1), szFileResNamesResource))) {
306 TRACE("FILERESNAMES map not found\n");
307 return NULL;
309 tmp = LoadResource(tf->hTheme, hrsc);
310 dwResourceIndex = (dwSizeCount * dwColorNum) + dwSizeNum;
311 for(i=0; i < dwResourceIndex; i++) {
312 tmp += lstrlenW(tmp)+1;
314 return UXINI_LoadINI(tf->hTheme, tmp);
318 /***********************************************************************
319 * MSSTYLES_ParseIniSectionName
321 * Parse an ini section name into its component parts
322 * Valid formats are:
323 * [classname]
324 * [classname(state)]
325 * [classname.part]
326 * [classname.part(state)]
327 * [application::classname]
328 * [application::classname(state)]
329 * [application::classname.part]
330 * [application::classname.part(state)]
332 * PARAMS
333 * lpSection Section name
334 * dwLen Length of section name
335 * szAppName Location to store application name
336 * szClassName Location to store class name
337 * iPartId Location to store part id
338 * iStateId Location to store state id
340 static BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR szAppName, LPWSTR szClassName, int *iPartId, int *iStateId)
342 WCHAR sec[255];
343 WCHAR part[60] = {'\0'};
344 WCHAR state[60] = {'\0'};
345 LPWSTR tmp;
346 LPWSTR comp;
347 lstrcpynW(sec, lpSection, min(dwLen+1, ARRAY_SIZE(sec)));
349 *szAppName = 0;
350 *szClassName = 0;
351 *iPartId = 0;
352 *iStateId = 0;
353 comp = sec;
354 /* Get the application name */
355 tmp = strchrW(comp, ':');
356 if(tmp) {
357 *tmp++ = 0;
358 tmp++;
359 lstrcpynW(szAppName, comp, MAX_THEME_APP_NAME);
360 comp = tmp;
363 tmp = strchrW(comp, '.');
364 if(tmp) {
365 *tmp++ = 0;
366 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
367 comp = tmp;
368 /* now get the part & state */
369 tmp = strchrW(comp, '(');
370 if(tmp) {
371 *tmp++ = 0;
372 lstrcpynW(part, comp, ARRAY_SIZE(part));
373 comp = tmp;
374 /* now get the state */
375 tmp = strchrW(comp, ')');
376 if (!tmp)
377 return FALSE;
378 *tmp = 0;
379 lstrcpynW(state, comp, ARRAY_SIZE(state));
381 else {
382 lstrcpynW(part, comp, ARRAY_SIZE(part));
385 else {
386 tmp = strchrW(comp, '(');
387 if(tmp) {
388 *tmp++ = 0;
389 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
390 comp = tmp;
391 /* now get the state */
392 tmp = strchrW(comp, ')');
393 if (!tmp)
394 return FALSE;
395 *tmp = 0;
396 lstrcpynW(state, comp, ARRAY_SIZE(state));
398 else {
399 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
402 if(!*szClassName) return FALSE;
403 return MSSTYLES_LookupPartState(szClassName, part[0]?part:NULL, state[0]?state:NULL, iPartId, iStateId);
406 /***********************************************************************
407 * MSSTYLES_FindClass
409 * Find a class
411 * PARAMS
412 * tf Theme file
413 * pszAppName App name to find
414 * pszClassName Class name to find
416 * RETURNS
417 * The class found, or NULL
419 static PTHEME_CLASS MSSTYLES_FindClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
421 PTHEME_CLASS cur = tf->classes;
422 while(cur) {
423 if(!pszAppName) {
424 if(!*cur->szAppName && !lstrcmpiW(pszClassName, cur->szClassName))
425 return cur;
427 else {
428 if(!lstrcmpiW(pszAppName, cur->szAppName) && !lstrcmpiW(pszClassName, cur->szClassName))
429 return cur;
431 cur = cur->next;
433 return NULL;
436 /***********************************************************************
437 * MSSTYLES_AddClass
439 * Add a class to a theme file
441 * PARAMS
442 * tf Theme file
443 * pszAppName App name to add
444 * pszClassName Class name to add
446 * RETURNS
447 * The class added, or a class previously added with the same name
449 static PTHEME_CLASS MSSTYLES_AddClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
451 PTHEME_CLASS cur = MSSTYLES_FindClass(tf, pszAppName, pszClassName);
452 if(cur) return cur;
454 cur = heap_alloc(sizeof(*cur));
455 cur->hTheme = tf->hTheme;
456 lstrcpyW(cur->szAppName, pszAppName);
457 lstrcpyW(cur->szClassName, pszClassName);
458 cur->next = tf->classes;
459 cur->partstate = NULL;
460 cur->overrides = NULL;
461 tf->classes = cur;
462 return cur;
465 /***********************************************************************
466 * MSSTYLES_FindPartState
468 * Find a part/state
470 * PARAMS
471 * tc Class to search
472 * iPartId Part ID to find
473 * iStateId State ID to find
474 * tcNext Receives the next class in the override chain
476 * RETURNS
477 * The part/state found, or NULL
479 PTHEME_PARTSTATE MSSTYLES_FindPartState(PTHEME_CLASS tc, int iPartId, int iStateId, PTHEME_CLASS *tcNext)
481 PTHEME_PARTSTATE cur = tc->partstate;
482 while(cur) {
483 if(cur->iPartId == iPartId && cur->iStateId == iStateId) {
484 if(tcNext) *tcNext = tc->overrides;
485 return cur;
487 cur = cur->next;
489 if(tc->overrides) return MSSTYLES_FindPartState(tc->overrides, iPartId, iStateId, tcNext);
490 return NULL;
493 /***********************************************************************
494 * MSSTYLES_AddPartState
496 * Add a part/state to a class
498 * PARAMS
499 * tc Theme class
500 * iPartId Part ID to add
501 * iStateId State ID to add
503 * RETURNS
504 * The part/state added, or a part/state previously added with the same IDs
506 static PTHEME_PARTSTATE MSSTYLES_AddPartState(PTHEME_CLASS tc, int iPartId, int iStateId)
508 PTHEME_PARTSTATE cur = MSSTYLES_FindPartState(tc, iPartId, iStateId, NULL);
509 if(cur) return cur;
511 cur = heap_alloc(sizeof(*cur));
512 cur->iPartId = iPartId;
513 cur->iStateId = iStateId;
514 cur->properties = NULL;
515 cur->next = tc->partstate;
516 tc->partstate = cur;
517 return cur;
520 /***********************************************************************
521 * MSSTYLES_LFindProperty
523 * Find a property within a property list
525 * PARAMS
526 * tp property list to scan
527 * iPropertyPrimitive Type of value expected
528 * iPropertyId ID of the required value
530 * RETURNS
531 * The property found, or NULL
533 static PTHEME_PROPERTY MSSTYLES_LFindProperty(PTHEME_PROPERTY tp, int iPropertyPrimitive, int iPropertyId)
535 PTHEME_PROPERTY cur = tp;
536 while(cur) {
537 if(cur->iPropertyId == iPropertyId) {
538 if(cur->iPrimitiveType == iPropertyPrimitive) {
539 return cur;
541 else {
542 if(!iPropertyPrimitive)
543 return cur;
544 return NULL;
547 cur = cur->next;
549 return NULL;
552 /***********************************************************************
553 * MSSTYLES_PSFindProperty
555 * Find a value within a part/state
557 * PARAMS
558 * ps Part/state to search
559 * iPropertyPrimitive Type of value expected
560 * iPropertyId ID of the required value
562 * RETURNS
563 * The property found, or NULL
565 static inline PTHEME_PROPERTY MSSTYLES_PSFindProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId)
567 return MSSTYLES_LFindProperty(ps->properties, iPropertyPrimitive, iPropertyId);
570 /***********************************************************************
571 * MSSTYLES_FFindMetric
573 * Find a metric property for a theme file
575 * PARAMS
576 * tf Theme file
577 * iPropertyPrimitive Type of value expected
578 * iPropertyId ID of the required value
580 * RETURNS
581 * The property found, or NULL
583 static inline PTHEME_PROPERTY MSSTYLES_FFindMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId)
585 return MSSTYLES_LFindProperty(tf->metrics, iPropertyPrimitive, iPropertyId);
588 /***********************************************************************
589 * MSSTYLES_FindMetric
591 * Find a metric property for the current installed theme
593 * PARAMS
594 * tf Theme file
595 * iPropertyPrimitive Type of value expected
596 * iPropertyId ID of the required value
598 * RETURNS
599 * The property found, or NULL
601 PTHEME_PROPERTY MSSTYLES_FindMetric(int iPropertyPrimitive, int iPropertyId)
603 if(!tfActiveTheme) return NULL;
604 return MSSTYLES_FFindMetric(tfActiveTheme, iPropertyPrimitive, iPropertyId);
607 /***********************************************************************
608 * MSSTYLES_AddProperty
610 * Add a property to a part/state
612 * PARAMS
613 * ps Part/state
614 * iPropertyPrimitive Primitive type of the property
615 * iPropertyId ID of the property
616 * lpValue Raw value (non-NULL terminated)
617 * dwValueLen Length of the value
619 * RETURNS
620 * The property added, or a property previously added with the same IDs
622 static PTHEME_PROPERTY MSSTYLES_AddProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen, BOOL isGlobal)
624 PTHEME_PROPERTY cur = MSSTYLES_PSFindProperty(ps, iPropertyPrimitive, iPropertyId);
625 /* Should duplicate properties overwrite the original, or be ignored? */
626 if(cur) return cur;
628 cur = heap_alloc(sizeof(*cur));
629 cur->iPrimitiveType = iPropertyPrimitive;
630 cur->iPropertyId = iPropertyId;
631 cur->lpValue = lpValue;
632 cur->dwValueLen = dwValueLen;
634 if(ps->iStateId)
635 cur->origin = PO_STATE;
636 else if(ps->iPartId)
637 cur->origin = PO_PART;
638 else if(isGlobal)
639 cur->origin = PO_GLOBAL;
640 else
641 cur->origin = PO_CLASS;
643 cur->next = ps->properties;
644 ps->properties = cur;
645 return cur;
648 /***********************************************************************
649 * MSSTYLES_AddMetric
651 * Add a property to a part/state
653 * PARAMS
654 * tf Theme file
655 * iPropertyPrimitive Primitive type of the property
656 * iPropertyId ID of the property
657 * lpValue Raw value (non-NULL terminated)
658 * dwValueLen Length of the value
660 * RETURNS
661 * The property added, or a property previously added with the same IDs
663 static PTHEME_PROPERTY MSSTYLES_AddMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen)
665 PTHEME_PROPERTY cur = MSSTYLES_FFindMetric(tf, iPropertyPrimitive, iPropertyId);
666 /* Should duplicate properties overwrite the original, or be ignored? */
667 if(cur) return cur;
669 cur = heap_alloc(sizeof(*cur));
670 cur->iPrimitiveType = iPropertyPrimitive;
671 cur->iPropertyId = iPropertyId;
672 cur->lpValue = lpValue;
673 cur->dwValueLen = dwValueLen;
675 cur->origin = PO_GLOBAL;
677 cur->next = tf->metrics;
678 tf->metrics = cur;
679 return cur;
682 /* Color-related state for theme ini parsing */
683 struct PARSECOLORSTATE
685 int colorCount;
686 int colorElements[TMT_LASTCOLOR-TMT_FIRSTCOLOR+1];
687 COLORREF colorRgb[TMT_LASTCOLOR-TMT_FIRSTCOLOR+1];
688 int captionColors;
691 static inline void parse_init_color (struct PARSECOLORSTATE* state)
693 memset (state, 0, sizeof (*state));
696 static BOOL parse_handle_color_property (struct PARSECOLORSTATE* state,
697 int iPropertyId, LPCWSTR lpValue,
698 DWORD dwValueLen)
700 int r,g,b;
701 LPCWSTR lpValueEnd = lpValue + dwValueLen;
702 if(MSSTYLES_GetNextInteger(lpValue, lpValueEnd, &lpValue, &r) &&
703 MSSTYLES_GetNextInteger(lpValue, lpValueEnd, &lpValue, &g) &&
704 MSSTYLES_GetNextInteger(lpValue, lpValueEnd, &lpValue, &b)) {
705 state->colorElements[state->colorCount] = iPropertyId - TMT_FIRSTCOLOR;
706 state->colorRgb[state->colorCount++] = RGB(r,g,b);
707 switch (iPropertyId)
709 case TMT_ACTIVECAPTION:
710 state->captionColors |= 0x1;
711 break;
712 case TMT_INACTIVECAPTION:
713 state->captionColors |= 0x2;
714 break;
715 case TMT_GRADIENTACTIVECAPTION:
716 state->captionColors |= 0x4;
717 break;
718 case TMT_GRADIENTINACTIVECAPTION:
719 state->captionColors |= 0x8;
720 break;
722 return TRUE;
724 else {
725 return FALSE;
729 static void parse_apply_color (struct PARSECOLORSTATE* state)
731 if (state->colorCount > 0)
732 SetSysColors(state->colorCount, state->colorElements, state->colorRgb);
733 if (state->captionColors == 0xf)
734 SystemParametersInfoW (SPI_SETGRADIENTCAPTIONS, 0, (PVOID)TRUE, 0);
737 /* Non-client-metrics-related state for theme ini parsing */
738 struct PARSENONCLIENTSTATE
740 NONCLIENTMETRICSW metrics;
741 BOOL metricsDirty;
742 LOGFONTW iconTitleFont;
745 static inline void parse_init_nonclient (struct PARSENONCLIENTSTATE* state)
747 memset (state, 0, sizeof (*state));
748 state->metrics.cbSize = sizeof (NONCLIENTMETRICSW);
749 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW),
750 &state->metrics, 0);
751 SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof (LOGFONTW),
752 &state->iconTitleFont, 0);
755 static BOOL parse_handle_nonclient_font (struct PARSENONCLIENTSTATE* state,
756 int iPropertyId, LPCWSTR lpValue,
757 DWORD dwValueLen)
759 LOGFONTW font;
761 memset (&font, 0, sizeof (font));
762 if (SUCCEEDED (MSSTYLES_GetFont (lpValue, lpValue + dwValueLen, &lpValue,
763 &font)))
765 switch (iPropertyId)
767 case TMT_CAPTIONFONT:
768 state->metrics.lfCaptionFont = font;
769 state->metricsDirty = TRUE;
770 break;
771 case TMT_SMALLCAPTIONFONT:
772 state->metrics.lfSmCaptionFont = font;
773 state->metricsDirty = TRUE;
774 break;
775 case TMT_MENUFONT:
776 state->metrics.lfMenuFont = font;
777 state->metricsDirty = TRUE;
778 break;
779 case TMT_STATUSFONT:
780 state->metrics.lfStatusFont = font;
781 state->metricsDirty = TRUE;
782 break;
783 case TMT_MSGBOXFONT:
784 state->metrics.lfMessageFont = font;
785 state->metricsDirty = TRUE;
786 break;
787 case TMT_ICONTITLEFONT:
788 state->iconTitleFont = font;
789 state->metricsDirty = TRUE;
790 break;
792 return TRUE;
794 else
795 return FALSE;
798 static BOOL parse_handle_nonclient_size (struct PARSENONCLIENTSTATE* state,
799 int iPropertyId, LPCWSTR lpValue,
800 DWORD dwValueLen)
802 int size;
803 LPCWSTR lpValueEnd = lpValue + dwValueLen;
804 if(MSSTYLES_GetNextInteger(lpValue, lpValueEnd, &lpValue, &size)) {
805 switch (iPropertyId)
807 case TMT_SIZINGBORDERWIDTH:
808 state->metrics.iBorderWidth = size;
809 state->metricsDirty = TRUE;
810 break;
811 case TMT_SCROLLBARWIDTH:
812 state->metrics.iScrollWidth = size;
813 state->metricsDirty = TRUE;
814 break;
815 case TMT_SCROLLBARHEIGHT:
816 state->metrics.iScrollHeight = size;
817 state->metricsDirty = TRUE;
818 break;
819 case TMT_CAPTIONBARWIDTH:
820 state->metrics.iCaptionWidth = size;
821 state->metricsDirty = TRUE;
822 break;
823 case TMT_CAPTIONBARHEIGHT:
824 state->metrics.iCaptionHeight = size;
825 state->metricsDirty = TRUE;
826 break;
827 case TMT_SMCAPTIONBARWIDTH:
828 state->metrics.iSmCaptionWidth = size;
829 state->metricsDirty = TRUE;
830 break;
831 case TMT_SMCAPTIONBARHEIGHT:
832 state->metrics.iSmCaptionHeight = size;
833 state->metricsDirty = TRUE;
834 break;
835 case TMT_MENUBARWIDTH:
836 state->metrics.iMenuWidth = size;
837 state->metricsDirty = TRUE;
838 break;
839 case TMT_MENUBARHEIGHT:
840 state->metrics.iMenuHeight = size;
841 state->metricsDirty = TRUE;
842 break;
844 return TRUE;
846 else
847 return FALSE;
850 static void parse_apply_nonclient (struct PARSENONCLIENTSTATE* state)
852 if (state->metricsDirty)
854 SystemParametersInfoW (SPI_SETNONCLIENTMETRICS, sizeof (state->metrics),
855 &state->metrics, 0);
856 SystemParametersInfoW (SPI_SETICONTITLELOGFONT, sizeof (state->iconTitleFont),
857 &state->iconTitleFont, 0);
861 /***********************************************************************
862 * MSSTYLES_ParseThemeIni
864 * Parse the theme ini for the selected color/style
866 * PARAMS
867 * tf Theme to parse
869 static void MSSTYLES_ParseThemeIni(PTHEME_FILE tf, BOOL setMetrics)
871 static const WCHAR szSysMetrics[] = {'S','y','s','M','e','t','r','i','c','s','\0'};
872 static const WCHAR szGlobals[] = {'g','l','o','b','a','l','s','\0'};
873 PTHEME_CLASS cls;
874 PTHEME_CLASS globals;
875 PTHEME_PARTSTATE ps;
876 PUXINI_FILE ini;
877 WCHAR szAppName[MAX_THEME_APP_NAME];
878 WCHAR szClassName[MAX_THEME_CLASS_NAME];
879 WCHAR szPropertyName[MAX_THEME_VALUE_NAME];
880 int iPartId;
881 int iStateId;
882 int iPropertyPrimitive;
883 int iPropertyId;
884 DWORD dwLen;
885 LPCWSTR lpName;
886 DWORD dwValueLen;
887 LPCWSTR lpValue;
889 ini = MSSTYLES_GetActiveThemeIni(tf);
891 while((lpName=UXINI_GetNextSection(ini, &dwLen))) {
892 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpName, dwLen, szSysMetrics, -1) == CSTR_EQUAL) {
893 struct PARSECOLORSTATE colorState;
894 struct PARSENONCLIENTSTATE nonClientState;
896 parse_init_color (&colorState);
897 parse_init_nonclient (&nonClientState);
899 while((lpName=UXINI_GetNextValue(ini, &dwLen, &lpValue, &dwValueLen))) {
900 lstrcpynW(szPropertyName, lpName, min(dwLen+1, ARRAY_SIZE(szPropertyName)));
901 if(MSSTYLES_LookupProperty(szPropertyName, &iPropertyPrimitive, &iPropertyId)) {
902 if(iPropertyId >= TMT_FIRSTCOLOR && iPropertyId <= TMT_LASTCOLOR) {
903 if (!parse_handle_color_property (&colorState, iPropertyId,
904 lpValue, dwValueLen))
905 FIXME("Invalid color value for %s\n",
906 debugstr_w(szPropertyName));
908 else if (setMetrics && (iPropertyId == TMT_FLATMENUS)) {
909 BOOL flatMenus = (*lpValue == 'T') || (*lpValue == 't');
910 SystemParametersInfoW (SPI_SETFLATMENU, 0, (PVOID)(INT_PTR)flatMenus, 0);
912 else if ((iPropertyId >= TMT_FIRSTFONT)
913 && (iPropertyId <= TMT_LASTFONT))
915 if (!parse_handle_nonclient_font (&nonClientState,
916 iPropertyId, lpValue, dwValueLen))
917 FIXME("Invalid font value for %s\n",
918 debugstr_w(szPropertyName));
920 else if ((iPropertyId >= TMT_FIRSTSIZE)
921 && (iPropertyId <= TMT_LASTSIZE))
923 if (!parse_handle_nonclient_size (&nonClientState,
924 iPropertyId, lpValue, dwValueLen))
925 FIXME("Invalid size value for %s\n",
926 debugstr_w(szPropertyName));
928 /* Catch all metrics, including colors */
929 MSSTYLES_AddMetric(tf, iPropertyPrimitive, iPropertyId, lpValue, dwValueLen);
931 else {
932 TRACE("Unknown system metric %s\n", debugstr_w(szPropertyName));
935 if (setMetrics)
937 parse_apply_color (&colorState);
938 parse_apply_nonclient (&nonClientState);
940 continue;
942 if(MSSTYLES_ParseIniSectionName(lpName, dwLen, szAppName, szClassName, &iPartId, &iStateId)) {
943 BOOL isGlobal = FALSE;
944 if(!lstrcmpiW(szClassName, szGlobals)) {
945 isGlobal = TRUE;
947 cls = MSSTYLES_AddClass(tf, szAppName, szClassName);
948 ps = MSSTYLES_AddPartState(cls, iPartId, iStateId);
950 while((lpName=UXINI_GetNextValue(ini, &dwLen, &lpValue, &dwValueLen))) {
951 lstrcpynW(szPropertyName, lpName, min(dwLen+1, ARRAY_SIZE(szPropertyName)));
952 if(MSSTYLES_LookupProperty(szPropertyName, &iPropertyPrimitive, &iPropertyId)) {
953 MSSTYLES_AddProperty(ps, iPropertyPrimitive, iPropertyId, lpValue, dwValueLen, isGlobal);
955 else {
956 TRACE("Unknown property %s\n", debugstr_w(szPropertyName));
962 /* App/Class combos override values defined by the base class, map these overrides */
963 globals = MSSTYLES_FindClass(tf, NULL, szGlobals);
964 cls = tf->classes;
965 while(cls) {
966 if(*cls->szAppName) {
967 cls->overrides = MSSTYLES_FindClass(tf, NULL, cls->szClassName);
968 if(!cls->overrides) {
969 TRACE("No overrides found for app %s class %s\n", debugstr_w(cls->szAppName), debugstr_w(cls->szClassName));
971 else {
972 cls->overrides = globals;
975 else {
976 /* Everything overrides globals..except globals */
977 if(cls != globals) cls->overrides = globals;
979 cls = cls->next;
981 UXINI_CloseINI(ini);
983 if(!tf->classes) {
984 ERR("Failed to parse theme ini\n");
988 /***********************************************************************
989 * MSSTYLES_OpenThemeClass
991 * Open a theme class, uses the current active theme
993 * PARAMS
994 * pszAppName Application name, for theme styles specific
995 * to a particular application
996 * pszClassList List of requested classes, semicolon delimited
998 PTHEME_CLASS MSSTYLES_OpenThemeClass(LPCWSTR pszAppName, LPCWSTR pszClassList)
1000 PTHEME_CLASS cls = NULL;
1001 WCHAR szClassName[MAX_THEME_CLASS_NAME];
1002 LPCWSTR start;
1003 LPCWSTR end;
1004 DWORD len;
1006 if(!tfActiveTheme) {
1007 TRACE("there is no active theme\n");
1008 return NULL;
1010 if(!tfActiveTheme->classes) {
1011 return NULL;
1014 start = pszClassList;
1015 while((end = strchrW(start, ';'))) {
1016 len = end-start;
1017 lstrcpynW(szClassName, start, min(len+1, ARRAY_SIZE(szClassName)));
1018 start = end+1;
1019 cls = MSSTYLES_FindClass(tfActiveTheme, pszAppName, szClassName);
1020 if(cls) break;
1022 if(!cls && *start) {
1023 lstrcpynW(szClassName, start, ARRAY_SIZE(szClassName));
1024 cls = MSSTYLES_FindClass(tfActiveTheme, pszAppName, szClassName);
1026 if(cls) {
1027 TRACE("Opened app %s, class %s from list %s\n", debugstr_w(cls->szAppName), debugstr_w(cls->szClassName), debugstr_w(pszClassList));
1028 cls->tf = tfActiveTheme;
1029 cls->tf->dwRefCount++;
1031 return cls;
1034 /***********************************************************************
1035 * MSSTYLES_CloseThemeClass
1037 * Close a theme class
1039 * PARAMS
1040 * tc Theme class to close
1042 * NOTES
1043 * The MSSTYLES_CloseThemeFile decreases the refcount of the owning
1044 * theme file and cleans it up, if needed.
1046 HRESULT MSSTYLES_CloseThemeClass(PTHEME_CLASS tc)
1048 MSSTYLES_CloseThemeFile (tc->tf);
1049 return S_OK;
1052 /***********************************************************************
1053 * MSSTYLES_FindProperty
1055 * Locate a property in a class. Part and state IDs will be used as a
1056 * preference, but may be ignored in the attempt to locate the property.
1057 * Will scan the entire chain of overrides for this class.
1059 PTHEME_PROPERTY MSSTYLES_FindProperty(PTHEME_CLASS tc, int iPartId, int iStateId, int iPropertyPrimitive, int iPropertyId)
1061 PTHEME_CLASS next = tc;
1062 PTHEME_PARTSTATE ps;
1063 PTHEME_PROPERTY tp;
1065 TRACE("(%p, %d, %d, %d)\n", tc, iPartId, iStateId, iPropertyId);
1066 /* Try and find an exact match on part & state */
1067 while(next && (ps = MSSTYLES_FindPartState(next, iPartId, iStateId, &next))) {
1068 if((tp = MSSTYLES_PSFindProperty(ps, iPropertyPrimitive, iPropertyId))) {
1069 return tp;
1072 /* If that fails, and we didn't already try it, search for just part */
1073 if(iStateId != 0)
1074 iStateId = 0;
1075 /* As a last ditch attempt..go for just class */
1076 else if(iPartId != 0)
1077 iPartId = 0;
1078 else
1079 return NULL;
1081 if((tp = MSSTYLES_FindProperty(tc, iPartId, iStateId, iPropertyPrimitive, iPropertyId)))
1082 return tp;
1083 return NULL;
1086 /* Prepare a bitmap to be used for alpha blending */
1087 static BOOL prepare_alpha (HBITMAP bmp, BOOL* hasAlpha)
1089 DIBSECTION dib;
1090 int n;
1091 BYTE* p;
1093 *hasAlpha = FALSE;
1095 if (!bmp || GetObjectW( bmp, sizeof(dib), &dib ) != sizeof(dib))
1096 return FALSE;
1098 if(dib.dsBm.bmBitsPixel != 32)
1099 /* nothing to do */
1100 return TRUE;
1102 *hasAlpha = TRUE;
1103 p = dib.dsBm.bmBits;
1104 n = dib.dsBmih.biHeight * dib.dsBmih.biWidth;
1105 /* AlphaBlend() wants premultiplied alpha, so do that now */
1106 while (n-- > 0)
1108 int a = p[3]+1;
1109 p[0] = (p[0] * a) >> 8;
1110 p[1] = (p[1] * a) >> 8;
1111 p[2] = (p[2] * a) >> 8;
1112 p += 4;
1115 return TRUE;
1118 HBITMAP MSSTYLES_LoadBitmap (PTHEME_CLASS tc, LPCWSTR lpFilename, BOOL* hasAlpha)
1120 WCHAR szFile[MAX_PATH];
1121 LPWSTR tmp;
1122 PTHEME_IMAGE img;
1123 lstrcpynW(szFile, lpFilename, ARRAY_SIZE(szFile));
1124 tmp = szFile;
1125 do {
1126 if(*tmp == '\\') *tmp = '_';
1127 if(*tmp == '/') *tmp = '_';
1128 if(*tmp == '.') *tmp = '_';
1129 } while(*tmp++);
1131 /* Try to locate in list of loaded images */
1132 img = tc->tf->images;
1133 while (img)
1135 if (lstrcmpiW (szFile, img->name) == 0)
1137 TRACE ("found %p %s: %p\n", img, debugstr_w (img->name), img->image);
1138 *hasAlpha = img->hasAlpha;
1139 return img->image;
1141 img = img->next;
1143 /* Not found? Load from resources */
1144 img = heap_alloc(sizeof(*img));
1145 img->image = LoadImageW(tc->hTheme, szFile, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
1146 prepare_alpha (img->image, hasAlpha);
1147 img->hasAlpha = *hasAlpha;
1148 /* ...and stow away for later reuse. */
1149 lstrcpyW (img->name, szFile);
1150 img->next = tc->tf->images;
1151 tc->tf->images = img;
1152 TRACE ("new %p %s: %p\n", img, debugstr_w (img->name), img->image);
1153 return img->image;
1156 static BOOL MSSTYLES_GetNextInteger(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, int *value)
1158 LPCWSTR cur = lpStringStart;
1159 int total = 0;
1160 BOOL gotNeg = FALSE;
1162 while(cur < lpStringEnd && (*cur < '0' || *cur > '9' || *cur == '-')) cur++;
1163 if(cur >= lpStringEnd) {
1164 return FALSE;
1166 if(*cur == '-') {
1167 cur++;
1168 gotNeg = TRUE;
1170 while(cur < lpStringEnd && (*cur >= '0' && *cur <= '9')) {
1171 total = total * 10 + (*cur - '0');
1172 cur++;
1174 if(gotNeg) total = -total;
1175 *value = total;
1176 if(lpValEnd) *lpValEnd = cur;
1177 return TRUE;
1180 static inline BOOL isSpace(WCHAR c)
1182 return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
1185 static BOOL MSSTYLES_GetNextToken(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, LPWSTR lpBuff, DWORD buffSize) {
1186 LPCWSTR cur = lpStringStart;
1187 LPCWSTR start;
1188 LPCWSTR end;
1190 while(cur < lpStringEnd && (isSpace(*cur) || *cur == ',')) cur++;
1191 if(cur >= lpStringEnd) {
1192 return FALSE;
1194 start = cur;
1195 while(cur < lpStringEnd && *cur != ',') cur++;
1196 end = cur;
1197 while(isSpace(*end)) end--;
1199 lstrcpynW(lpBuff, start, min(buffSize, end-start+1));
1201 if(lpValEnd) *lpValEnd = cur;
1202 return TRUE;
1205 /***********************************************************************
1206 * MSSTYLES_GetPropertyBool
1208 * Retrieve a color value for a property
1210 HRESULT MSSTYLES_GetPropertyBool(PTHEME_PROPERTY tp, BOOL *pfVal)
1212 *pfVal = FALSE;
1213 if(*tp->lpValue == 't' || *tp->lpValue == 'T')
1214 *pfVal = TRUE;
1215 return S_OK;
1218 /***********************************************************************
1219 * MSSTYLES_GetPropertyColor
1221 * Retrieve a color value for a property
1223 HRESULT MSSTYLES_GetPropertyColor(PTHEME_PROPERTY tp, COLORREF *pColor)
1225 LPCWSTR lpEnd;
1226 LPCWSTR lpCur;
1227 int red, green, blue;
1229 lpCur = tp->lpValue;
1230 lpEnd = tp->lpValue + tp->dwValueLen;
1232 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &red)) {
1233 TRACE("Could not parse color property\n");
1234 return E_PROP_ID_UNSUPPORTED;
1236 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &green)) {
1237 TRACE("Could not parse color property\n");
1238 return E_PROP_ID_UNSUPPORTED;
1240 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &blue)) {
1241 TRACE("Could not parse color property\n");
1242 return E_PROP_ID_UNSUPPORTED;
1244 *pColor = RGB(red,green,blue);
1245 return S_OK;
1248 /***********************************************************************
1249 * MSSTYLES_GetPropertyColor
1251 * Retrieve a color value for a property
1253 static HRESULT MSSTYLES_GetFont (LPCWSTR lpCur, LPCWSTR lpEnd,
1254 LPCWSTR *lpValEnd, LOGFONTW* pFont)
1256 static const WCHAR szBold[] = {'b','o','l','d','\0'};
1257 static const WCHAR szItalic[] = {'i','t','a','l','i','c','\0'};
1258 static const WCHAR szUnderline[] = {'u','n','d','e','r','l','i','n','e','\0'};
1259 static const WCHAR szStrikeOut[] = {'s','t','r','i','k','e','o','u','t','\0'};
1260 int pointSize;
1261 WCHAR attr[32];
1263 if(!MSSTYLES_GetNextToken(lpCur, lpEnd, &lpCur, pFont->lfFaceName, LF_FACESIZE)) {
1264 TRACE("Property is there, but failed to get face name\n");
1265 *lpValEnd = lpCur;
1266 return E_PROP_ID_UNSUPPORTED;
1268 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pointSize)) {
1269 TRACE("Property is there, but failed to get point size\n");
1270 *lpValEnd = lpCur;
1271 return E_PROP_ID_UNSUPPORTED;
1273 pFont->lfHeight = pointSize;
1274 pFont->lfWeight = FW_REGULAR;
1275 pFont->lfCharSet = DEFAULT_CHARSET;
1276 while(MSSTYLES_GetNextToken(lpCur, lpEnd, &lpCur, attr, ARRAY_SIZE(attr))) {
1277 if(!lstrcmpiW(szBold, attr)) pFont->lfWeight = FW_BOLD;
1278 else if(!lstrcmpiW(szItalic, attr)) pFont->lfItalic = TRUE;
1279 else if(!lstrcmpiW(szUnderline, attr)) pFont->lfUnderline = TRUE;
1280 else if(!lstrcmpiW(szStrikeOut, attr)) pFont->lfStrikeOut = TRUE;
1282 *lpValEnd = lpCur;
1283 return S_OK;
1286 HRESULT MSSTYLES_GetPropertyFont(PTHEME_PROPERTY tp, HDC hdc, LOGFONTW *pFont)
1288 LPCWSTR lpCur = tp->lpValue;
1289 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1290 HRESULT hr;
1292 ZeroMemory(pFont, sizeof(LOGFONTW));
1293 hr = MSSTYLES_GetFont (lpCur, lpEnd, &lpCur, pFont);
1294 if (SUCCEEDED (hr))
1295 pFont->lfHeight = -MulDiv(pFont->lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1297 return hr;
1300 /***********************************************************************
1301 * MSSTYLES_GetPropertyInt
1303 * Retrieve an int value for a property
1305 HRESULT MSSTYLES_GetPropertyInt(PTHEME_PROPERTY tp, int *piVal)
1307 if(!MSSTYLES_GetNextInteger(tp->lpValue, (tp->lpValue + tp->dwValueLen), NULL, piVal)) {
1308 TRACE("Could not parse int property\n");
1309 return E_PROP_ID_UNSUPPORTED;
1311 return S_OK;
1314 /***********************************************************************
1315 * MSSTYLES_GetPropertyIntList
1317 * Retrieve an int list value for a property
1319 HRESULT MSSTYLES_GetPropertyIntList(PTHEME_PROPERTY tp, INTLIST *pIntList)
1321 int i;
1322 LPCWSTR lpCur = tp->lpValue;
1323 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1325 for(i=0; i < MAX_INTLIST_COUNT; i++) {
1326 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pIntList->iValues[i]))
1327 break;
1329 pIntList->iValueCount = i;
1330 return S_OK;
1333 /***********************************************************************
1334 * MSSTYLES_GetPropertyPosition
1336 * Retrieve a position value for a property
1338 HRESULT MSSTYLES_GetPropertyPosition(PTHEME_PROPERTY tp, POINT *pPoint)
1340 int x,y;
1341 LPCWSTR lpCur = tp->lpValue;
1342 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1344 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &x)) {
1345 TRACE("Could not parse position property\n");
1346 return E_PROP_ID_UNSUPPORTED;
1348 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &y)) {
1349 TRACE("Could not parse position property\n");
1350 return E_PROP_ID_UNSUPPORTED;
1352 pPoint->x = x;
1353 pPoint->y = y;
1354 return S_OK;
1357 /***********************************************************************
1358 * MSSTYLES_GetPropertyString
1360 * Retrieve a string value for a property
1362 HRESULT MSSTYLES_GetPropertyString(PTHEME_PROPERTY tp, LPWSTR pszBuff, int cchMaxBuffChars)
1364 lstrcpynW(pszBuff, tp->lpValue, min(tp->dwValueLen+1, cchMaxBuffChars));
1365 return S_OK;
1368 /***********************************************************************
1369 * MSSTYLES_GetPropertyRect
1371 * Retrieve a rect value for a property
1373 HRESULT MSSTYLES_GetPropertyRect(PTHEME_PROPERTY tp, RECT *pRect)
1375 LPCWSTR lpCur = tp->lpValue;
1376 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1378 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pRect->left);
1379 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pRect->top);
1380 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pRect->right);
1381 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pRect->bottom)) {
1382 TRACE("Could not parse rect property\n");
1383 return E_PROP_ID_UNSUPPORTED;
1385 return S_OK;
1388 /***********************************************************************
1389 * MSSTYLES_GetPropertyMargins
1391 * Retrieve a margins value for a property
1393 HRESULT MSSTYLES_GetPropertyMargins(PTHEME_PROPERTY tp, RECT *prc, MARGINS *pMargins)
1395 LPCWSTR lpCur = tp->lpValue;
1396 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1398 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pMargins->cxLeftWidth);
1399 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pMargins->cxRightWidth);
1400 MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pMargins->cyTopHeight);
1401 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pMargins->cyBottomHeight)) {
1402 TRACE("Could not parse margins property\n");
1403 return E_PROP_ID_UNSUPPORTED;
1405 return S_OK;