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 } 1458