Source code of Windows XP (NT5)
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.

1850 lines
55 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);
  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. memcpy(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. memcpy(u.pb, (BYTE*) pHdr, dwHdrLen);
  202. u.pb += dwHdrLen;
  203. memcpy(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 pSrc, DWORD dwLen, int *piOffSet)
  210. {
  211. HRESULT hr = AllocateThemeFileBytes(u.pb, (dwLen + 1) * sizeof(WCHAR));
  212. if (FAILED(hr))
  213. return hr;
  214. lstrcpy(u.px, pSrc);
  215. if (piOffSet)
  216. {
  217. *piOffSet = THEME_OFFSET(u.pb);
  218. }
  219. u.px += dwLen + 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. memcpy(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature);
  412. hdr->dwVersion = THEMEDATA_VERSION;
  413. hdr->dwFlags = 0; // not yet ready to be accessed
  414. hdr->iDllNameOffset = 0; // will be updated
  415. hdr->iColorParamOffset = 0; // will be updated
  416. hdr->iSizeParamOffset = 0; // will be updated
  417. hdr->dwLangID = (DWORD) GetUserDefaultUILanguage();
  418. hdr->iLoadId = 0; // was iLoadCounter
  419. hdr->iGlobalsOffset = 0; // will be updated
  420. hdr->iGlobalsTextObjOffset = 0; // will be updated
  421. hdr->iGlobalsDrawObjOffset = 0; // will be updated
  422. hdr->dwCheckSum = 0; // will be updated
  423. // Store the time stamp of the .msstyles file in the live file, this will be written to the cache file
  424. // for later comparison (Whistler:190202).
  425. ::ZeroMemory(&hdr->ftModifTimeStamp, sizeof &hdr->ftModifTimeStamp);
  426. HANDLE hFile = ::CreateFile(pszThemeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  427. FILE_ATTRIBUTE_NORMAL, NULL);
  428. if (hFile != INVALID_HANDLE_VALUE)
  429. {
  430. // There's nothing we can do if GetFileTime() fails
  431. ::GetFileTime(hFile, NULL, NULL, &hdr->ftModifTimeStamp);
  432. ::CloseHandle(hFile);
  433. }
  434. //---- build string section ----
  435. hdr->iStringsOffset = THEME_OFFSET(u.pb);
  436. DWORD *pdwFirstString = u.pdw;
  437. int len;
  438. //---- add header strings ----
  439. len = lstrlen(pszThemeName);
  440. if (len)
  441. {
  442. hr = EmitString(u, pszThemeName, len, &hdr->iDllNameOffset);
  443. if (FAILED(hr))
  444. goto exit;
  445. }
  446. len = lstrlen(pszColorParam);
  447. if (len)
  448. {
  449. hr = EmitString(u, pszColorParam, len, &hdr->iColorParamOffset);
  450. if (FAILED(hr))
  451. goto exit;
  452. }
  453. len = lstrlen(pszSizeParam);
  454. if (len)
  455. {
  456. hr = EmitString(u, pszSizeParam, len, &hdr->iSizeParamOffset);
  457. if (FAILED(hr))
  458. goto exit;
  459. }
  460. //---- add strings from class index ----
  461. for (i=0; i < iIndexCount; i++)
  462. {
  463. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  464. int len = ac->csAppName.GetLength();
  465. if (len)
  466. {
  467. hr = EmitString(u, ac->csAppName, len, (int*) &ac->LiveIndex.dwAppNameIndex);
  468. if (FAILED(hr))
  469. goto exit;
  470. }
  471. else
  472. ac->LiveIndex.dwAppNameIndex = 0;
  473. len = ac->csClassName.GetLength();
  474. if (len)
  475. {
  476. hr = EmitString(u, ac->csClassName, len, (int*) &ac->LiveIndex.dwClassNameIndex);
  477. if (FAILED(hr))
  478. goto exit;
  479. }
  480. else
  481. ac->LiveIndex.dwClassNameIndex = 0;
  482. }
  483. //---- copy strings from LOADTHEMEMETRICS -----
  484. for (i=0; i < TM_STRINGCOUNT; i++)
  485. {
  486. CWideString *ws = &_LoadThemeMetrics.wsStrings[i];
  487. int len = ws->GetLength();
  488. if (len)
  489. {
  490. hr = EmitString(u, *ws, len, &_LoadThemeMetrics.iStringOffsets[i]);
  491. if (FAILED(hr))
  492. goto exit;
  493. }
  494. else
  495. _LoadThemeMetrics.iStringOffsets[i] = 0;
  496. }
  497. int iStringLength = int(u.pb - ((BYTE *)pdwFirstString));
  498. hdr->iStringsLength = iStringLength;
  499. //---- write index header ----
  500. hdr->iSectionIndexOffset = THEME_OFFSET(u.pb);
  501. hdr->iSectionIndexLength = iIndexCount * sizeof(APPCLASSLIVE);
  502. APPCLASSLIVE *acl = (APPCLASSLIVE *)u.pb; // will write these in parallel with theme data
  503. hr = AllocateThemeFileBytes(u.pb, hdr->iSectionIndexLength);
  504. if (FAILED(hr))
  505. goto exit;
  506. u.pb += hdr->iSectionIndexLength;
  507. //---- write index AND theme data in parallel ----
  508. //---- first pass thru, copy [globals] and all [app::xxx] sections ----
  509. for (i=0; i < iIndexCount; i++) // for each parent section
  510. {
  511. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  512. if ((i) && (! ac->LiveIndex.dwAppNameIndex)) // not an [app::] section
  513. continue;
  514. acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex;
  515. acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
  516. acl->iIndex = THEME_OFFSET(u.pb);
  517. if (AsciiStrCmpI(ac->csClassName, L"globals")== 0) // globals section
  518. _iGlobalsOffset = acl->iIndex;
  519. hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex);
  520. if (FAILED(hr))
  521. goto exit;
  522. acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex;
  523. acl++;
  524. }
  525. //---- second pass thru, copy all non-[app::xxx] sections (except [globals]) ----
  526. for (i=0; i < iIndexCount; i++) // for each parent section
  527. {
  528. APPCLASSLOCAL *ac = &_LocalIndexes[i];
  529. if ((! i) || (ac->LiveIndex.dwAppNameIndex)) // don't process [app::] sections
  530. continue;
  531. acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex;
  532. acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
  533. acl->iIndex = THEME_OFFSET(u.pb);
  534. if (AsciiStrCmpI(ac->csClassName, L"sysmetrics")== 0) // SysMetrics section
  535. {
  536. _iSysMetricsOffset = acl->iIndex;
  537. hr = EmitEntryHdr(u, TMT_THEMEMETRICS, TMT_THEMEMETRICS);
  538. if (FAILED(hr))
  539. goto exit;
  540. DWORD len = sizeof(THEMEMETRICS);
  541. hr = EmitAndCopyBlock(u, (BYTE*) (THEMEMETRICS*) &_LoadThemeMetrics, len);
  542. EndEntry(u);
  543. //---- add a "jump to parent" to be consistent (not used) ----
  544. hr = EmitEntryHdr(u, TMT_JUMPTOPARENT, TMT_JUMPTOPARENT);
  545. if (FAILED(hr))
  546. goto exit;
  547. hr = AllocateThemeFileBytes(u.pb, sizeof(int));
  548. if (FAILED(hr))
  549. goto exit;
  550. *u.pi++ = -1;
  551. EndEntry(u);
  552. }
  553. else // regular section
  554. {
  555. hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex);
  556. if (FAILED(hr))
  557. goto exit;
  558. }
  559. acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex;
  560. acl++;
  561. }
  562. hr = EmitAndCopyBlock(u, (BYTE*) kszEndCacheFileSignature, kcbEndSignature);
  563. if (FAILED(hr))
  564. goto exit;
  565. //---- ensure we got the calc size right ----
  566. DWORD dwActualLen;
  567. dwActualLen = THEME_OFFSET(u.pb);
  568. if (hdr->dwTotalLength != dwActualLen)
  569. {
  570. //---- make this growable so we really have enough room ----
  571. //Log(LOG_TMCHANGE, L"ThemeLoader - calculated len=%d, actual len=%d",
  572. // hdr->dwTotalLength, dwActualLen);
  573. hdr->dwTotalLength = dwActualLen;
  574. }
  575. Log(LOG_TMCHANGE, L"ThemeLoader - theme size: %d", dwActualLen);
  576. //----- update header fields ----
  577. hdr->dwFlags |= SECTION_READY;
  578. hdr->iGlobalsOffset = _iGlobalsOffset;
  579. hdr->iSysMetricsOffset = _iSysMetricsOffset;
  580. hdr->iGlobalsTextObjOffset = _iGlobalsTextObj;
  581. hdr->iGlobalsDrawObjOffset = _iGlobalsDrawObj;
  582. #ifdef NEVER
  583. hdr->dwCheckSum = _LoadingThemeFile.DataCheckSum();
  584. #else
  585. hdr->dwCheckSum = 0;
  586. #endif // NEVER
  587. exit:
  588. return hr;
  589. }
  590. //---------------------------------------------------------------------------
  591. HRESULT CThemeLoader::PackMetrics()
  592. {
  593. //---- find the optional [SysMetrics] section ----
  594. int iIndexCount = _LocalIndexes.GetSize();
  595. APPCLASSLOCAL *ac = NULL;
  596. for (int i=0; i < iIndexCount; i++)
  597. {
  598. ac = &_LocalIndexes[i];
  599. if (AsciiStrCmpI(ac->csClassName, L"SysMetrics")==0)
  600. break;
  601. }
  602. if (i == iIndexCount) // not found
  603. return S_OK;
  604. //---- walk thru the properties & put into _LoadThemeMetrics ----
  605. if (! ac->PartStateIndexes.GetSize()) // no data
  606. return S_OK;
  607. MIXEDPTRS u;
  608. //---- parts & states not allowed so just use entry "0" ----
  609. u.pb = _pbLocalData + ac->PartStateIndexes[0].iIndex;
  610. UCHAR *lastpb = u.pb + ac->PartStateIndexes[0].iLen;
  611. while ((u.pb < lastpb) && (*u.pw != TMT_JUMPTOPARENT))
  612. {
  613. UNPACKED_ENTRYHDR hdr;
  614. FillAndSkipHdr(u, &hdr);
  615. switch (hdr.ePrimVal)
  616. {
  617. case TMT_FONT:
  618. _LoadThemeMetrics.lfFonts[hdr.usTypeNum-TMT_FIRSTFONT] = *(LOGFONT *)u.pb;
  619. break;
  620. case TMT_COLOR:
  621. _LoadThemeMetrics.crColors[hdr.usTypeNum-TMT_FIRSTCOLOR] = *(COLORREF *)u.pb;
  622. break;
  623. case TMT_BOOL:
  624. _LoadThemeMetrics.fBools[hdr.usTypeNum-TMT_FIRSTBOOL] = (BOOL)*u.pb;
  625. break;
  626. case TMT_SIZE:
  627. _LoadThemeMetrics.iSizes[hdr.usTypeNum-TMT_FIRSTSIZE] = *(int *)u.pb;
  628. break;
  629. case TMT_INT:
  630. _LoadThemeMetrics.iInts[hdr.usTypeNum-TMT_FIRSTINT] = *(int *)u.pb;
  631. break;
  632. case TMT_STRING:
  633. _LoadThemeMetrics.wsStrings[hdr.usTypeNum-TMT_FIRSTSTRING] = (WCHAR *)u.pb;
  634. break;
  635. }
  636. u.pb += hdr.dwDataLen; // skip to next entry
  637. }
  638. //---- compute packed size of theme metrics ----
  639. //---- the actual entry ----
  640. ac->iPackedSize = ENTRYHDR_SIZE + sizeof(THEMEMETRICS);
  641. //---- a "jump to parent" entry ----
  642. ac->iPackedSize += ENTRYHDR_SIZE + sizeof(int);
  643. //---- add strings used in sysmetrics ----
  644. for (i=0; i < TM_STRINGCOUNT; i++)
  645. {
  646. int len = _LoadThemeMetrics.wsStrings[i].GetLength();
  647. ac->iPackedSize += sizeof(WCHAR)*(1 + len);
  648. }
  649. return S_OK;
  650. }
  651. //---------------------------------------------------------------------------
  652. HRESULT CThemeLoader::PackThemeStructs()
  653. {
  654. HRESULT hr = PackMetrics();
  655. if (FAILED(hr))
  656. return hr;
  657. //---- IMAGEDATA and TEXTDATA packing go here ----
  658. return S_OK;
  659. }
  660. //---------------------------------------------------------------------------
  661. HRESULT CThemeLoader::PackAndLoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam,
  662. LPCWSTR pszSizeParam, HINSTANCE hInst)
  663. {
  664. WCHAR szColor[MAX_PATH];
  665. WCHAR szSize[MAX_PATH];
  666. HRESULT hr = PackThemeStructs();
  667. //---- if color not specifed, get default color ----
  668. if ((! pszColorParam) || (! *pszColorParam))
  669. {
  670. hr = GetResString(hInst, L"COLORNAMES", 0, szColor, ARRAYSIZE(szColor));
  671. if (FAILED(hr))
  672. goto exit;
  673. pszColorParam = szColor;
  674. }
  675. //---- if size not specifed, get default size ----
  676. if ((! pszSizeParam) || (! *pszSizeParam))
  677. {
  678. hr = GetResString(hInst, L"SIZENAMES", 0, szSize, ARRAYSIZE(szSize));
  679. if (FAILED(hr))
  680. goto exit;
  681. pszSizeParam = szSize;
  682. }
  683. hr = _LoadingThemeFile.CreateFile(MAX_SHAREDMEM_SIZE, TRUE);
  684. if (FAILED(hr))
  685. goto exit;
  686. //---- copy local theme data to live ----
  687. hr = CopyLocalThemeToLive(MAX_SHAREDMEM_SIZE, pszThemeName, pszColorParam, pszSizeParam);
  688. if (FAILED(hr))
  689. goto exit;
  690. exit:
  691. return hr;
  692. }
  693. //---------------------------------------------------------------------------
  694. BOOL CThemeLoader::GetThemeName(LPTSTR NameBuff, int BuffSize)
  695. {
  696. Log(LOG_TM, L"GetThemeName()");
  697. int len = _wsThemeFileName.GetLength();
  698. if (BuffSize < len)
  699. return FALSE;
  700. lstrcpy(NameBuff, _wsThemeFileName);
  701. return TRUE;
  702. }
  703. //---------------------------------------------------------------------------
  704. HRESULT CThemeLoader::AddMissingParent(LPCWSTR pszAppName, LPCWSTR pszClassName,
  705. int iPartNum, int iStateNum)
  706. {
  707. //---- add missing parent section ----
  708. int iData = 0;
  709. int iStart = GetNextDataIndex();
  710. HRESULT hr = AddData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &iData, sizeof(iData));
  711. if (FAILED(hr))
  712. return hr;
  713. int iLen = GetNextDataIndex() - iStart;
  714. hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum,
  715. iStart, iLen);
  716. if (FAILED(hr))
  717. return hr;
  718. return S_OK;
  719. }
  720. //---------------------------------------------------------------------------
  721. HRESULT CThemeLoader::AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName,
  722. int iPartNum, int iStateNum, int iIndex, int iLen)
  723. {
  724. HRESULT hr;
  725. if (iPartNum) // ensure parent exists
  726. {
  727. if (! IndexExists(pszAppName, pszClassName, 0, 0))
  728. {
  729. hr = AddMissingParent(pszAppName, pszClassName, 0, 0);
  730. if (FAILED(hr))
  731. return hr;
  732. }
  733. }
  734. if (iStateNum) // ensure parent exists
  735. {
  736. if (! IndexExists(pszAppName, pszClassName, iPartNum, 0))
  737. {
  738. hr = AddMissingParent(pszAppName, pszClassName, iPartNum, 0);
  739. if (FAILED(hr))
  740. return hr;
  741. }
  742. }
  743. hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum, iIndex,
  744. iLen);
  745. if (FAILED(hr))
  746. return hr;
  747. return S_OK;
  748. }
  749. //---------------------------------------------------------------------------
  750. BOOL CThemeLoader::IndexExists(LPCWSTR pszAppName, LPCWSTR pszClassName,
  751. int iPartNum, int iStateNum)
  752. {
  753. //---- try to find existing entry ----
  754. int cnt = _LocalIndexes.GetSize();
  755. for (int i=0; i < cnt; i++)
  756. {
  757. LPCWSTR localAppName = _LocalIndexes[i].csAppName;
  758. if ((pszAppName) && (*pszAppName))
  759. {
  760. if ((! localAppName) || (! *localAppName))
  761. continue;
  762. if (AsciiStrCmpI(pszAppName, localAppName) != 0)
  763. continue;
  764. }
  765. else if ((localAppName) && (*localAppName))
  766. continue;
  767. if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0)
  768. break;
  769. }
  770. if (i == cnt) // not found
  771. return FALSE;
  772. //---- find matching child info ----
  773. APPCLASSLOCAL *acl = &_LocalIndexes[i];
  774. for (int c=0; c < acl->PartStateIndexes.m_nSize; c++)
  775. {
  776. if (acl->PartStateIndexes[c].iPartNum == iPartNum)
  777. {
  778. if (acl->PartStateIndexes[c].iStateNum == iStateNum)
  779. return TRUE;
  780. }
  781. }
  782. return FALSE;
  783. }
  784. //---------------------------------------------------------------------------
  785. HRESULT CThemeLoader::AddIndexInternal(LPCWSTR pszAppName, LPCWSTR pszClassName,
  786. int iPartNum, int iStateNum, int iIndex, int iLen)
  787. {
  788. //---- try to find existing entry ----
  789. int cnt = _LocalIndexes.GetSize();
  790. for (int i=0; i < cnt; i++)
  791. {
  792. LPCWSTR localAppName = _LocalIndexes[i].csAppName;
  793. if ((pszAppName) && (*pszAppName))
  794. {
  795. if ((! localAppName) || (! *localAppName))
  796. continue;
  797. if (AsciiStrCmpI(pszAppName, localAppName) != 0)
  798. continue;
  799. }
  800. else if ((localAppName) && (*localAppName))
  801. continue;
  802. if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0)
  803. break;
  804. }
  805. APPCLASSLOCAL *acl;
  806. if (i == cnt) // not found - create a new entry
  807. {
  808. APPCLASSLOCAL local;
  809. local.csAppName = pszAppName;
  810. local.csClassName = pszClassName;
  811. local.iMaxPartNum = 0;
  812. local.iPackedSize = 0;
  813. _LocalIndexes.Add(local);
  814. int last = _LocalIndexes.GetSize()-1;
  815. acl = &_LocalIndexes[last];
  816. }
  817. else // update existing entry with child info
  818. {
  819. acl = &_LocalIndexes[i];
  820. // child info should not be there already
  821. for (int c=0; c < acl->PartStateIndexes.m_nSize; c++)
  822. {
  823. if (acl->PartStateIndexes[c].iPartNum == iPartNum)
  824. {
  825. if (acl->PartStateIndexes[c].iStateNum == iStateNum)
  826. {
  827. return MakeError32(ERROR_ALREADY_EXISTS);
  828. }
  829. }
  830. }
  831. }
  832. //---- add the part ----
  833. if (iPartNum > acl->iMaxPartNum)
  834. acl->iMaxPartNum = iPartNum;
  835. PART_STATE_INDEX psi;
  836. psi.iPartNum = iPartNum;
  837. psi.iStateNum = iStateNum;
  838. psi.iIndex = iIndex;
  839. psi.iLen = iLen;
  840. acl->PartStateIndexes.Add(psi);
  841. return S_OK;
  842. }
  843. //---------------------------------------------------------------------------
  844. HRESULT CThemeLoader::AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen)
  845. {
  846. DWORD dwFullLen = ENTRYHDR_SIZE + dwLen;
  847. HRESULT hr;
  848. BYTE bFiller = ALIGN_FACTOR - 1;
  849. MIXEDPTRS u;
  850. u.pb = _pbLocalData + _iLocalLen;
  851. //---- add to local copy of theme data ----
  852. if ((PtrToUint(u.pb) / _dwPageSize != PtrToUint(u.pb + dwFullLen + bFiller) / _dwPageSize)
  853. || _iLocalLen == 0)
  854. {
  855. if (NULL == VirtualAlloc(_pbLocalData, _iLocalLen + 1 + dwFullLen + bFiller, MEM_COMMIT, PAGE_READWRITE))
  856. {
  857. return MakeError32(ERROR_NOT_ENOUGH_MEMORY);
  858. }
  859. }
  860. hr = EmitEntryHdr(u, sTypeNum, ePrimVal);
  861. if (FAILED(hr))
  862. goto exit;
  863. if (dwLen)
  864. {
  865. memcpy(u.pb, pData, dwLen);
  866. u.pb += dwLen;
  867. }
  868. //---- this may generate filler bytes ----
  869. bFiller = (BYTE)EndEntry(u);
  870. _iLocalLen += (dwFullLen + bFiller);
  871. exit:
  872. return hr;
  873. }
  874. //---------------------------------------------------------------------------
  875. int CThemeLoader::GetNextDataIndex()
  876. {
  877. return _iLocalLen;
  878. }
  879. //---------------------------------------------------------------------------
  880. void SetSysBool(THEMEMETRICS* ptm, int iBoolNum, int iSpiSetNum)
  881. {
  882. BOOL fVal = ptm->fBools[iBoolNum - TMT_FIRSTBOOL];
  883. BOOL fSet = ClassicSystemParametersInfo(iSpiSetNum, 0, IntToPtr(fVal), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  884. if (! fSet)
  885. {
  886. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo() call to set BOOL");
  887. }
  888. }
  889. //---------------------------------------------------------------------------
  890. void SetSystemMetrics_Worker(THEMEMETRICS* ptm)
  891. {
  892. #ifdef DEBUG
  893. if (LogOptionOn(LO_TMLOAD))
  894. {
  895. WCHAR szUserName[MAX_PATH];
  896. DWORD dwSize = ARRAYSIZE(szUserName);
  897. GetUserName(szUserName, &dwSize);
  898. Log(LOG_TMLOAD, L"SetSystemMetrics_Worker: User=%s, SM_REMOTESESSION=%d",
  899. szUserName, GetSystemMetrics(SM_REMOTESESSION));
  900. }
  901. #endif
  902. //---- apply nonclient metrics ----
  903. NONCLIENTMETRICS ncm = {sizeof(ncm)};
  904. BOOL fSet;
  905. //----- scale all sizes from 96-dpi to match current screen logical DPI ----
  906. ncm.iBorderWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE]);
  907. ncm.iCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE]);
  908. ncm.iCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE]);
  909. ncm.iSmCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE]);
  910. ncm.iSmCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE]);
  911. ncm.iMenuWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE]);
  912. ncm.iMenuHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE]);
  913. ncm.iScrollWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE]);
  914. ncm.iScrollHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE]);
  915. //---- transfer font info (stored internally at 96 dpi) ----
  916. ncm.lfCaptionFont = ptm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT];
  917. ncm.lfSmCaptionFont = ptm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT];
  918. ncm.lfMenuFont = ptm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT];
  919. ncm.lfStatusFont = ptm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT];
  920. ncm.lfMessageFont = ptm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT];
  921. //---- scale fonts (from 96 dpi to current screen dpi) ----
  922. ScaleFontForScreenDpi(&ncm.lfCaptionFont);
  923. ScaleFontForScreenDpi(&ncm.lfSmCaptionFont);
  924. ScaleFontForScreenDpi(&ncm.lfMenuFont);
  925. ScaleFontForScreenDpi(&ncm.lfStatusFont);
  926. ScaleFontForScreenDpi(&ncm.lfMessageFont);
  927. fSet = ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS,
  928. sizeof(NONCLIENTMETRICS),
  929. &ncm,
  930. SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  931. if (! fSet)
  932. {
  933. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS)");
  934. }
  935. //---- apply the remaining font ----
  936. LOGFONT lf = ptm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT];
  937. ScaleFontForScreenDpi(&lf);
  938. fSet = ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT,
  939. sizeof(LOGFONT),
  940. &lf,
  941. SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  942. if (! fSet)
  943. {
  944. Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT)");
  945. }
  946. //---- apply the sys bools (one at a time, unfortunately) ----
  947. SetSysBool(ptm, TMT_FLATMENUS, SPI_SETFLATMENU);
  948. //---- apply system colors ----
  949. int iIndexes[TM_COLORCOUNT];
  950. for (int i=0; i < TM_COLORCOUNT; i++)
  951. {
  952. iIndexes[i] = i;
  953. }
  954. fSet = SetSysColors(TM_COLORCOUNT, iIndexes, ptm->crColors);
  955. if (! fSet)
  956. {
  957. Log(LOG_ALWAYS, L"Error returned from SetSysColors()");
  958. }
  959. HRESULT hr = PersistSystemColors(ptm); // write them to registry
  960. if (FAILED(hr))
  961. {
  962. Log(LOG_ALWAYS, L"failed to persist SysColors");
  963. }
  964. }
  965. //---------------------------------------------------------------------------
  966. STDAPI_(DWORD) SetSystemMetrics_WorkerThread(void* pv)
  967. {
  968. THEMEMETRICS_THREADINFO* ptm = (THEMEMETRICS_THREADINFO*)pv;
  969. ASSERT(ptm);
  970. BOOL fSuccess = TRUE;
  971. if (ptm->hUserToken)
  972. {
  973. fSuccess = ImpersonateLoggedOnUser(ptm->hUserToken);
  974. if (!fSuccess)
  975. {
  976. Log(LOG_ALWAYS, L"ImpersonateLoggedOnUser failed in SetSystemMetrics");
  977. }
  978. }
  979. if (fSuccess)
  980. {
  981. SetSystemMetrics_Worker(&ptm->tm);
  982. }
  983. if (ptm->hUserToken)
  984. {
  985. if (fSuccess)
  986. {
  987. RevertToSelf();
  988. }
  989. CloseHandle(ptm->hUserToken);
  990. }
  991. LocalFree(ptm);
  992. FreeLibraryAndExitThread(g_hInst, 0);
  993. }
  994. //---------------------------------------------------------------------------
  995. void SetSystemMetrics(THEMEMETRICS* ptm, BOOL fSyncLoad)
  996. {
  997. BOOL bSuccess = FALSE;
  998. HMODULE hmod;
  999. if (!ptm)
  1000. {
  1001. return;
  1002. }
  1003. if (! fSyncLoad) // ok to use a new thread
  1004. {
  1005. // add a dllref for the thread we are creating
  1006. hmod = LoadLibrary(TEXT("uxtheme.dll"));
  1007. if (hmod)
  1008. {
  1009. THEMEMETRICS_THREADINFO* ptmCopy = (THEMEMETRICS_THREADINFO*)LocalAlloc(LPTR, sizeof(THEMEMETRICS_THREADINFO));
  1010. if (ptmCopy)
  1011. {
  1012. // fill in all of the thememetrics info for the thread we are going to create
  1013. CopyMemory(ptmCopy, ptm, sizeof(THEMEMETRICS));
  1014. HANDLE hToken = NULL;
  1015. // If the calling thread is impersonating, use the same token
  1016. // OpenThreadToken can fail if the thread is not impersonating
  1017. #ifdef DEBUG
  1018. BOOL fSuccess =
  1019. #endif
  1020. OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, &hToken);
  1021. #ifdef DEBUG
  1022. if (!fSuccess)
  1023. {
  1024. DWORD dw = GetLastError();
  1025. Log(LOG_TMCHANGE, L"OpenThreadToken failed in SetSystemMetrics, last error=%d", dw);
  1026. }
  1027. #endif
  1028. ptmCopy->hUserToken = hToken;
  1029. // we want to do this async since we end up calling xxxSendMessage for a TON of things which blocks this
  1030. // thread which can cause deadlocks
  1031. HANDLE hThread = CreateThread(NULL, 0, SetSystemMetrics_WorkerThread, ptmCopy, 0, NULL);
  1032. if (hThread)
  1033. {
  1034. CloseHandle(hThread);
  1035. bSuccess = TRUE;
  1036. }
  1037. else
  1038. {
  1039. LocalFree(ptmCopy);
  1040. }
  1041. }
  1042. if (!bSuccess)
  1043. {
  1044. FreeLibrary(hmod);
  1045. }
  1046. }
  1047. }
  1048. if (!bSuccess)
  1049. {
  1050. // failed, fall back to calling synchronously
  1051. SetSystemMetrics_Worker(ptm);
  1052. }
  1053. }
  1054. //---------------------------------------------------------------------------
  1055. void SetFont(LOGFONT *plf, LPCWSTR lszFontName, int iPointSize)
  1056. {
  1057. memset(plf, 0, sizeof(LOGFONT));
  1058. plf->lfWeight = FW_NORMAL;
  1059. plf->lfCharSet = DEFAULT_CHARSET;
  1060. plf->lfHeight = iPointSize;
  1061. lstrcpy(plf->lfFaceName, lszFontName);
  1062. }
  1063. //---------------------------------------------------------------------------
  1064. COLORREF DefaultColors[] =
  1065. {
  1066. RGB(212, 208, 200), // Scrollbar (0)
  1067. RGB(58, 110, 165), // Background (1)
  1068. RGB(10, 36, 106), // ActiveCaption (2)
  1069. RGB(128, 128, 128), // InactiveCaption (3)
  1070. RGB(212, 208, 200), // Menu (4)
  1071. RGB(255, 255, 255), // Window (5)
  1072. RGB(0, 0, 0), // WindowFrame (6)
  1073. RGB(0, 0, 0), // MenuText (7)
  1074. RGB(0, 0, 0), // WindowText (8)
  1075. RGB(255, 255, 255), // CaptionText (9)
  1076. RGB(212, 208, 200), // ActiveBorder (10)
  1077. RGB(212, 208, 200), // InactiveBorder (11)
  1078. RGB(128, 128, 128), // AppWorkSpace (12)
  1079. RGB(10, 36, 106), // Highlight (13)
  1080. RGB(255, 255, 255), // HighlightText (14)
  1081. RGB(212, 208, 200), // BtnFace (15)
  1082. RGB(128, 128, 128), // BtnShadow (16)
  1083. RGB(128, 128, 128), // GrayText (17)
  1084. RGB(0, 0, 0), // BtnText (18)
  1085. RGB(212, 208, 200), // InactiveCaptionText (19)
  1086. RGB(255, 255, 255), // BtnHighlight (20)
  1087. RGB(64, 64, 64), // DkShadow3d (21)
  1088. RGB(212, 208, 200), // Light3d (22)
  1089. RGB(0, 0, 0), // InfoText (23)
  1090. RGB(255, 255, 225), // InfoBk (24)
  1091. RGB(181, 181, 181), // ButtonAlternateFace (25)
  1092. RGB(0, 0, 128), // HotTracking (26)
  1093. RGB(166, 202, 240), // GradientActiveCaption (27)
  1094. RGB(192, 192, 192), // GradientInactiveCaption (28)
  1095. RGB(206, 211, 225), // MenuiHilight (29)
  1096. RGB(244, 244, 240), // MenuBar (30)
  1097. };
  1098. //---------------------------------------------------------------------------
  1099. HRESULT InitThemeMetrics(LOADTHEMEMETRICS *tm)
  1100. {
  1101. memset(tm, 0, sizeof(*tm)); // zero out in case we miss a property
  1102. //---- init fonts ----
  1103. SetFont(&tm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT], L"tahoma bold", POINTS_DPI96(8));
  1104. SetFont(&tm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1105. SetFont(&tm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1106. SetFont(&tm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1107. SetFont(&tm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1108. SetFont(&tm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
  1109. //---- init bools ----
  1110. tm->fBools[TMT_FLATMENUS - TMT_FIRSTBOOL] = FALSE;
  1111. //---- init sizes ----
  1112. tm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE] = 1;
  1113. tm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE] = 16;
  1114. tm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE] = 16;
  1115. tm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE] = 18;
  1116. tm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1117. tm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE] = 12;
  1118. tm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1119. tm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE] = 18;
  1120. tm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE] = 19;
  1121. //---- init strings ----
  1122. tm->iStringOffsets[TMT_CSSNAME - TMT_FIRSTSTRING] = 0;
  1123. tm->iStringOffsets[TMT_XMLNAME - TMT_FIRSTSTRING] = 0;
  1124. tm->wsStrings[TMT_CSSNAME - TMT_FIRSTSTRING] = L"";
  1125. tm->wsStrings[TMT_XMLNAME - TMT_FIRSTSTRING] = L"";
  1126. //---- init ints ----
  1127. tm->iInts[TMT_MINCOLORDEPTH - TMT_FIRSTINT] = 16;
  1128. //---- init colors ----
  1129. for (int i=0; i < TM_COLORCOUNT; i++)
  1130. tm->crColors[i] = DefaultColors[i];
  1131. return S_OK;
  1132. }
  1133. //---------------------------------------------------------------------------
  1134. HRESULT PersistSystemColors(THEMEMETRICS *tm)
  1135. {
  1136. HRESULT hr;
  1137. LONG lErrorCode;
  1138. HKEY hkcu;
  1139. CCurrentUser hKeyCurrentUser(KEY_SET_VALUE);
  1140. lErrorCode = RegOpenKeyEx(hKeyCurrentUser,
  1141. REGSTR_PATH_COLORS,
  1142. 0,
  1143. KEY_SET_VALUE,
  1144. &hkcu);
  1145. if (ERROR_SUCCESS == lErrorCode)
  1146. {
  1147. hr = S_OK;
  1148. //---- believe it or not, we have to manually write each color ----
  1149. //---- as a string to the registry to persist them ----
  1150. ASSERT(iSysColorSize == TM_COLORCOUNT); // should also match winuser.h entries
  1151. //---- are gradients turned on? ----
  1152. BOOL fGradientsEnabled = FALSE;
  1153. ClassicSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&fGradientsEnabled, 0);
  1154. //---- enough colors for a gradient? ----
  1155. HDC hdc = GetDC(NULL);
  1156. if (hdc)
  1157. {
  1158. if (GetDeviceCaps(hdc, BITSPIXEL) <= 8)
  1159. fGradientsEnabled = FALSE;
  1160. ReleaseDC(NULL, hdc);
  1161. }
  1162. for (int i=0; i < iSysColorSize; i++)
  1163. {
  1164. // If this is the Gradient Caption setting and the system does
  1165. // not currently show gradient captions then don't write them out
  1166. // to the theme file.
  1167. if ((i == COLOR_GRADIENTACTIVECAPTION) || (i == COLOR_GRADIENTINACTIVECAPTION))
  1168. {
  1169. if (! fGradientsEnabled)
  1170. continue;
  1171. }
  1172. //---- translate color into "r, g, b" value string ----
  1173. WCHAR buff[100];
  1174. COLORREF cr = tm->crColors[i];
  1175. wsprintf(buff, L"%d %d %d", RED(cr), GREEN(cr), BLUE(cr));
  1176. //---- write color key/value to registry ----
  1177. lErrorCode = RegSetValueEx(hkcu,
  1178. pszSysColorNames[i],
  1179. 0,
  1180. REG_SZ,
  1181. reinterpret_cast<BYTE*>(buff),
  1182. (lstrlen(buff) + 1) * sizeof(WCHAR));
  1183. if (ERROR_SUCCESS != lErrorCode)
  1184. {
  1185. if (SUCCEEDED(hr))
  1186. {
  1187. hr = MakeError32(lErrorCode);
  1188. }
  1189. }
  1190. }
  1191. (LONG)RegCloseKey(hkcu);
  1192. }
  1193. else
  1194. {
  1195. hr = MakeError32(lErrorCode);
  1196. }
  1197. return hr;
  1198. }
  1199. //---------------------------------------------------------------------------
  1200. BOOL CThemeLoader::KeyDrawPropertyFound(int iStateDataOffset)
  1201. {
  1202. BOOL fFound = FALSE;
  1203. MIXEDPTRS u;
  1204. UNPACKED_ENTRYHDR hdr;
  1205. u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
  1206. while (*u.ps != TMT_JUMPTOPARENT)
  1207. {
  1208. if (CBorderFill::KeyProperty((*u.ps)))
  1209. {
  1210. fFound = TRUE;
  1211. break;
  1212. }
  1213. if (CImageFile::KeyProperty((*u.ps)))
  1214. {
  1215. fFound = TRUE;
  1216. break;
  1217. }
  1218. //---- skip to next entry ----
  1219. FillAndSkipHdr(u, &hdr);
  1220. u.pb += hdr.dwDataLen;
  1221. }
  1222. return fFound;
  1223. }
  1224. //---------------------------------------------------------------------------
  1225. BOOL CThemeLoader::KeyTextPropertyFound(int iStateDataOffset)
  1226. {
  1227. BOOL fFound = FALSE;
  1228. MIXEDPTRS u;
  1229. UNPACKED_ENTRYHDR hdr;
  1230. u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
  1231. while (*u.ps != TMT_JUMPTOPARENT)
  1232. {
  1233. if (CTextDraw::KeyProperty((*u.ps)))
  1234. {
  1235. fFound = TRUE;
  1236. break;
  1237. }
  1238. //---- skip to next entry ----
  1239. FillAndSkipHdr(u, &hdr);
  1240. u.pb += hdr.dwDataLen;
  1241. }
  1242. return fFound;
  1243. }
  1244. //---------------------------------------------------------------------------
  1245. HRESULT CThemeLoader::PackImageFileInfo(DIBINFO *pdi, CImageFile *pImageObj, MIXEDPTRS &u,
  1246. CRenderObj *pRender, int iPartId, int iStateId)
  1247. {
  1248. HRESULT hr = S_OK;
  1249. //---- write custom region data ----
  1250. int iMaxState;
  1251. if ((! iStateId) && (pImageObj->HasRegionImageFile(pdi, &iMaxState)))
  1252. {
  1253. //---- update object's _iRgnDataOffset field ----
  1254. pImageObj->SetRgnListOffset(pdi, THEME_OFFSET(u.pb));
  1255. //---- write the TMT_RGNLIST entry ----
  1256. hr = EmitEntryHdr(u, TMT_RGNLIST, TMT_RGNLIST);
  1257. if (FAILED(hr))
  1258. goto exit;
  1259. int cEntries = iMaxState + 1; // number of jump table entries
  1260. hr = AllocateThemeFileBytes(u.pb, 1 + cEntries * sizeof(int));
  1261. if (FAILED(hr))
  1262. goto exit;
  1263. *u.pb++ = static_cast<BYTE>(cEntries);
  1264. //---- write jump table now and update asap ----
  1265. int *piJumpTable = u.pi;
  1266. for (int i=0; i <= iMaxState; i++)
  1267. *u.pi++ = 0;
  1268. for (int iRgnState=0; iRgnState <= iMaxState; iRgnState++)
  1269. {
  1270. //---- build & pack custom region data for each state in this object's imagefile ----
  1271. CAutoArrayPtr<RGNDATA> pRgnData;
  1272. int iDataLen;
  1273. hr = pImageObj->BuildRgnData(pdi, pRender, iRgnState, &pRgnData, &iDataLen);
  1274. if (FAILED(hr))
  1275. goto exit;
  1276. if (iDataLen) // if we got a non-empty region
  1277. {
  1278. piJumpTable[iRgnState] = THEME_OFFSET(u.pb);
  1279. RGNDATAHDR rdHdr = {iPartId, iRgnState, 0};
  1280. //---- copy rgndata hdr ----
  1281. hr = EmitObject(u, TMT_RGNDATA, TMT_RGNDATA, &rdHdr, sizeof(rdHdr), pRgnData, iDataLen);
  1282. if (FAILED(hr))
  1283. goto exit;
  1284. }
  1285. }
  1286. EndEntry(u);
  1287. }
  1288. exit:
  1289. return hr;
  1290. }
  1291. //---------------------------------------------------------------------------
  1292. HRESULT CThemeLoader::PackDrawObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId,
  1293. int iStateId)
  1294. {
  1295. HRESULT hr = S_OK;
  1296. BGTYPE eBgType;
  1297. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_BGTYPE, (int *)&eBgType)))
  1298. eBgType = BT_BORDERFILL; // default value
  1299. DRAWOBJHDR hdr = {iPartId, iStateId};
  1300. if ((eBgType == BT_BORDERFILL) || (eBgType == BT_NONE))
  1301. {
  1302. CBorderFill bfobj;
  1303. hr = bfobj.PackProperties(pRender, (eBgType == BT_NONE), iPartId, iStateId);
  1304. if (FAILED(hr))
  1305. goto exit;
  1306. //---- copy "bfobj" to packed bytes ----
  1307. hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &bfobj, sizeof(bfobj));
  1308. if (FAILED(hr))
  1309. goto exit;
  1310. }
  1311. else // imagefile
  1312. {
  1313. CMaxImageFile maxif;
  1314. int iMultiCount;
  1315. hr = maxif.PackMaxProperties(pRender, iPartId, iStateId, &iMultiCount);
  1316. if (FAILED(hr))
  1317. goto exit;
  1318. //---- process all DIBINFO structs in the CImageFile obj ----
  1319. for (int i=0; ; i++)
  1320. {
  1321. DIBINFO *pdi = maxif.EnumImageFiles(i);
  1322. if (! pdi)
  1323. break;
  1324. hr = PackImageFileInfo(pdi, &maxif, u, pRender, iPartId, iStateId);
  1325. if (FAILED(hr))
  1326. goto exit;
  1327. }
  1328. //---- copy imagefile obj & multi DIB's to packed bytes ----
  1329. DWORD dwLen = sizeof(CImageFile) + sizeof(DIBINFO)*iMultiCount;
  1330. hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &maxif, dwLen);
  1331. if (FAILED(hr))
  1332. goto exit;
  1333. }
  1334. exit:
  1335. return hr;
  1336. }
  1337. //---------------------------------------------------------------------------
  1338. HRESULT CThemeLoader::PackTextObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId)
  1339. {
  1340. HRESULT hr;
  1341. DRAWOBJHDR hdr = {iPartId, iStateId};
  1342. CTextDraw ctobj;
  1343. hr = ctobj.PackProperties(pRender, iPartId, iStateId);
  1344. if (FAILED(hr))
  1345. goto exit;
  1346. hr = EmitObject(u, TMT_TEXTOBJ, TMT_TEXTOBJ, &hdr, sizeof(hdr), &ctobj, sizeof(ctobj));
  1347. if (FAILED(hr))
  1348. goto exit;
  1349. exit:
  1350. return hr;
  1351. }
  1352. //---------------------------------------------------------------------------
  1353. int CThemeLoader::GetPartOffset(CRenderObj *pRender, int iPartNum)
  1354. {
  1355. int iOffset;
  1356. int iPartCount;
  1357. MIXEDPTRS u;
  1358. //---- see if state table exists for this part ----
  1359. u.pb = pRender->_pbSectionData;
  1360. if (*u.ps != TMT_PARTJUMPTABLE)
  1361. {
  1362. iOffset = -1;
  1363. goto exit;
  1364. }
  1365. u.pb += ENTRYHDR_SIZE + sizeof(int); // skip over hdr + PackedObjOffset
  1366. iPartCount = *u.pb++;
  1367. if (iPartNum >= iPartCount) // iPartCount is MaxPart+1
  1368. {
  1369. iOffset = -1;
  1370. goto exit;
  1371. }
  1372. iOffset = u.pi[iPartNum];
  1373. exit:
  1374. return iOffset;
  1375. }
  1376. //---------------------------------------------------------------------------
  1377. HRESULT CThemeLoader::PackDrawObjects(MIXEDPTRS &uOut, CRenderObj *pRender,
  1378. int iMaxPart, BOOL fGlobals)
  1379. {
  1380. HRESULT hr = S_OK;
  1381. MIXEDPTRS u;
  1382. //---- build a draw obj for each part ----
  1383. for (int iPart=0; iPart <= iMaxPart; iPart++)
  1384. {
  1385. int iPartOff = GetPartOffset(pRender, iPart);
  1386. if (iPartOff == -1)
  1387. continue;
  1388. u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
  1389. if (*u.ps == TMT_STATEJUMPTABLE)
  1390. {
  1391. u.pb += ENTRYHDR_SIZE;
  1392. int iMaxState = (*u.pb++) - 1;
  1393. int *piStateJumpTable = u.pi;
  1394. //---- build a draw obj for each needed state ----
  1395. for (int iState=0; iState <= iMaxState; iState++)
  1396. {
  1397. int iStateDataOffset = piStateJumpTable[iState];
  1398. if (iStateDataOffset == -1)
  1399. continue;
  1400. if ((fGlobals) || (KeyDrawPropertyFound(iStateDataOffset)))
  1401. {
  1402. hr = PackDrawObject(uOut, pRender, iPart, iState);
  1403. if (FAILED(hr))
  1404. goto exit;
  1405. if (fGlobals) // just needed to force (part=0, state=0)
  1406. fGlobals = FALSE;
  1407. }
  1408. }
  1409. }
  1410. else // no state jump table
  1411. {
  1412. if ((fGlobals) || (KeyDrawPropertyFound(THEME_OFFSET(u.pb))))
  1413. {
  1414. hr = PackDrawObject(uOut, pRender, iPart, 0);
  1415. if (FAILED(hr))
  1416. goto exit;
  1417. }
  1418. }
  1419. }
  1420. exit:
  1421. return hr;
  1422. }
  1423. //---------------------------------------------------------------------------
  1424. HRESULT CThemeLoader::PackTextObjects(MIXEDPTRS &uOut, CRenderObj *pRender,
  1425. int iMaxPart, BOOL fGlobals)
  1426. {
  1427. HRESULT hr = S_OK;
  1428. MIXEDPTRS u;
  1429. //---- build a text obj for each part ----
  1430. for (int iPart=0; iPart <= iMaxPart; iPart++)
  1431. {
  1432. int iPartOff = GetPartOffset(pRender, iPart);
  1433. if (iPartOff == -1)
  1434. continue;
  1435. u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
  1436. if (*u.ps == TMT_STATEJUMPTABLE)
  1437. {
  1438. u.pb += ENTRYHDR_SIZE;
  1439. int iMaxState = (*u.pb++) - 1;
  1440. int *piStateJumpTable = u.pi;
  1441. //---- build a text obj for each needed state ----
  1442. for (int iState=0; iState <= iMaxState; iState++)
  1443. {
  1444. int iStateDataOffset = piStateJumpTable[iState];
  1445. if (iStateDataOffset == -1)
  1446. continue;
  1447. if ((fGlobals) || (KeyTextPropertyFound(iStateDataOffset)))
  1448. {
  1449. hr = PackTextObject(uOut, pRender, iPart, iState);
  1450. if (FAILED(hr))
  1451. goto exit;
  1452. if (fGlobals) // just needed to force (part=0, state=0)
  1453. fGlobals = FALSE;
  1454. }
  1455. }
  1456. }
  1457. else // no state jump table
  1458. {
  1459. if ((fGlobals) || (KeyTextPropertyFound(THEME_OFFSET(u.pb))))
  1460. {
  1461. hr = PackTextObject(uOut, pRender, iPart, 0);
  1462. if (FAILED(hr))
  1463. goto exit;
  1464. }
  1465. }
  1466. }
  1467. exit:
  1468. return hr;
  1469. }
  1470. //---------------------------------------------------------------------------
  1471. HRESULT CThemeLoader::EmitEntryHdr(MIXEDPTRS &u, SHORT propnum, BYTE privnum)
  1472. {
  1473. HRESULT hr = S_OK;
  1474. if (_iEntryHdrLevel == MAX_ENTRY_NESTING)
  1475. {
  1476. Log(LOG_ERROR, L"Maximum entry nesting exceeded");
  1477. hr = E_FAIL;
  1478. goto exit;
  1479. }
  1480. if (_LoadingThemeFile._pbThemeData != NULL)
  1481. {
  1482. hr = AllocateThemeFileBytes(u.pb, ENTRYHDR_SIZE);
  1483. if (FAILED(hr))
  1484. goto exit;
  1485. }
  1486. //---- bump up the nesting level of entries ----
  1487. _iEntryHdrLevel++;
  1488. *u.ps++ = propnum;
  1489. *u.pb++ = privnum;
  1490. _pbEntryHdrs[_iEntryHdrLevel] = u.pb; // used to update next 2 fields in EndEntry()
  1491. *u.pb++ = 0; // filler to align end of data to 4/8 bytes
  1492. *u.pi++ = 0; // length
  1493. exit:
  1494. return hr;
  1495. }
  1496. //---------------------------------------------------------------------------
  1497. int CThemeLoader::EndEntry(MIXEDPTRS &u)
  1498. {
  1499. MIXEDPTRS uHdr;
  1500. uHdr.pb = _pbEntryHdrs[_iEntryHdrLevel];
  1501. //---- calcuate actual length of date emitted ----
  1502. int iActualLen = (int)(u.pb - (uHdr.pb + sizeof(BYTE) + sizeof(int)));
  1503. //---- calculate filler to be aligned ----
  1504. int iAlignLen = ((iActualLen + ALIGN_FACTOR - 1)/ALIGN_FACTOR) * ALIGN_FACTOR;
  1505. BYTE bFiller = (BYTE)(iAlignLen - iActualLen);
  1506. if (_LoadingThemeFile._pbThemeData != NULL)
  1507. {
  1508. HRESULT hr = AllocateThemeFileBytes(u.pb, bFiller);
  1509. if (FAILED(hr))
  1510. return -1;
  1511. }
  1512. //---- emit filler bytes to be correctly aligned ----
  1513. for (int i=0; i < bFiller; i++)
  1514. *u.pb++ = 0 ;
  1515. //---- update the entry Hdr ----
  1516. *uHdr.pb++ = bFiller;
  1517. *uHdr.pi++ = iAlignLen;
  1518. //---- decrement the nesting level of entries ----
  1519. _iEntryHdrLevel--;
  1520. return bFiller;
  1521. }
  1522. //---------------------------------------------------------------------------