Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1830 lines
57 KiB

  1. //---------------------------------------------------------------------------
  2. // Loader.cpp - loads the theme data into shared memory
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include <regstr.h>
  6. #include "Loader.h"
  7. #include "Parser.h"
  8. #include "Utils.h"
  9. #include "TmReg.h"
  10. #include "TmUtils.h"
  11. #include "syscolors.h"
  12. #include "Render.h"
  13. #include "BorderFill.h"
  14. #include "ImageFile.h"
  15. #include "TextDraw.h"
  16. #include "info.h"
  17. //---------------------------------------------------------------------------
  18. #define POINTS_DPI96(pts) -MulDiv(pts, 96, 72)
  19. //---------------------------------------------------------------------------
  20. WCHAR pszColorsKey[] = L"Control Panel\\Colors";
  21. //---------------------------------------------------------------------------
  22. typedef struct
  23. {
  24. THEMEMETRICS tm;
  25. HANDLE hUserToken;
  26. } THEMEMETRICS_THREADINFO;
  27. //---------------------------------------------------------------------------
  28. CThemeLoader::CThemeLoader()
  29. {
  30. _pbLocalData = NULL;
  31. _iEntryHdrLevel = -1;
  32. InitThemeMetrics(&_LoadThemeMetrics);
  33. SYSTEM_INFO si;
  34. GetSystemInfo(&si);
  35. _dwPageSize = si.dwPageSize;
  36. }
  37. //---------------------------------------------------------------------------
  38. CThemeLoader::~CThemeLoader()
  39. {
  40. FreeLocalTheme();
  41. }
  42. //---------------------------------------------------------------------------
  43. HRESULT CThemeLoader::LoadClassDataIni(HINSTANCE hInst, LPCWSTR pszColorName,
  44. LPCWSTR pszSizeName, LPWSTR pszFoundIniName, DWORD dwMaxIniNameChars, LPWSTR *ppIniData)
  45. {
  46. COLORSIZECOMBOS *combos;
  47. HRESULT hr = FindComboData(hInst, &combos);
  48. if (FAILED(hr))
  49. return hr;
  50. int iSizeIndex = 0;
  51. int iColorIndex = 0;
  52. if ((pszColorName) && (* pszColorName))
  53. {
  54. hr = GetColorSchemeIndex(hInst, pszColorName, &iColorIndex);
  55. if (FAILED(hr))
  56. return hr;
  57. }
  58. if ((pszSizeName) && (* pszSizeName))
  59. {
  60. hr = GetSizeIndex(hInst, pszSizeName, &iSizeIndex);
  61. if (FAILED(hr))
  62. return hr;
  63. }
  64. int filenum = COMBOENTRY(combos, iColorIndex, iSizeIndex);
  65. if (filenum == -1)
  66. return MakeError32(ERROR_NOT_FOUND);
  67. //---- locate resname for classdata file "filenum" ----
  68. hr = GetResString(hInst, L"FILERESNAMES", filenum, pszFoundIniName, dwMaxIniNameChars);
  69. if (SUCCEEDED(hr))
  70. {
  71. hr = AllocateTextResource(hInst, pszFoundIniName, ppIniData);
  72. if (FAILED(hr))
  73. return hr;
  74. }
  75. return hr;
  76. }
  77. //---------------------------------------------------------------------------
  78. HRESULT CThemeLoader::LoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam,
  79. LPCWSTR pszSizeParam, OUT HANDLE *pHandle, BOOL fGlobalTheme)
  80. {
  81. HRESULT hr;
  82. CThemeParser *pParser = NULL;
  83. HINSTANCE hInst = NULL;
  84. WCHAR *pThemesIni = NULL;
  85. WCHAR *pDataIni = NULL;
  86. WCHAR szClassDataName[_MAX_PATH+1];
  87. DWORD dwStartTime = StartTimer();
  88. Log(LOG_TMCHANGE, L"LoadTheme: filename=%s", pszThemeName);
  89. FreeLocalTheme();
  90. //---- allocate a local theme data to construct ----
  91. _pbLocalData = (BYTE*) VirtualAlloc(NULL, MAX_SHAREDMEM_SIZE, MEM_RESERVE, PAGE_READWRITE);
  92. if (NULL == _pbLocalData)
  93. {
  94. hr = MakeError32(E_OUTOFMEMORY);
  95. goto exit;
  96. }
  97. _iLocalLen = 0;
  98. //---- load the Color Scheme from "themes.ini" ----
  99. hr = LoadThemeLibrary(pszThemeName, &hInst);
  100. if (FAILED(hr))
  101. goto exit;
  102. pParser = new CThemeParser(fGlobalTheme);
  103. if (! pParser)
  104. {
  105. hr = MakeError32(E_OUTOFMEMORY);
  106. goto exit;
  107. }
  108. //---- if a color scheme is specified, ask parser to load it ----
  109. if ((pszColorParam) && (*pszColorParam))
  110. {
  111. //---- load the "themes.ini" text ----
  112. hr = AllocateTextResource(hInst, CONTAINER_RESNAME, &pThemesIni);
  113. if (FAILED(hr))
  114. goto exit;
  115. //---- parser call to load color scheme & keep state ----
  116. hr = pParser->ParseThemeBuffer(pThemesIni,
  117. CONTAINER_RESNAME, pszColorParam, hInst, this, NULL, NULL, PTF_CONTAINER_PARSE);
  118. if (FAILED(hr))
  119. goto exit;
  120. }
  121. //---- load the classdata file resource into memory ----
  122. hr = LoadClassDataIni(hInst, pszColorParam, pszSizeParam, szClassDataName,
  123. ARRAYSIZE(szClassDataName), &pDataIni);
  124. if (FAILED(hr))
  125. goto exit;
  126. //---- parse & build binary theme ----
  127. hr = pParser->ParseThemeBuffer(pDataIni,
  128. szClassDataName, pszColorParam, hInst, this, NULL, NULL, PTF_CLASSDATA_PARSE);
  129. if (FAILED(hr))
  130. goto exit;
  131. _fGlobalTheme = fGlobalTheme;
  132. hr = PackAndLoadTheme(pszThemeName, pszColorParam, pszSizeParam, hInst);
  133. if (FAILED(hr))
  134. goto exit;
  135. if (LogOptionOn(LO_TMLOAD))
  136. {
  137. DWORD dwTicks;
  138. dwTicks = StopTimer(dwStartTime);
  139. WCHAR buff[100];
  140. TimeToStr(dwTicks, buff, ARRAYSIZE(buff));
  141. Log(LOG_TMLOAD, L"LoadTheme took: %s", buff);
  142. }
  143. exit:
  144. if (FAILED(hr) && pParser)
  145. {
  146. pParser->CleanupStockBitmaps();
  147. }
  148. if (pParser)
  149. delete pParser;
  150. if (hInst)
  151. FreeLibrary(hInst);
  152. if (pThemesIni)
  153. delete [] pThemesIni;
  154. if (pDataIni)
  155. delete [] pDataIni;
  156. FreeLocalTheme();
  157. if (SUCCEEDED(hr))
  158. {
  159. if (_fGlobalTheme)
  160. {
  161. THEMEHDR *hdr = (THEMEHDR *) _LoadingThemeFile._pbThemeData;
  162. hdr->dwFlags |= SECTION_HASSTOCKOBJECTS;
  163. }
  164. //---- transfer theme file handle to caller ----
  165. *pHandle = _LoadingThemeFile.Unload();
  166. }
  167. else
  168. {
  169. _LoadingThemeFile.CloseFile();
  170. }
  171. return hr;
  172. }
  173. //---------------------------------------------------------------------------
  174. void CThemeLoader::FreeLocalTheme()
  175. {
  176. if (_pbLocalData)
  177. {
  178. VirtualFree(_pbLocalData, 0, MEM_RELEASE);
  179. _pbLocalData = NULL;
  180. _iLocalLen = 0;
  181. }
  182. _LocalIndexes.RemoveAll();
  183. }
  184. //---------------------------------------------------------------------------
  185. HRESULT CThemeLoader::EmitAndCopyBlock(MIXEDPTRS &u, void *pSrc, DWORD dwLen)
  186. {
  187. HRESULT hr = AllocateThemeFileBytes(u.pb, dwLen);
  188. if (FAILED(hr))
  189. return hr;
  190. CopyMemory(u.pb, (BYTE*) pSrc, dwLen);
  191. u.pb += dwLen;
  192. return S_OK;
  193. }
  194. //---------------------------------------------------------------------------
  195. HRESULT CThemeLoader::EmitObject(MIXEDPTRS &u, SHORT propnum, BYTE privnum, void *pHdr, DWORD dwHdrLen, void *pObj, DWORD dwObjLen)
  196. {
  197. EmitEntryHdr(u, propnum, privnum);
  198. HRESULT hr = AllocateThemeFileBytes(u.pb, dwHdrLen + dwObjLen);
  199. if (FAILED(hr))
  200. return hr;
  201. CopyMemory(u.pb, (BYTE*) pHdr, dwHdrLen);
  202. u.pb += dwHdrLen;
  203. CopyMemory(u.pb, (BYTE*) pObj, dwObjLen);
  204. u.pb += dwObjLen;
  205. EndEntry(u);
  206. return S_OK;
  207. }
  208. //---------------------------------------------------------------------------
  209. HRESULT CThemeLoader::EmitString(MIXEDPTRS &u, LPCWSTR pszSrc, DWORD cchSrc, int *piOffSet)
  210. {
  211. HRESULT hr = AllocateThemeFileBytes(u.pb, (cchSrc + 1) * sizeof(WCHAR));
  212. if (FAILED(hr))
  213. return hr;
  214. StringCchCopyW(u.px, cchSrc + 1, pszSrc);
  215. if (piOffSet)
  216. {
  217. *piOffSet = THEME_OFFSET(u.pb);
  218. }
  219. u.px += cchSrc + 1;
  220. return S_OK;
  221. }
  222. //---------------------------------------------------------------------------
  223. int CThemeLoader::GetMaxState(APPCLASSLOCAL *ac, int iPartNum)
  224. {
  225. //---- calculate max. state index ----
  226. int iMaxState = -1;
  227. int pscnt = ac->PartStateIndexes.GetSize();
  228. for (int i=0; i < pscnt; i++)
  229. {
  230. PART_STATE_INDEX *psi = &ac->PartStateIndexes[i];
  231. if (psi->iPartNum == iPartNum)
  232. {
  233. if (psi->iStateNum > iMaxState)
  234. iMaxState = psi->iStateNum;
  235. }
  236. }
  237. return iMaxState;
  238. }
  239. //---------------------------------------------------------------------------
  240. HRESULT CThemeLoader::CopyPartGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iPartNum,
  241. int *piPartJumpTable, int iPartZeroIndex, int iGlobalsOffset, BOOL fGlobalsGroup)
  242. {
  243. HRESULT hr = S_OK;
  244. int *piStateJumpTable = NULL;
  245. //---- calculate max. state index ----
  246. int iMaxState = GetMaxState(ac, iPartNum);
  247. if (iMaxState < 0) // no states to copy
  248. goto exit;
  249. //---- update part jump table index ----
  250. if (piPartJumpTable)
  251. piPartJumpTable[iPartNum] = THEME_OFFSET(u.pb);
  252. if (iMaxState > 0) // create a state jump table
  253. {
  254. //---- create state jump table ----
  255. hr = EmitEntryHdr(u, TMT_STATEJUMPTABLE, TMT_STATEJUMPTABLE);
  256. if (FAILED(hr))
  257. goto exit;
  258. int statecnt = 1 + iMaxState;
  259. hr = AllocateThemeFileBytes(u.pb, 1 + statecnt * sizeof(int));
  260. if (FAILED(hr))
  261. goto exit;
  262. // 1 byte table entry count
  263. *u.pb++ = (BYTE)statecnt;
  264. piStateJumpTable = u.pi;
  265. //---- default "not avail" indexes for children ----
  266. for (int j=0; j < statecnt; j++)
  267. *u.pi++ = -1;
  268. EndEntry(u);
  269. }
  270. int pscnt, iStateZeroIndex;
  271. iStateZeroIndex = THEME_OFFSET(u.pb);
  272. pscnt = ac->PartStateIndexes.GetSize();
  273. //---- copy each defined part/state section ----
  274. for (int state=0; state <= iMaxState; state++)
  275. {
  276. PART_STATE_INDEX *psi = NULL;
  277. //---- find entry for "state" ----
  278. for (int i=0; i < pscnt; i++)
  279. {
  280. psi = &ac->PartStateIndexes[i];
  281. if ((psi->iPartNum == iPartNum) && (psi->iStateNum == state))
  282. break;
  283. }
  284. if (i == pscnt) // not found
  285. continue;
  286. //---- update state jump table entry ----
  287. if (piStateJumpTable)
  288. piStateJumpTable[state] = THEME_OFFSET(u.pb);
  289. //---- copy the actual PART/STATE DATA ----
  290. hr = EmitAndCopyBlock(u, _pbLocalData+psi->iIndex, psi->iLen);
  291. //---- update child's "JumpToParent" value ----
  292. if (! state)
  293. {
  294. if (fGlobalsGroup)
  295. {
  296. *(u.pi-1) = -1; // end of the line
  297. }
  298. else if (! iPartNum) // simple class jumps to globals
  299. {
  300. *(u.pi-1) = iGlobalsOffset;
  301. }
  302. else // parts jumps to their base class
  303. {
  304. *(u.pi-1) = iPartZeroIndex;
  305. }
  306. }
  307. else // states jumps to their base part
  308. {
  309. *(u.pi-1) = iStateZeroIndex;
  310. }
  311. }
  312. exit:
  313. return hr;
  314. }
  315. //---------------------------------------------------------------------------
  316. HRESULT CThemeLoader::CopyClassGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iGlobalsOffset,
  317. int iClassNameOffset)
  318. {
  319. HRESULT hr = S_OK;
  320. int *piPartJumpTable = NULL;
  321. int *piFirstPackObj = NULL;
  322. int partcnt;
  323. int iPartZeroIndex;
  324. CRenderObj *pRender = NULL;
  325. BOOL fGlobals = (iGlobalsOffset == THEME_OFFSET(u.pb));
  326. BYTE *pStartOfSection = u.pb;
  327. BOOL fGlobalGroup = (THEME_OFFSET(u.pb) == iGlobalsOffset);
  328. //---- always create a part table ----
  329. hr = EmitEntryHdr(u, TMT_PARTJUMPTABLE, TMT_PARTJUMPTABLE);
  330. if (FAILED(hr))
  331. goto exit;
  332. partcnt = 1 + ac->iMaxPartNum;
  333. // offset to first packed DrawObj/TextObj
  334. piFirstPackObj = u.pi;
  335. hr = AllocateThemeFileBytes(u.pb, 1 + (1 + partcnt) * sizeof(int));
  336. if (FAILED(hr))
  337. goto exit;
  338. *u.pi++ = 0; // will update later
  339. // partcnt
  340. *u.pb++ = (BYTE)partcnt;
  341. piPartJumpTable = u.pi;
  342. //---- default "not avail" indexes for children ----
  343. for (int j=0; j < partcnt; j++)
  344. *u.pi++ = -1;
  345. EndEntry(u);
  346. iPartZeroIndex = THEME_OFFSET(u.pb);
  347. //---- copy each defined part section ----
  348. for (int j=0; j <= ac->iMaxPartNum; j++)
  349. {
  350. CopyPartGroup(ac, u, j, piPartJumpTable, iPartZeroIndex,
  351. iGlobalsOffset, fGlobalGroup);
  352. }
  353. //---- now, extract draw objs for each part/state as needed ----
  354. *piFirstPackObj = THEME_OFFSET(u.pb);
  355. //---- build a CRenderObj to access the just copied class section ----
  356. hr = CreateRenderObj(&_LoadingThemeFile, 0, THEME_OFFSET(pStartOfSection),
  357. iClassNameOffset, 0, FALSE, NULL, NULL, 0, &pRender);
  358. if (FAILED(hr))
  359. goto exit;
  360. if (fGlobals)
  361. _iGlobalsDrawObj = THEME_OFFSET(u.pb);
  362. hr = PackDrawObjects(u, pRender, ac->iMaxPartNum, fGlobals);
  363. if (FAILED(hr))
  364. goto exit;
  365. if (fGlobals)
  366. _iGlobalsTextObj = THEME_OFFSET(u.pb);
  367. hr = PackTextObjects(u, pRender, ac->iMaxPartNum, fGlobals);
  368. if (FAILED(hr))
  369. goto exit;
  370. //---- write "end of class" marker ----
  371. hr = EmitEntryHdr(u, TMT_ENDOFCLASS, TMT_ENDOFCLASS);
  372. if (FAILED(hr))
  373. goto exit;
  374. EndEntry(u);
  375. exit:
  376. delete pRender;
  377. return hr;
  378. }
  379. //---------------------------------------------------------------------------
  380. __inline HRESULT CThemeLoader::AllocateThemeFileBytes(BYTE *upb, DWORD dwAdditionalLen)
  381. {
  382. ASSERT(upb != NULL && _LoadingThemeFile._pbThemeData != NULL);
  383. if (PtrToUint(upb) / _dwPageSize != PtrToUint(upb + dwAdditionalLen) / _dwPageSize)
  384. {
  385. if (NULL == VirtualAlloc(_LoadingThemeFile._pbThemeData, upb - _LoadingThemeFile._pbThemeData + 1 + dwAdditionalLen, MEM_COMMIT, PAGE_READWRITE))
  386. {
  387. return MakeError32(ERROR_NOT_ENOUGH_MEMORY);
  388. }
  389. }
  390. return S_OK;
  391. }
  392. //---------------------------------------------------------------------------
  393. HRESULT CThemeLoader::CopyLocalThemeToLive(int iTotalLength,
  394. LPCWSTR pszThemeName, LPCWSTR pszColorParam, LPCWSTR pszSizeParam)
  395. {
  396. int i;
  397. MIXEDPTRS u;
  398. HRESULT hr = S_OK;
  399. u.pb = (BYTE*) VirtualAlloc(_LoadingThemeFile._pbThemeData, sizeof(THEMEHDR), MEM_COMMIT, PAGE_READWRITE);
  400. if (u.pb == NULL)
  401. {
  402. return MakeError32(ERROR_NOT_ENOUGH_MEMORY);
  403. }
  404. _iGlobalsOffset = -1;
  405. _iSysMetricsOffset = -1;
  406. int iIndexCount = _LocalIndexes.GetSize();
  407. //---- build header ----
  408. THEMEHDR *hdr = (THEMEHDR *)u.pb;
  409. u.pb += sizeof(THEMEHDR);
  410. hdr->dwTotalLength = iTotalLength;
  411. CopyMemory(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature);
  412. // note: hdr->szSignature should not be null terminated
  413. hdr->dwVersion = THEMEDATA_VERSION;
  414. hdr->dwFlags = 0; // not yet ready to be accessed
  415. hdr->iDllNameOffset = 0; // will be updated
  416. hdr->iColorParamOffset = 0; // will be updated
  417. hdr->iSizeParamOffset = 0; // will be updated
  418. hdr->dwLangID = (DWORD) GetUserDefaultUILanguage();
  419. hdr->iLoadId = 0; // was iLoadCounter
  420. hdr->iGlobalsOffset = 0; // will be updated
  421. hdr->iGlobalsTextObjOffset = 0; // will be updated
  422. hdr->iGlobalsDrawObjOffset = 0; // will be updated
  423. hdr->dwCheckSum = 0; // will be updated
  424. // Store the time stamp of the .msstyles file in the live file, this will be written to the cache file
  425. // for later comparison (Whistler:190202).
  426. ZeroMemory(&hdr->ftModifTimeStamp, sizeof hdr->ftModifTimeStamp);
  427. HANDLE hFile = CreateFile(pszThemeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  428. FILE_ATTRIBUTE_NORMAL, NULL);
  429. if (hFile != INVALID_HANDLE_VALUE)
  430. {
  431. // There's nothing we can do if GetFileTime() fails
  432. GetFileTime(hFile, NULL, NULL, &hdr->ftModifTimeStamp);
  433. CloseHandle(hFile);
  434. }
  435. //---- build string section ----
  436. hdr->iStringsOffset = THEME_OFFSET(u.pb);
  437. DWORD *pdwFirstString = u.pdw;
  438. int len;
  439. //---- add header strings ----
  440. len = lstrlen(pszThemeName);
  441. if (len)
  442. {
  443. hr = EmitString(u, pszThemeName, len, &hdr->iDllNameOffset);
  444. if (FAILED(hr))
  445. goto exit;
  446. }
  447. len = lstrlen(pszColorParam);
  448. if (len)
  449. {
  450. hr = EmitString(u, pszColorParam, len, &hdr->iColorParamOffset);
  451. if (FAILED(hr))
  452. goto exit;
  453. }
  454. len = lstrlen(pszSizeParam);
  455. if (len)
  456. {
  457. hr = EmitString(u, pszSizeParam, len, &hdr->iSizeParamOffset);
  458. if (FAILED(hr))
  459. goto exit;
  460. }
  461. //---- add strings from class index ----
  462. for (i=0; i < iIndexCount; i++)
  463. {
  464. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  465. int len = ac->csAppName.GetLength();
  466. if (len)
  467. {
  468. hr = EmitString(u, ac->csAppName, len, (int*) &ac->LiveIndex.dwAppNameIndex);
  469. if (FAILED(hr))
  470. goto exit;
  471. }
  472. else
  473. ac->LiveIndex.dwAppNameIndex = 0;
  474. len = ac->csClassName.GetLength();
  475. if (len)
  476. {
  477. hr = EmitString(u, ac->csClassName, len, (int*) &ac->LiveIndex.dwClassNameIndex);
  478. if (FAILED(hr))
  479. goto exit;
  480. }
  481. else
  482. ac->LiveIndex.dwClassNameIndex = 0;
  483. }
  484. //---- copy strings from LOADTHEMEMETRICS -----
  485. for (i=0; i < TM_STRINGCOUNT; i++)
  486. {
  487. CWideString *ws = &_LoadThemeMetrics.wsStrings[i];
  488. int len = ws->GetLength();
  489. if (len)
  490. {
  491. hr = EmitString(u, *ws, len, &_LoadThemeMetrics.iStringOffsets[i]);
  492. if (FAILED(hr))
  493. goto exit;
  494. }
  495. else
  496. _LoadThemeMetrics.iStringOffsets[i] = 0;
  497. }
  498. int iStringLength = int(u.pb - ((BYTE *)pdwFirstString));
  499. hdr->iStringsLength = iStringLength;
  500. //---- write index header ----
  501. hdr->iSectionIndexOffset = THEME_OFFSET(u.pb);
  502. hdr->iSectionIndexLength = iIndexCount * sizeof(APPCLASSLIVE);
  503. APPCLASSLIVE *acl = (APPCLASSLIVE *)u.pb; // will write these in parallel with theme data
  504. hr = AllocateThemeFileBytes(u.pb, hdr->iSectionIndexLength);
  505. if (FAILED(hr))
  506. goto exit;
  507. u.pb += hdr->iSectionIndexLength;
  508. //---- write index AND theme data in parallel ----
  509. //---- first pass thru, copy [globals] and all [app::xxx] sections ----
  510. for (i=0; i < iIndexCount; i++) // for each parent section
  511. {
  512. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  513. if ((i) && (! ac->LiveIndex.dwAppNameIndex)) // not an [app::] section
  514. continue;
  515. acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex;
  516. acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
  517. acl->iIndex = THEME_OFFSET(u.pb);
  518. if (AsciiStrCmpI(ac->csClassName, L"globals")== 0) // globals section
  519. _iGlobalsOffset = acl->iIndex;
  520. hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex);
  521. if (FAILED(hr))
  522. goto exit;
  523. acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex;
  524. acl++;
  525. }
  526. //---- second pass thru, copy all non-[app::xxx] sections (except [globals]) ----
  527. for (i=0; i < iIndexCount; i++) // for each parent section
  528. {
  529. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  530. if ((! i) || (ac->LiveIndex.dwAppNameIndex)) // don't process [app::] sections
  531. continue;
  532. acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex;
  533. acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
  534. acl->iIndex = THEME_OFFSET(u.pb);
  535. if (AsciiStrCmpI(ac->csClassName, L"sysmetrics")== 0) // SysMetrics section
  536. {
  537. _iSysMetricsOffset = acl->iIndex;
  538. hr = EmitEntryHdr(u, TMT_THEMEMETRICS, TMT_THEMEMETRICS);
  539. if (FAILED(hr))
  540. goto exit;
  541. DWORD len = sizeof(THEMEMETRICS);
  542. hr = EmitAndCopyBlock(u, (BYTE*) (THEMEMETRICS*) &_LoadThemeMetrics, len);
  543. EndEntry(u);
  544. //---- add a "jump to parent" to be consistent (not used) ----
  545. hr = EmitEntryHdr(u, TMT_JUMPTOPARENT, TMT_JUMPTOPARENT);
  546. if (FAILED(hr))
  547. goto exit;
  548. hr = AllocateThemeFileBytes(u.pb, sizeof(int));
  549. if (FAILED(hr))
  550. goto exit;
  551. *u.pi++ = -1;
  552. EndEntry(u);
  553. }
  554. else // regular section
  555. {
  556. hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex);
  557. if (FAILED(hr))
  558. goto exit;
  559. }
  560. acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex;
  561. acl++;
  562. }
  563. hr = EmitAndCopyBlock(u, (BYTE*) kszEndCacheFileSignature, kcbEndSignature);
  564. if (FAILED(hr))
  565. goto exit;
  566. //---- ensure we got the calc size right ----
  567. DWORD dwActualLen;
  568. dwActualLen = THEME_OFFSET(u.pb);
  569. if (hdr->dwTotalLength != dwActualLen)
  570. {
  571. //---- make this growable so we really have enough room ----
  572. //Log(LOG_TMCHANGE, L"ThemeLoader - calculated len=%d, actual len=%d",
  573. // hdr->dwTotalLength, dwActualLen);
  574. hdr->dwTotalLength = dwActualLen;
  575. }
  576. Log(LOG_TMCHANGE, L"ThemeLoader - theme size: %d", dwActualLen);
  577. //----- update header fields ----
  578. hdr->dwFlags |= SECTION_READY;
  579. hdr->iGlobalsOffset = _iGlobalsOffset;
  580. hdr->iSysMetricsOffset = _iSysMetricsOffset;
  581. hdr->iGlobalsTextObjOffset = _iGlobalsTextObj;
  582. hdr->iGlobalsDrawObjOffset = _iGlobalsDrawObj;
  583. hdr->dwCheckSum = 0; // Reserved for future use. (old checksum was too slow.).
  584. exit:
  585. return hr;
  586. }
  587. //---------------------------------------------------------------------------
  588. HRESULT CThemeLoader::PackMetrics()
  589. {
  590. //---- find the optional [SysMetrics] section ----
  591. int iIndexCount = _LocalIndexes.GetSize();
  592. APPCLASSLOCAL *ac = NULL;
  593. for (int i=0; i < iIndexCount; i++)
  594. {
  595. ac = &_LocalIndexes[i];
  596. if (AsciiStrCmpI(ac->csClassName, L"SysMetrics")==0)
  597. break;
  598. }
  599. if (i == iIndexCount) // not found
  600. return S_OK;
  601. //---- walk thru the properties & put into _LoadThemeMetrics ----
  602. if (! ac->PartStateIndexes.GetSize()) // no data
  603. return S_OK;
  604. MIXEDPTRS u;
  605. //---- parts & states not allowed so just use entry "0" ----
  606. u.pb = _pbLocalData + ac->PartStateIndexes[0].iIndex;
  607. UCHAR *lastpb = u.pb + ac->PartStateIndexes[0].iLen;
  608. while ((u.pb < lastpb) && (*u.pw != TMT_JUMPTOPARENT))
  609. {
  610. UNPACKED_ENTRYHDR hdr;
  611. FillAndSkipHdr(u, &hdr);
  612. switch (hdr.ePrimVal)
  613. {
  614. case TMT_FONT:
  615. _LoadThemeMetrics.lfFonts[hdr.usTypeNum-TMT_FIRSTFONT] = *(LOGFONT *)u.pb;
  616. break;
  617. case TMT_COLOR:
  618. _LoadThemeMetrics.crColors[hdr.usTypeNum-TMT_FIRSTCOLOR] = *(COLORREF *)u.pb;
  619. break;
  620. case TMT_BOOL:
  621. _LoadThemeMetrics.fBools[hdr.usTypeNum-TMT_FIRSTBOOL] = (BOOL)*u.pb;
  622. break;
  623. case TMT_SIZE:
  624. _LoadThemeMetrics.iSizes[hdr.usTypeNum-TMT_FIRSTSIZE] = *(int *)u.pb;
  625. break;
  626. case TMT_INT:
  627. _LoadThemeMetrics.iInts[hdr.usTypeNum-TMT_FIRSTINT] = *(int *)u.pb;
  628. break;
  629. case TMT_STRING:
  630. _LoadThemeMetrics.wsStrings[hdr.usTypeNum-TMT_FIRSTSTRING] = (WCHAR *)u.pb;
  631. break;
  632. }
  633. u.pb += hdr.dwDataLen; // skip to next entry
  634. }
  635. //---- compute packed size of theme metrics ----
  636. //---- the actual entry ----
  637. ac->iPackedSize = ENTRYHDR_SIZE + sizeof(THEMEMETRICS);
  638. //---- a "jump to parent" entry ----
  639. ac->iPackedSize += ENTRYHDR_SIZE + sizeof(int);
  640. //---- add strings used in sysmetrics ----
  641. for (i=0; i < TM_STRINGCOUNT; i++)
  642. {
  643. int len = _LoadThemeMetrics.wsStrings[i].GetLength();
  644. ac->iPackedSize += sizeof(WCHAR)*(1 + len);
  645. }
  646. return S_OK;
  647. }
  648. //---------------------------------------------------------------------------
  649. HRESULT CThemeLoader::PackThemeStructs()
  650. {
  651. HRESULT hr = PackMetrics();
  652. if (FAILED(hr))
  653. return hr;
  654. //---- IMAGEDATA and TEXTDATA packing go here ----
  655. return S_OK;
  656. }
  657. //---------------------------------------------------------------------------
  658. HRESULT CThemeLoader::PackAndLoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam,
  659. LPCWSTR pszSizeParam, HINSTANCE hInst)
  660. {
  661. WCHAR szColor[MAX_PATH];
  662. WCHAR szSize[MAX_PATH];
  663. HRESULT hr = PackThemeStructs();
  664. //---- if color not specifed, get default color ----
  665. if ((! pszColorParam) || (! *pszColorParam))
  666. {
  667. hr = GetResString(hInst, L"COLORNAMES", 0, szColor, ARRAYSIZE(szColor));
  668. if (FAILED(hr))
  669. goto exit;
  670. pszColorParam = szColor;
  671. }
  672. //---- if size not specifed, get default size ----
  673. if ((! pszSizeParam) || (! *pszSizeParam))
  674. {
  675. hr = GetResString(hInst, L"SIZENAMES", 0, szSize, ARRAYSIZE(szSize));
  676. if (FAILED(hr))
  677. goto exit;
  678. pszSizeParam = szSize;
  679. }
  680. hr = _LoadingThemeFile.CreateFile(MAX_SHAREDMEM_SIZE, TRUE);
  681. if (FAILED(hr))
  682. goto exit;
  683. //---- copy local theme data to live ----
  684. hr = CopyLocalThemeToLive(MAX_SHAREDMEM_SIZE, pszThemeName, pszColorParam, pszSizeParam);
  685. if (FAILED(hr))
  686. goto exit;
  687. exit:
  688. return hr;
  689. }
  690. //---------------------------------------------------------------------------
  691. HRESULT CThemeLoader::AddMissingParent(LPCWSTR pszAppName, LPCWSTR pszClassName,
  692. int iPartNum, int iStateNum)
  693. {
  694. //---- add missing parent section ----
  695. int iData = 0;
  696. int iStart = GetNextDataIndex();
  697. HRESULT hr = AddData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &iData, sizeof(iData));
  698. if (FAILED(hr))
  699. return hr;
  700. int iLen = GetNextDataIndex() - iStart;
  701. hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum,
  702. iStart, iLen);
  703. if (FAILED(hr))
  704. return hr;
  705. return S_OK;
  706. }
  707. //---------------------------------------------------------------------------
  708. HRESULT CThemeLoader::AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName,
  709. int iPartNum, int iStateNum, int iIndex, int iLen)
  710. {
  711. HRESULT hr;
  712. if (iPartNum) // ensure parent exists
  713. {
  714. if (! IndexExists(pszAppName, pszClassName, 0, 0))
  715. {
  716. hr = AddMissingParent(pszAppName, pszClassName, 0, 0);
  717. if (FAILED(hr))
  718. return hr;
  719. }
  720. }
  721. if (iStateNum) // ensure parent exists
  722. {
  723. if (! IndexExists(pszAppName, pszClassName, iPartNum, 0))
  724. {
  725. hr = AddMissingParent(pszAppName, pszClassName, iPartNum, 0);
  726. if (FAILED(hr))
  727. return hr;
  728. }
  729. }
  730. hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum, iIndex,
  731. iLen);
  732. if (FAILED(hr))
  733. return hr;
  734. return S_OK;
  735. }
  736. //---------------------------------------------------------------------------
  737. BOOL CThemeLoader::IndexExists(LPCWSTR pszAppName, LPCWSTR pszClassName,
  738. int iPartNum, int iStateNum)
  739. {
  740. //---- try to find existing entry ----
  741. int cnt = _LocalIndexes.GetSize();
  742. for (int i=0; i < cnt; i++)
  743. {
  744. LPCWSTR localAppName = _LocalIndexes[i].csAppName;
  745. if ((pszAppName) && (*pszAppName))
  746. {
  747. if ((! localAppName) || (! *localAppName))
  748. continue;
  749. if (AsciiStrCmpI(pszAppName, localAppName) != 0)
  750. continue;
  751. }
  752. else if ((localAppName) && (*localAppName))
  753. continue;
  754. if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0)
  755. break;
  756. }
  757. if (i == cnt) // not found
  758. return FALSE;
  759. //---- find matching child info ----
  760. APPCLASSLOCAL *acl = &_LocalIndexes[i];
  761. for (int c=0; c < acl->PartStateIndexes.m_nSize; c++)
  762. {
  763. if (acl->PartStateIndexes[c].iPartNum == iPartNum)
  764. {
  765. if (acl->PartStateIndexes[c].iStateNum == iStateNum)
  766. return TRUE;
  767. }
  768. }
  769. return FALSE;
  770. }
  771. //---------------------------------------------------------------------------
  772. HRESULT CThemeLoader::AddIndexInternal(LPCWSTR pszAppName, LPCWSTR pszClassName,
  773. int iPartNum, int iStateNum, int iIndex, int iLen)
  774. {
  775. //---- try to find existing entry ----
  776. int cnt = _LocalIndexes.GetSize();
  777. for (int i=0; i < cnt; i++)
  778. {
  779. LPCWSTR localAppName = _LocalIndexes[i].csAppName;
  780. if ((pszAppName) && (*pszAppName))
  781. {
  782. if ((! localAppName) || (! *localAppName))
  783. continue;
  784. if (AsciiStrCmpI(pszAppName, localAppName) != 0)
  785. continue;
  786. }
  787. else if ((localAppName) && (*localAppName))
  788. continue;
  789. if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0)
  790. break;
  791. }
  792. APPCLASSLOCAL *acl;
  793. if (i == cnt) // not found - create a new entry
  794. {
  795. APPCLASSLOCAL local;
  796. local.csAppName = pszAppName;
  797. local.csClassName = pszClassName;
  798. local.iMaxPartNum = 0;
  799. local.iPackedSize = 0;
  800. _LocalIndexes.Add(local);
  801. int last = _LocalIndexes.GetSize()-1;
  802. acl = &_LocalIndexes[last];
  803. }
  804. else // update existing entry with child info
  805. {
  806. acl = &_LocalIndexes[i];
  807. // child info should not be there already
  808. for (int c=0; c < acl->PartStateIndexes.m_nSize; c++)
  809. {
  810. if (acl->PartStateIndexes[c].iPartNum == iPartNum)
  811. {
  812. if (acl->PartStateIndexes[c].iStateNum == iStateNum)
  813. {
  814. return MakeError32(ERROR_ALREADY_EXISTS);
  815. }
  816. }
  817. }
  818. }
  819. //---- add the part ----
  820. if (iPartNum > acl->iMaxPartNum)
  821. acl->iMaxPartNum = iPartNum;
  822. PART_STATE_INDEX psi;
  823. psi.iPartNum = iPartNum;
  824. psi.iStateNum = iStateNum;
  825. psi.iIndex = iIndex;
  826. psi.iLen = iLen;
  827. acl->PartStateIndexes.Add(psi);
  828. return S_OK;
  829. }
  830. //---------------------------------------------------------------------------
  831. HRESULT CThemeLoader::AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen)
  832. {
  833. DWORD dwFullLen = ENTRYHDR_SIZE + dwLen;
  834. HRESULT hr;
  835. BYTE bFiller = ALIGN_FACTOR - 1;
  836. MIXEDPTRS u;
  837. u.pb = _pbLocalData + _iLocalLen;
  838. //---- add to local copy of theme data ----
  839. if ((PtrToUint(u.pb) / _dwPageSize != PtrToUint(u.pb + dwFullLen + bFiller) / _dwPageSize)
  840. || _iLocalLen == 0)
  841. {
  842. if (NULL == VirtualAlloc(_pbLocalData, _iLocalLen + 1 + dwFullLen + bFiller, MEM_COMMIT, PAGE_READWRITE))
  843. {
  844. return MakeError32(ERROR_NOT_ENOUGH_MEMORY);
  845. }
  846. }
  847. hr = EmitEntryHdr(u, sTypeNum, ePrimVal);
  848. if (FAILED(hr))
  849. goto exit;
  850. if (dwLen)
  851. {
  852. CopyMemory(u.pb, pData, dwLen);
  853. u.pb += dwLen;
  854. }
  855. //---- this may generate filler bytes ----
  856. bFiller = (BYTE)EndEntry(u);
  857. _iLocalLen += (dwFullLen + bFiller);
  858. exit:
  859. return hr;
  860. }
  861. //---------------------------------------------------------------------------
  862. int CThemeLoader::GetNextDataIndex()
  863. {
  864. return _iLocalLen;
  865. }
  866. //---------------------------------------------------------------------------
  867. void SetSysBool(THEMEMETRICS* ptm, int iBoolNum, int iSpiSetNum)
  868. {
  869. BOOL fVal = ptm->fBools[iBoolNum - TMT_FIRSTBOOL];
  870. BOOL fSet = ClassicSystemParametersInfo(iSpiSetNum, 0, IntToPtr(fVal), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  871. if (! fSet)
  872. {
  873. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo() call to set BOOL");
  874. }
  875. }
  876. //---------------------------------------------------------------------------
  877. void SetSystemMetrics_Worker(THEMEMETRICS* ptm)
  878. {
  879. #ifdef DEBUG
  880. if (LogOptionOn(LO_TMLOAD))
  881. {
  882. WCHAR szUserName[MAX_PATH];
  883. DWORD dwSize = ARRAYSIZE(szUserName);
  884. GetUserName(szUserName, &dwSize);
  885. Log(LOG_TMLOAD, L"SetSystemMetrics_Worker: User=%s, SM_REMOTESESSION=%d",
  886. szUserName, GetSystemMetrics(SM_REMOTESESSION));
  887. }
  888. #endif
  889. //---- apply nonclient metrics ----
  890. NONCLIENTMETRICS ncm = {sizeof(ncm)};
  891. BOOL fSet;
  892. //----- scale all sizes from 96-dpi to match current screen logical DPI ----
  893. ncm.iBorderWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE]);
  894. ncm.iCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE]);
  895. ncm.iCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE]);
  896. ncm.iSmCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE]);
  897. ncm.iSmCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE]);
  898. ncm.iMenuWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE]);
  899. ncm.iMenuHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE]);
  900. ncm.iScrollWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE]);
  901. ncm.iScrollHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE]);
  902. //---- transfer font info (stored internally at 96 dpi) ----
  903. ncm.lfCaptionFont = ptm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT];
  904. ncm.lfSmCaptionFont = ptm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT];
  905. ncm.lfMenuFont = ptm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT];
  906. ncm.lfStatusFont = ptm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT];
  907. ncm.lfMessageFont = ptm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT];
  908. //---- scale fonts (from 96 dpi to current screen dpi) ----
  909. ScaleFontForScreenDpi(&ncm.lfCaptionFont);
  910. ScaleFontForScreenDpi(&ncm.lfSmCaptionFont);
  911. ScaleFontForScreenDpi(&ncm.lfMenuFont);
  912. ScaleFontForScreenDpi(&ncm.lfStatusFont);
  913. ScaleFontForScreenDpi(&ncm.lfMessageFont);
  914. fSet = ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS,
  915. sizeof(NONCLIENTMETRICS),
  916. &ncm,
  917. SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  918. if (! fSet)
  919. {
  920. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS)");
  921. }
  922. //---- apply the remaining font ----
  923. LOGFONT lf = ptm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT];
  924. ScaleFontForScreenDpi(&lf);
  925. fSet = ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT,
  926. sizeof(LOGFONT),
  927. &lf,
  928. SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  929. if (! fSet)
  930. {
  931. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT)");
  932. }
  933. //---- apply the sys bools (one at a time, unfortunately) ----
  934. SetSysBool(ptm, TMT_FLATMENUS, SPI_SETFLATMENU);
  935. //---- apply system colors ----
  936. int iIndexes[TM_COLORCOUNT];
  937. for (int i=0; i < TM_COLORCOUNT; i++)
  938. {
  939. iIndexes[i] = i;
  940. }
  941. fSet = SetSysColors(TM_COLORCOUNT, iIndexes, ptm->crColors);
  942. if (! fSet)
  943. {
  944. Log(LOG_ALWAYS, L"Error returned from SetSysColors()");
  945. }
  946. HRESULT hr = PersistSystemColors(ptm); // write them to registry
  947. if (FAILED(hr))
  948. {
  949. Log(LOG_ALWAYS, L"failed to persist SysColors");
  950. }
  951. }
  952. //---------------------------------------------------------------------------
  953. STDAPI_(DWORD) SetSystemMetrics_WorkerThread(void* pv)
  954. {
  955. THEMEMETRICS_THREADINFO* ptm = (THEMEMETRICS_THREADINFO*)pv;
  956. ASSERT(ptm);
  957. BOOL fSuccess = TRUE;
  958. if (ptm->hUserToken)
  959. {
  960. fSuccess = ImpersonateLoggedOnUser(ptm->hUserToken);
  961. if (!fSuccess)
  962. {
  963. Log(LOG_ALWAYS, L"ImpersonateLoggedOnUser failed in SetSystemMetrics");
  964. }
  965. }
  966. if (fSuccess)
  967. {
  968. SetSystemMetrics_Worker(&ptm->tm);
  969. }
  970. if (ptm->hUserToken)
  971. {
  972. if (fSuccess)
  973. {
  974. RevertToSelf();
  975. }
  976. CloseHandle(ptm->hUserToken);
  977. }
  978. LocalFree(ptm);
  979. FreeLibraryAndExitThread(g_hInst, 0);
  980. }
  981. //---------------------------------------------------------------------------
  982. void SetSystemMetrics(THEMEMETRICS* ptm, BOOL fSyncLoad)
  983. {
  984. if (ptm != NULL)
  985. {
  986. BOOL fSuccess = FALSE;
  987. HMODULE hmod;
  988. if (!fSyncLoad) // ok to use a new thread
  989. {
  990. // add a dllref for the thread we are creating
  991. hmod = LoadLibrary(TEXT("uxtheme.dll"));
  992. if (hmod)
  993. {
  994. THEMEMETRICS_THREADINFO* ptmCopy = (THEMEMETRICS_THREADINFO*)LocalAlloc(LPTR, sizeof(THEMEMETRICS_THREADINFO));
  995. if (ptmCopy)
  996. {
  997. // fill in all of the thememetrics info for the thread we are going to create
  998. CopyMemory(ptmCopy, ptm, sizeof(THEMEMETRICS));
  999. HANDLE hToken = NULL;
  1000. // If the calling thread is impersonating, use the same token
  1001. // OpenThreadToken can fail if the thread is not impersonating
  1002. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, &hToken))
  1003. {
  1004. ptmCopy->hUserToken = hToken;
  1005. // we want to do this async since we end up calling xxxSendMessage for a TON of things which blocks this
  1006. // thread which can cause deadlocks
  1007. HANDLE hThread = CreateThread(NULL, 0, SetSystemMetrics_WorkerThread, ptmCopy, 0, NULL);
  1008. if (hThread)
  1009. {
  1010. CloseHandle(hThread);
  1011. fSuccess = TRUE;
  1012. }
  1013. }
  1014. else
  1015. {
  1016. Log(LOG_TMCHANGE, L"OpenThreadToken failed in SetSystemMetrics, last error=%d", GetLastError());
  1017. }
  1018. if (!fSuccess)
  1019. {
  1020. LocalFree(ptmCopy);
  1021. }
  1022. }
  1023. if (!fSuccess)
  1024. {
  1025. FreeLibrary(hmod);
  1026. }
  1027. }
  1028. }
  1029. if (!fSuccess)
  1030. {
  1031. // failed, fall back to calling synchronously
  1032. SetSystemMetrics_Worker(ptm);
  1033. }
  1034. }
  1035. }
  1036. //---------------------------------------------------------------------------
  1037. void SetFont(LOGFONT *plf, LPCWSTR lszFontName, int iPointSize)
  1038. {
  1039. memset(plf, 0, sizeof(*plf));
  1040. plf->lfWeight = FW_NORMAL;
  1041. plf->lfCharSet = DEFAULT_CHARSET;
  1042. plf->lfHeight = iPointSize;
  1043. StringCchCopyW(plf->lfFaceName, ARRAYSIZE(plf->lfFaceName), lszFontName);
  1044. }
  1045. //---------------------------------------------------------------------------
  1046. COLORREF DefaultColors[] =
  1047. {
  1048. RGB(212, 208, 200), // Scrollbar (0)
  1049. RGB(58, 110, 165), // Background (1)
  1050. RGB(10, 36, 106), // ActiveCaption (2)
  1051. RGB(128, 128, 128), // InactiveCaption (3)
  1052. RGB(212, 208, 200), // Menu (4)
  1053. RGB(255, 255, 255), // Window (5)
  1054. RGB(0, 0, 0), // WindowFrame (6)
  1055. RGB(0, 0, 0), // MenuText (7)
  1056. RGB(0, 0, 0), // WindowText (8)
  1057. RGB(255, 255, 255), // CaptionText (9)
  1058. RGB(212, 208, 200), // ActiveBorder (10)
  1059. RGB(212, 208, 200), // InactiveBorder (11)
  1060. RGB(128, 128, 128), // AppWorkSpace (12)
  1061. RGB(10, 36, 106), // Highlight (13)
  1062. RGB(255, 255, 255), // HighlightText (14)
  1063. RGB(212, 208, 200), // BtnFace (15)
  1064. RGB(128, 128, 128), // BtnShadow (16)
  1065. RGB(128, 128, 128), // GrayText (17)
  1066. RGB(0, 0, 0), // BtnText (18)
  1067. RGB(212, 208, 200), // InactiveCaptionText (19)
  1068. RGB(255, 255, 255), // BtnHighlight (20)
  1069. RGB(64, 64, 64), // DkShadow3d (21)
  1070. RGB(212, 208, 200), // Light3d (22)
  1071. RGB(0, 0, 0), // InfoText (23)
  1072. RGB(255, 255, 225), // InfoBk (24)
  1073. RGB(181, 181, 181), // ButtonAlternateFace (25)
  1074. RGB(0, 0, 128), // HotTracking (26)
  1075. RGB(166, 202, 240), // GradientActiveCaption (27)
  1076. RGB(192, 192, 192), // GradientInactiveCaption (28)
  1077. RGB(206, 211, 225), // MenuiHilight (29)
  1078. RGB(244, 244, 240), // MenuBar (30)
  1079. };
  1080. //---------------------------------------------------------------------------
  1081. HRESULT InitThemeMetrics(LOADTHEMEMETRICS *tm)
  1082. {
  1083. memset(tm, 0, sizeof(*tm)); // zero out in case we miss a property
  1084. //---- init fonts ----
  1085. SetFont(&tm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT], L"tahoma bold", POINTS_DPI96(8));
  1086. SetFont(&tm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1087. SetFont(&tm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1088. SetFont(&tm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1089. SetFont(&tm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1090. SetFont(&tm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1091. //---- init bools ----
  1092. tm->fBools[TMT_FLATMENUS - TMT_FIRSTBOOL] = FALSE;
  1093. //---- init sizes ----
  1094. tm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE] = 1;
  1095. tm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE] = 16;
  1096. tm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE] = 16;
  1097. tm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE] = 18;
  1098. tm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1099. tm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE] = 12;
  1100. tm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1101. tm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE] = 18;
  1102. tm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1103. //---- init strings ----
  1104. tm->iStringOffsets[TMT_CSSNAME - TMT_FIRSTSTRING] = 0;
  1105. tm->iStringOffsets[TMT_XMLNAME - TMT_FIRSTSTRING] = 0;
  1106. tm->wsStrings[TMT_CSSNAME - TMT_FIRSTSTRING] = L"";
  1107. tm->wsStrings[TMT_XMLNAME - TMT_FIRSTSTRING] = L"";
  1108. //---- init ints ----
  1109. tm->iInts[TMT_MINCOLORDEPTH - TMT_FIRSTINT] = 16;
  1110. //---- init colors ----
  1111. for (int i=0; i < TM_COLORCOUNT; i++)
  1112. tm->crColors[i] = DefaultColors[i];
  1113. return S_OK;
  1114. }
  1115. //---------------------------------------------------------------------------
  1116. HRESULT PersistSystemColors(THEMEMETRICS *tm)
  1117. {
  1118. HRESULT hr;
  1119. LONG lErrorCode;
  1120. HKEY hkcu;
  1121. CCurrentUser hKeyCurrentUser(KEY_SET_VALUE);
  1122. lErrorCode = RegOpenKeyEx(hKeyCurrentUser,
  1123. REGSTR_PATH_COLORS,
  1124. 0,
  1125. KEY_SET_VALUE,
  1126. &hkcu);
  1127. if (ERROR_SUCCESS == lErrorCode)
  1128. {
  1129. hr = S_OK;
  1130. //---- believe it or not, we have to manually write each color ----
  1131. //---- as a string to the registry to persist them ----
  1132. ASSERT(iSysColorSize == TM_COLORCOUNT); // should also match winuser.h entries
  1133. //---- are gradients turned on? ----
  1134. BOOL fGradientsEnabled = FALSE;
  1135. ClassicSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&fGradientsEnabled, 0);
  1136. //---- enough colors for a gradient? ----
  1137. HDC hdc = GetDC(NULL);
  1138. if (hdc)
  1139. {
  1140. if (GetDeviceCaps(hdc, BITSPIXEL) <= 8)
  1141. fGradientsEnabled = FALSE;
  1142. ReleaseDC(NULL, hdc);
  1143. }
  1144. for (int i=0; i < iSysColorSize; i++)
  1145. {
  1146. // If this is the Gradient Caption setting and the system does
  1147. // not currently show gradient captions then don't write them out
  1148. // to the theme file.
  1149. if ((i == COLOR_GRADIENTACTIVECAPTION) || (i == COLOR_GRADIENTINACTIVECAPTION))
  1150. {
  1151. if (! fGradientsEnabled)
  1152. continue;
  1153. }
  1154. //---- translate color into "r, g, b" value string ----
  1155. WCHAR buff[100];
  1156. COLORREF cr = tm->crColors[i];
  1157. StringCchPrintfW(buff, ARRAYSIZE(buff), L"%d %d %d", RED(cr), GREEN(cr), BLUE(cr));
  1158. //---- write color key/value to registry ----
  1159. lErrorCode = RegSetValueEx(hkcu,
  1160. pszSysColorNames[i],
  1161. 0,
  1162. REG_SZ,
  1163. reinterpret_cast<BYTE*>(buff),
  1164. (lstrlen(buff) + 1) * sizeof(WCHAR));
  1165. if (ERROR_SUCCESS != lErrorCode)
  1166. {
  1167. if (SUCCEEDED(hr))
  1168. {
  1169. hr = MakeError32(lErrorCode);
  1170. }
  1171. }
  1172. }
  1173. (LONG)RegCloseKey(hkcu);
  1174. }
  1175. else
  1176. {
  1177. hr = MakeError32(lErrorCode);
  1178. }
  1179. return hr;
  1180. }
  1181. //---------------------------------------------------------------------------
  1182. BOOL CThemeLoader::KeyDrawPropertyFound(int iStateDataOffset)
  1183. {
  1184. BOOL fFound = FALSE;
  1185. MIXEDPTRS u;
  1186. UNPACKED_ENTRYHDR hdr;
  1187. u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
  1188. while (*u.ps != TMT_JUMPTOPARENT)
  1189. {
  1190. if (CBorderFill::KeyProperty((*u.ps)))
  1191. {
  1192. fFound = TRUE;
  1193. break;
  1194. }
  1195. if (CImageFile::KeyProperty((*u.ps)))
  1196. {
  1197. fFound = TRUE;
  1198. break;
  1199. }
  1200. //---- skip to next entry ----
  1201. FillAndSkipHdr(u, &hdr);
  1202. u.pb += hdr.dwDataLen;
  1203. }
  1204. return fFound;
  1205. }
  1206. //---------------------------------------------------------------------------
  1207. BOOL CThemeLoader::KeyTextPropertyFound(int iStateDataOffset)
  1208. {
  1209. BOOL fFound = FALSE;
  1210. MIXEDPTRS u;
  1211. UNPACKED_ENTRYHDR hdr;
  1212. u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
  1213. while (*u.ps != TMT_JUMPTOPARENT)
  1214. {
  1215. if (CTextDraw::KeyProperty((*u.ps)))
  1216. {
  1217. fFound = TRUE;
  1218. break;
  1219. }
  1220. //---- skip to next entry ----
  1221. FillAndSkipHdr(u, &hdr);
  1222. u.pb += hdr.dwDataLen;
  1223. }
  1224. return fFound;
  1225. }
  1226. //---------------------------------------------------------------------------
  1227. HRESULT CThemeLoader::PackImageFileInfo(DIBINFO *pdi, CImageFile *pImageObj, MIXEDPTRS &u,
  1228. CRenderObj *pRender, int iPartId, int iStateId)
  1229. {
  1230. HRESULT hr = S_OK;
  1231. //---- write custom region data ----
  1232. int iMaxState;
  1233. if ((! iStateId) && (pImageObj->HasRegionImageFile(pdi, &iMaxState)))
  1234. {
  1235. //---- update object's _iRgnDataOffset field ----
  1236. pImageObj->SetRgnListOffset(pdi, THEME_OFFSET(u.pb));
  1237. //---- write the TMT_RGNLIST entry ----
  1238. hr = EmitEntryHdr(u, TMT_RGNLIST, TMT_RGNLIST);
  1239. if (FAILED(hr))
  1240. goto exit;
  1241. int cEntries = iMaxState + 1; // number of jump table entries
  1242. hr = AllocateThemeFileBytes(u.pb, 1 + cEntries * sizeof(int));
  1243. if (FAILED(hr))
  1244. goto exit;
  1245. *u.pb++ = static_cast<BYTE>(cEntries);
  1246. //---- write jump table now and update asap ----
  1247. int *piJumpTable = u.pi;
  1248. for (int i=0; i <= iMaxState; i++)
  1249. *u.pi++ = 0;
  1250. for (int iRgnState=0; iRgnState <= iMaxState; iRgnState++)
  1251. {
  1252. //---- build & pack custom region data for each state in this object's imagefile ----
  1253. CAutoArrayPtr<RGNDATA> pRgnData;
  1254. int iDataLen;
  1255. hr = pImageObj->BuildRgnData(pdi, pRender, iRgnState, &pRgnData, &iDataLen);
  1256. if (FAILED(hr))
  1257. goto exit;
  1258. if (iDataLen) // if we got a non-empty region
  1259. {
  1260. piJumpTable[iRgnState] = THEME_OFFSET(u.pb);
  1261. RGNDATAHDR rdHdr = {iPartId, iRgnState, 0};
  1262. //---- copy rgndata hdr ----
  1263. hr = EmitObject(u, TMT_RGNDATA, TMT_RGNDATA, &rdHdr, sizeof(rdHdr), pRgnData, iDataLen);
  1264. if (FAILED(hr))
  1265. goto exit;
  1266. }
  1267. }
  1268. EndEntry(u);
  1269. }
  1270. exit:
  1271. return hr;
  1272. }
  1273. //---------------------------------------------------------------------------
  1274. HRESULT CThemeLoader::PackDrawObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId,
  1275. int iStateId)
  1276. {
  1277. HRESULT hr = S_OK;
  1278. BGTYPE eBgType;
  1279. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_BGTYPE, (int *)&eBgType)))
  1280. eBgType = BT_BORDERFILL; // default value
  1281. DRAWOBJHDR hdr = {iPartId, iStateId};
  1282. if ((eBgType == BT_BORDERFILL) || (eBgType == BT_NONE))
  1283. {
  1284. CBorderFill bfobj;
  1285. hr = bfobj.PackProperties(pRender, (eBgType == BT_NONE), iPartId, iStateId);
  1286. if (FAILED(hr))
  1287. goto exit;
  1288. //---- copy "bfobj" to packed bytes ----
  1289. hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &bfobj, sizeof(bfobj));
  1290. if (FAILED(hr))
  1291. goto exit;
  1292. }
  1293. else // imagefile
  1294. {
  1295. CMaxImageFile maxif;
  1296. int iMultiCount;
  1297. hr = maxif.PackMaxProperties(pRender, iPartId, iStateId, &iMultiCount);
  1298. if (FAILED(hr))
  1299. goto exit;
  1300. //---- process all DIBINFO structs in the CImageFile obj ----
  1301. for (int i=0; ; i++)
  1302. {
  1303. DIBINFO *pdi = maxif.EnumImageFiles(i);
  1304. if (! pdi)
  1305. break;
  1306. hr = PackImageFileInfo(pdi, &maxif, u, pRender, iPartId, iStateId);
  1307. if (FAILED(hr))
  1308. goto exit;
  1309. }
  1310. //---- copy imagefile obj & multi DIB's to packed bytes ----
  1311. DWORD dwLen = sizeof(CImageFile) + sizeof(DIBINFO)*iMultiCount;
  1312. hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &maxif, dwLen);
  1313. if (FAILED(hr))
  1314. goto exit;
  1315. }
  1316. exit:
  1317. return hr;
  1318. }
  1319. //---------------------------------------------------------------------------
  1320. HRESULT CThemeLoader::PackTextObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId)
  1321. {
  1322. HRESULT hr;
  1323. DRAWOBJHDR hdr = {iPartId, iStateId};
  1324. CTextDraw ctobj;
  1325. hr = ctobj.PackProperties(pRender, iPartId, iStateId);
  1326. if (FAILED(hr))
  1327. goto exit;
  1328. hr = EmitObject(u, TMT_TEXTOBJ, TMT_TEXTOBJ, &hdr, sizeof(hdr), &ctobj, sizeof(ctobj));
  1329. if (FAILED(hr))
  1330. goto exit;
  1331. exit:
  1332. return hr;
  1333. }
  1334. //---------------------------------------------------------------------------
  1335. int CThemeLoader::GetPartOffset(CRenderObj *pRender, int iPartNum)
  1336. {
  1337. int iOffset;
  1338. int iPartCount;
  1339. MIXEDPTRS u;
  1340. //---- see if state table exists for this part ----
  1341. u.pb = pRender->_pbSectionData;
  1342. if (*u.ps != TMT_PARTJUMPTABLE)
  1343. {
  1344. iOffset = -1;
  1345. goto exit;
  1346. }
  1347. u.pb += ENTRYHDR_SIZE + sizeof(int); // skip over hdr + PackedObjOffset
  1348. iPartCount = *u.pb++;
  1349. if (iPartNum >= iPartCount) // iPartCount is MaxPart+1
  1350. {
  1351. iOffset = -1;
  1352. goto exit;
  1353. }
  1354. iOffset = u.pi[iPartNum];
  1355. exit:
  1356. return iOffset;
  1357. }
  1358. //---------------------------------------------------------------------------
  1359. HRESULT CThemeLoader::PackDrawObjects(MIXEDPTRS &uOut, CRenderObj *pRender,
  1360. int iMaxPart, BOOL fGlobals)
  1361. {
  1362. HRESULT hr = S_OK;
  1363. MIXEDPTRS u;
  1364. //---- build a draw obj for each part ----
  1365. for (int iPart=0; iPart <= iMaxPart; iPart++)
  1366. {
  1367. int iPartOff = GetPartOffset(pRender, iPart);
  1368. if (iPartOff == -1)
  1369. continue;
  1370. u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
  1371. if (*u.ps == TMT_STATEJUMPTABLE)
  1372. {
  1373. u.pb += ENTRYHDR_SIZE;
  1374. int iMaxState = (*u.pb++) - 1;
  1375. int *piStateJumpTable = u.pi;
  1376. //---- build a draw obj for each needed state ----
  1377. for (int iState=0; iState <= iMaxState; iState++)
  1378. {
  1379. int iStateDataOffset = piStateJumpTable[iState];
  1380. if (iStateDataOffset == -1)
  1381. continue;
  1382. if ((fGlobals) || (KeyDrawPropertyFound(iStateDataOffset)))
  1383. {
  1384. hr = PackDrawObject(uOut, pRender, iPart, iState);
  1385. if (FAILED(hr))
  1386. goto exit;
  1387. if (fGlobals) // just needed to force (part=0, state=0)
  1388. fGlobals = FALSE;
  1389. }
  1390. }
  1391. }
  1392. else // no state jump table
  1393. {
  1394. if ((fGlobals) || (KeyDrawPropertyFound(THEME_OFFSET(u.pb))))
  1395. {
  1396. hr = PackDrawObject(uOut, pRender, iPart, 0);
  1397. if (FAILED(hr))
  1398. goto exit;
  1399. }
  1400. }
  1401. }
  1402. exit:
  1403. return hr;
  1404. }
  1405. //---------------------------------------------------------------------------
  1406. HRESULT CThemeLoader::PackTextObjects(MIXEDPTRS &uOut, CRenderObj *pRender,
  1407. int iMaxPart, BOOL fGlobals)
  1408. {
  1409. HRESULT hr = S_OK;
  1410. MIXEDPTRS u;
  1411. //---- build a text obj for each part ----
  1412. for (int iPart=0; iPart <= iMaxPart; iPart++)
  1413. {
  1414. int iPartOff = GetPartOffset(pRender, iPart);
  1415. if (iPartOff == -1)
  1416. continue;
  1417. u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
  1418. if (*u.ps == TMT_STATEJUMPTABLE)
  1419. {
  1420. u.pb += ENTRYHDR_SIZE;
  1421. int iMaxState = (*u.pb++) - 1;
  1422. int *piStateJumpTable = u.pi;
  1423. //---- build a text obj for each needed state ----
  1424. for (int iState=0; iState <= iMaxState; iState++)
  1425. {
  1426. int iStateDataOffset = piStateJumpTable[iState];
  1427. if (iStateDataOffset == -1)
  1428. continue;
  1429. if ((fGlobals) || (KeyTextPropertyFound(iStateDataOffset)))
  1430. {
  1431. hr = PackTextObject(uOut, pRender, iPart, iState);
  1432. if (FAILED(hr))
  1433. goto exit;
  1434. if (fGlobals) // just needed to force (part=0, state=0)
  1435. fGlobals = FALSE;
  1436. }
  1437. }
  1438. }
  1439. else // no state jump table
  1440. {
  1441. if ((fGlobals) || (KeyTextPropertyFound(THEME_OFFSET(u.pb))))
  1442. {
  1443. hr = PackTextObject(uOut, pRender, iPart, 0);
  1444. if (FAILED(hr))
  1445. goto exit;
  1446. }
  1447. }
  1448. }
  1449. exit:
  1450. return hr;
  1451. }
  1452. //---------------------------------------------------------------------------
  1453. HRESULT CThemeLoader::EmitEntryHdr(MIXEDPTRS &u, SHORT propnum, BYTE privnum)
  1454. {
  1455. HRESULT hr = S_OK;
  1456. if (_iEntryHdrLevel == MAX_ENTRY_NESTING)
  1457. {
  1458. Log(LOG_ERROR, L"Maximum entry nesting exceeded");
  1459. hr = E_FAIL;
  1460. goto exit;
  1461. }
  1462. if (_LoadingThemeFile._pbThemeData != NULL)
  1463. {
  1464. hr = AllocateThemeFileBytes(u.pb, ENTRYHDR_SIZE);
  1465. if (FAILED(hr))
  1466. goto exit;
  1467. }
  1468. //---- bump up the nesting level of entries ----
  1469. _iEntryHdrLevel++;
  1470. *u.ps++ = propnum;
  1471. *u.pb++ = privnum;
  1472. _pbEntryHdrs[_iEntryHdrLevel] = u.pb; // used to update next 2 fields in EndEntry()
  1473. *u.pb++ = 0; // filler to align end of data to 4/8 bytes
  1474. *u.pi++ = 0; // length
  1475. exit:
  1476. return hr;
  1477. }
  1478. //---------------------------------------------------------------------------
  1479. int CThemeLoader::EndEntry(MIXEDPTRS &u)
  1480. {
  1481. MIXEDPTRS uHdr;
  1482. uHdr.pb = _pbEntryHdrs[_iEntryHdrLevel];
  1483. //---- calcuate actual length of date emitted ----
  1484. int iActualLen = (int)(u.pb - (uHdr.pb + sizeof(BYTE) + sizeof(int)));
  1485. //---- calculate filler to be aligned ----
  1486. int iAlignLen = ((iActualLen + ALIGN_FACTOR - 1)/ALIGN_FACTOR) * ALIGN_FACTOR;
  1487. BYTE bFiller = (BYTE)(iAlignLen - iActualLen);
  1488. if (_LoadingThemeFile._pbThemeData != NULL)
  1489. {
  1490. HRESULT hr = AllocateThemeFileBytes(u.pb, bFiller);
  1491. if (FAILED(hr))
  1492. return -1;
  1493. }
  1494. //---- emit filler bytes to be correctly aligned ----
  1495. for (int i=0; i < bFiller; i++)
  1496. *u.pb++ = 0 ;
  1497. //---- update the entry Hdr ----
  1498. *uHdr.pb++ = bFiller;
  1499. *uHdr.pi++ = iAlignLen;
  1500. //---- decrement the nesting level of entries ----
  1501. _iEntryHdrLevel--;
  1502. return bFiller;
  1503. }
  1504. //---------------------------------------------------------------------------