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.

2723 lines
80 KiB

  1. //---------------------------------------------------------------------------
  2. // Parser.cpp - parses a "themes.ini" file and builds the ThemeInfo entries
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "scanner.h"
  6. #include "Parser.h"
  7. #include "Utils.h"
  8. #include "TmUtils.h"
  9. #include "TmSchema.h"
  10. #include "TmReg.h"
  11. //---------------------------------------------------------------------------
  12. //#include "NtlParse.h"
  13. #define SYSCOLOR_STRINGS
  14. #include "SysColors.h"
  15. //---------------------------------------------------------------------------
  16. #define SCHEMA_STRINGS
  17. #include "TmSchema.h" // implements GetSchemaInfo()
  18. #ifdef DEBUG
  19. // TODO: Isn't synchronized anymore (different processes), need to use a volatile reg key instead
  20. DWORD g_dwStockSize = 0;
  21. #endif
  22. static HBITMAP (*s_pfnSetBitmapAttributes)(HBITMAP, DWORD) = NULL;
  23. static HBITMAP (*s_pfnClearBitmapAttributes)(HBITMAP, DWORD) = NULL;
  24. //--------------------------------------------------------------------
  25. CThemeParser::CThemeParser(BOOL fGlobalTheme)
  26. {
  27. _pCallBackObj = NULL;
  28. _pNameCallBack = NULL;
  29. _fGlobalsDefined = FALSE;
  30. _fClassSectionDefined = FALSE;
  31. _fDefiningColorScheme = FALSE;
  32. _fUsingResourceProperties = FALSE;
  33. _fDefiningMetrics = FALSE;
  34. _fMetricsDefined = FALSE;
  35. _fGlobalTheme = FALSE;
  36. _crBlend = RGB(0, 0, 0xFF); // Hard code to blue
  37. *_szResPropValue = 0; // not yet set
  38. #ifdef DEBUG
  39. // Provide a means of disabling stock bitmaps
  40. BOOL fStock = TRUE;
  41. GetCurrentUserThemeInt(L"StockBitmaps", TRUE, &fStock);
  42. if (fStock && fGlobalTheme)
  43. #else
  44. if (fGlobalTheme)
  45. #endif
  46. {
  47. // Just don't use stock bitmaps when not running on Whistler
  48. if (s_pfnSetBitmapAttributes != NULL)
  49. {
  50. _fGlobalTheme = TRUE;
  51. } else
  52. {
  53. HMODULE hMod = ::LoadLibrary(L"GDI32.DLL"); // No need to free
  54. if (hMod)
  55. {
  56. s_pfnSetBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "SetBitmapAttributes");
  57. s_pfnClearBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "ClearBitmapAttributes");
  58. if ((s_pfnSetBitmapAttributes != NULL) && (s_pfnClearBitmapAttributes != NULL))
  59. {
  60. _fGlobalTheme = TRUE;
  61. }
  62. }
  63. }
  64. }
  65. *_szBaseSectionName = 0;
  66. *_szFullSectionName = 0;
  67. _iColorCount = 0;
  68. _iHueCount = 0;
  69. _uCharSet = DEFAULT_CHARSET;
  70. _iFontNumber = 0;
  71. _hinstThemeDll = NULL;
  72. }
  73. //---------------------------------------------------------------------------
  74. HRESULT CThemeParser::SourceError(int iMsgResId, LPCWSTR pszParam1, LPCWSTR pszParam2)
  75. {
  76. LPCWSTR pszSrcLine = _scan._szLineBuff;
  77. LPCWSTR pszFileName = _scan._szFileName;
  78. int iLineNum = _scan._iLineNum;
  79. if (*_szResPropValue) // error in localizable property value
  80. {
  81. pszSrcLine = _szResPropValue;
  82. pszFileName = L"StringTable#";
  83. iLineNum = _iResPropId;
  84. }
  85. HRESULT hr = MakeParseError(iMsgResId, pszParam1, pszParam2, pszFileName,
  86. pszSrcLine, iLineNum);
  87. return hr;
  88. }
  89. //---------------------------------------------------------------------------
  90. PRIMVAL CThemeParser::GetPrimVal(LPCWSTR pszName)
  91. {
  92. int symcnt = _Symbols.GetSize();
  93. for (int i=0; i < symcnt; i++)
  94. {
  95. if (AsciiStrCmpI(_Symbols[i].csName, pszName)==0)
  96. return _Symbols[i].ePrimVal;
  97. }
  98. return TMT_UNKNOWN;
  99. }
  100. //---------------------------------------------------------------------------
  101. int CThemeParser::GetSymbolIndex(LPCWSTR pszName)
  102. {
  103. int symcnt = _Symbols.GetSize();
  104. for (int i=0; i < symcnt; i++)
  105. {
  106. if (AsciiStrCmpI(_Symbols[i].csName, pszName)==0)
  107. return i;
  108. }
  109. return -1;
  110. }
  111. //---------------------------------------------------------------------------
  112. HRESULT CThemeParser::AddSymbol(LPCWSTR pszName, SHORT sTypeNum, PRIMVAL ePrimVal)
  113. {
  114. //---- ensure symbol doesn't already exist ----
  115. for (int i = 0; i < _Symbols.m_nSize; i++)
  116. {
  117. if (AsciiStrCmpI(_Symbols.m_aT[i].csName, pszName)==0)
  118. return SourceError(PARSER_IDS_TYPE_DEFINED_TWICE, pszName);
  119. }
  120. if (sTypeNum == -1)
  121. sTypeNum = (SHORT)_Symbols.GetSize();
  122. SYMBOL symbol;
  123. symbol.csName = pszName;
  124. symbol.sTypeNum = sTypeNum;
  125. symbol.ePrimVal = ePrimVal;
  126. _Symbols.Add(symbol);
  127. return S_OK;
  128. }
  129. //---------------------------------------------------------------------------
  130. HRESULT CThemeParser::InitializeSymbols()
  131. {
  132. _Symbols.RemoveAll();
  133. _StockBitmapCleanupList.RemoveAll();
  134. //---- get tm & comctl symbols ----
  135. const TMSCHEMAINFO *si = GetSchemaInfo();
  136. int cnt = si->iPropCount;
  137. const TMPROPINFO *pi = si->pPropTable;
  138. //---- first pass - add all symbols except ENUM definitions ----
  139. for (int i=0; i < cnt; i++)
  140. {
  141. if (pi[i].bPrimVal == TMT_ENUMDEF)
  142. continue;
  143. if (pi[i].bPrimVal == TMT_ENUMVAL)
  144. continue;
  145. HRESULT hr = AddSymbol(pi[i].pszName, pi[i].sEnumVal, pi[i].bPrimVal);
  146. if (FAILED(hr))
  147. return hr;
  148. }
  149. //---- second pass - add ENUM definitions ----
  150. int iEnumPropNum = -1;
  151. for (int i=0; i < cnt; i++)
  152. {
  153. if (pi[i].bPrimVal == TMT_ENUMDEF)
  154. {
  155. int iSymIndex = GetSymbolIndex(pi[i].pszName);
  156. if (iSymIndex == -1) // not found - add it as a non-property enum symbol
  157. {
  158. HRESULT hr = AddSymbol(pi[i].pszName, -1, TMT_ENUM);
  159. if (FAILED(hr))
  160. return hr;
  161. iSymIndex = GetSymbolIndex(pi[i].pszName);
  162. }
  163. if (iSymIndex > -1)
  164. iEnumPropNum = _Symbols[iSymIndex].sTypeNum;
  165. else
  166. iEnumPropNum = -1;
  167. }
  168. else if (pi[i].bPrimVal == TMT_ENUMVAL)
  169. {
  170. ENUMVAL enumval;
  171. enumval.csName = pi[i].pszName;
  172. enumval.iSymbolIndex = iEnumPropNum;
  173. enumval.iValue = pi[i].sEnumVal;
  174. _EnumVals.Add(enumval);
  175. }
  176. }
  177. return S_OK;
  178. }
  179. //---------------------------------------------------------------------------
  180. HRESULT CThemeParser::ParseDocSection()
  181. {
  182. _scan.ForceNextLine(); // get line after section line
  183. //---- just skip over all lines in this section ----
  184. while (1)
  185. {
  186. WCHAR szNameBuff[_MAX_PATH+1];
  187. if (_scan.GetChar('[')) // start of new section
  188. break;
  189. if (! _scan.GetId(szNameBuff))
  190. return SourceError(PARSER_IDS_EXPECTED_PROP_NAME);
  191. if (! _scan.GetChar('='))
  192. return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN);
  193. int cnt = _Symbols.GetSize();
  194. for (int i=0; i < cnt; i++)
  195. {
  196. if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0)
  197. break;
  198. }
  199. int symtype;
  200. if (i == cnt)
  201. symtype = TMT_STRING; // unknown string property
  202. else
  203. symtype = _Symbols[i].sTypeNum;
  204. HRESULT hr;
  205. //---- check to see if caller is querying for a doc property ----
  206. if ((_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (lstrcmpi(_pszDocProperty, szNameBuff)==0))
  207. hr = ParseStringValue(symtype, _pszResult, _dwMaxResultChars);
  208. else
  209. hr = ParseStringValue(symtype);
  210. if (FAILED(hr))
  211. return hr;
  212. _scan.ForceNextLine();
  213. }
  214. //---- done with [documentation] section - turn off callback flag for properties ----
  215. _dwParseFlags &= (~PTF_CALLBACK_DOCPROPERTIES);
  216. return S_OK;
  217. }
  218. //---------------------------------------------------------------------------
  219. HRESULT CThemeParser::ParseClassSectionName(LPCWSTR pszFirstName, LPWSTR appsym)
  220. {
  221. //---- validate section name ----
  222. //
  223. // optional: appsym::
  224. // _szClassName
  225. // optional: .partsym
  226. WCHAR partsym[_MAX_PATH+1];
  227. WCHAR statesym[_MAX_PATH+1];
  228. *appsym = 0;
  229. *partsym = 0;
  230. _iPartId = -1;
  231. _iStateId = -1;
  232. //---- copy the section name for callbacks ----
  233. wsprintf(_szFullSectionName, L"%s%s", pszFirstName, _scan._p);
  234. WCHAR *p = wcschr(_szFullSectionName, ']');
  235. if (p)
  236. *p = 0;
  237. HRESULT hr;
  238. hr = hr_lstrcpy(_szClassName, pszFirstName, ARRAYSIZE(_szClassName));
  239. if (FAILED(hr))
  240. return hr;
  241. if (_scan.GetChar(':'))
  242. {
  243. hr = hr_lstrcpy(appsym, _szClassName, MAX_PATH);
  244. if (FAILED(hr))
  245. return hr;
  246. if (! _scan.GetChar(':'))
  247. return SourceError(PARSER_IDS_EXPECTED_DOUBLE_COLON);
  248. if (! _scan.GetId(_szClassName))
  249. return SourceError(PARSER_IDS_MISSING_SECT_HDR_NAME);
  250. }
  251. else
  252. *appsym = 0;
  253. _fDefiningMetrics = (AsciiStrCmpI(_szClassName, L"SysMetrics")==0);
  254. if ((_fDefiningMetrics) && (*appsym))
  255. return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  256. if (_scan.GetChar('.')) // an optional part id
  257. {
  258. //---- ensure a enum exists: <classname>Parts ----
  259. WCHAR classparts[_MAX_PATH+1];
  260. wsprintf(classparts, L"%sParts", _szClassName);
  261. int iSymIndex = GetSymbolIndex(classparts);
  262. if (iSymIndex == -1) // doesn't exist
  263. return SourceError(PARSER_IDS_PARTS_NOT_DEFINED, _szClassName);
  264. //---- _scan the part name ----
  265. if (! _scan.GetId(partsym))
  266. return SourceError(PARSER_IDS_MISSING_SECT_HDR_PART);
  267. //---- validate that it is a value for the <classname>Parts ----
  268. hr = ValidateEnumSymbol(partsym, iSymIndex, &_iPartId);
  269. if (FAILED(hr))
  270. return hr;
  271. }
  272. if (_scan.GetChar('(')) // an optional state
  273. {
  274. //---- ensure a enum exists: <class or part name>States ----
  275. WCHAR statesname[_MAX_PATH+1];
  276. WCHAR *pszBaseName;
  277. if (_iPartId == -1)
  278. pszBaseName = _szClassName;
  279. else
  280. pszBaseName = partsym;
  281. wsprintf(statesname, L"%sStates", pszBaseName);
  282. int iSymIndex = GetSymbolIndex(statesname);
  283. if (iSymIndex == -1)
  284. return SourceError(PARSER_IDS_STATES_NOT_DEFINED, pszBaseName);
  285. if (! _scan.GetId(statesym))
  286. return SourceError(PARSER_IDS_MISSING_SECT_HDR_STATE);
  287. hr = ValidateEnumSymbol(statesym, iSymIndex, &_iStateId);
  288. if (FAILED(hr))
  289. return hr;
  290. if (! _scan.GetChar(')'))
  291. return SourceError(PARSER_IDS_EXPECTED_RPAREN);
  292. }
  293. if (_iPartId > -1)
  294. {
  295. _iPartId = _EnumVals[_iPartId].iValue;
  296. lstrcpy_truncate(_szBaseSectionName, partsym, ARRAYSIZE(_szBaseSectionName));
  297. }
  298. else // not specified
  299. {
  300. lstrcpy_truncate(_szBaseSectionName, _szClassName, ARRAYSIZE(_szBaseSectionName));
  301. _iPartId = 0;
  302. }
  303. if (_iStateId > -1)
  304. _iStateId = _EnumVals[_iStateId].iValue;
  305. else
  306. _iStateId = 0;
  307. if (! _scan.GetChar(']'))
  308. return SourceError(PARSER_IDS_EXPECTED_END_OF_SECTION);
  309. return S_OK;
  310. }
  311. //---------------------------------------------------------------------------
  312. HRESULT CThemeParser::ValidateEnumSymbol(LPCWSTR pszName, int iSymType,
  313. int *pIndex)
  314. {
  315. for (int i = 0; i < _EnumVals.m_nSize; i++)
  316. {
  317. if (AsciiStrCmpI(_EnumVals.m_aT[i].csName, pszName)==0)
  318. {
  319. if (_EnumVals.m_aT[i].iSymbolIndex == iSymType)
  320. {
  321. if (pIndex)
  322. *pIndex = i;
  323. return S_OK;
  324. }
  325. }
  326. }
  327. return SourceError(PARSER_IDS_NOT_ENUM_VALNAME, pszName, (LPCWSTR)_Symbols[iSymType].csName);
  328. }
  329. //---------------------------------------------------------------------------
  330. HRESULT CThemeParser::AddThemeData(int iTypeNum, PRIMVAL ePrimVal,
  331. const void *pData, DWORD dwLen)
  332. {
  333. //Log("AddThemeData: typenum=%d, len=%d, data=0x%x", iTypeNum, dwLen, pData);
  334. if (! _pCallBackObj)
  335. return S_FALSE;
  336. HRESULT hr = _pCallBackObj->AddData((SHORT)iTypeNum, ePrimVal, pData, dwLen);
  337. if (FAILED(hr))
  338. return SourceError(PARSER_IDS_THEME_TOO_BIG);
  339. return S_OK;
  340. }
  341. //---------------------------------------------------------------------------
  342. HRESULT CThemeParser::ParseEnumValue(int iSymType)
  343. {
  344. WCHAR valbuff[_MAX_PATH+1];
  345. HRESULT hr;
  346. int value;
  347. if (! _scan.GetId(valbuff))
  348. return SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED);
  349. int index;
  350. hr = ValidateEnumSymbol(valbuff, iSymType, &index);
  351. if (FAILED(hr))
  352. return hr;
  353. value = _EnumVals[index].iValue;
  354. hr = AddThemeData(iSymType, TMT_ENUM, &value, sizeof(value));
  355. if (FAILED(hr))
  356. return hr;
  357. return S_OK;
  358. }
  359. //---------------------------------------------------------------------------
  360. HRESULT CThemeParser::GetEnumValue(LPCWSTR pszEnumName, LPCWSTR pszEnumValName,
  361. int *piValue)
  362. {
  363. if (! pszEnumName )
  364. return SourceError(PARSER_IDS_ENUM_NOT_DEFINED);
  365. //---- lookup the Enum Name ----
  366. int cnt = _Symbols.GetSize();
  367. for (int i=0; i < cnt; i++)
  368. {
  369. if (AsciiStrCmpI(_Symbols[i].csName, pszEnumName)==0)
  370. break;
  371. }
  372. if (i == cnt)
  373. return SourceError(PARSER_IDS_NOT_ENUM_VALNAME, pszEnumValName, pszEnumName);
  374. int iSymType = _Symbols[i].sTypeNum;
  375. //---- lookup the Enum value name ----
  376. int index;
  377. HRESULT hr = ValidateEnumSymbol(pszEnumValName, iSymType, &index);
  378. if (FAILED(hr))
  379. return hr;
  380. *piValue = _EnumVals[index].iValue;
  381. return S_OK;
  382. }
  383. //---------------------------------------------------------------------------
  384. HRESULT CThemeParser::ParseStringValue(int iSymType, LPWSTR pszBuff, DWORD dwMaxBuffChars)
  385. {
  386. HRESULT hr;
  387. //---- just store the raw string ----
  388. _scan.SkipSpaces();
  389. if (_fDefiningMetrics)
  390. {
  391. if ((iSymType < TMT_FIRSTSTRING) || (iSymType > TMT_LASTSTRING))
  392. return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  393. }
  394. if (pszBuff) // special call
  395. {
  396. hr = hr_lstrcpy(pszBuff, _scan._p, dwMaxBuffChars);
  397. if (FAILED(hr))
  398. return hr;
  399. }
  400. else
  401. {
  402. int len = 1 + lstrlen(_scan._p);
  403. hr = AddThemeData(iSymType, TMT_STRING, _scan._p, len*sizeof(WCHAR));
  404. if (FAILED(hr))
  405. return hr;
  406. }
  407. if ((iSymType >= TMT_FIRST_RCSTRING_NAME) && (iSymType <= TMT_LAST_RCSTRING_NAME))
  408. {
  409. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_DOCPROPERTIES))
  410. {
  411. int index = iSymType - TMT_FIRST_RCSTRING_NAME;
  412. BOOL fContinue = (*_pNameCallBack)(TCB_DOCPROPERTY, _scan._p, NULL,
  413. NULL, index, _lNameParam);
  414. if (! fContinue)
  415. return MakeErrorParserLast();
  416. }
  417. }
  418. //---- advance _scanner to end of line ----
  419. _scan._p += lstrlen(_scan._p);
  420. return S_OK;
  421. }
  422. //---------------------------------------------------------------------------
  423. HRESULT CThemeParser::ParseIntValue(int iSymType, int *piValue)
  424. {
  425. int value;
  426. if (! _scan.GetNumber(&value))
  427. return SourceError(PARSER_IDS_INT_EXPECTED);
  428. if (piValue) // special call
  429. *piValue = value;
  430. else
  431. {
  432. HRESULT hr = AddThemeData(iSymType, TMT_INT, &value, sizeof(value));
  433. if (FAILED(hr))
  434. return hr;
  435. }
  436. if (iSymType == TMT_CHARSET)
  437. {
  438. if (_iFontNumber)
  439. return SourceError(PARSER_IDS_CHARSETFIRST);
  440. if (_fGlobalsDefined)
  441. return SourceError(PARSER_IDS_CHARSET_GLOBALS_ONLY);
  442. _uCharSet = (UCHAR) value;
  443. }
  444. if (iSymType == TMT_MINCOLORDEPTH)
  445. {
  446. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_MINCOLORDEPTH))
  447. {
  448. BOOL fContinue = (*_pNameCallBack)(TCB_MINCOLORDEPTH, _scan._szFileName, NULL,
  449. NULL, value, _lNameParam);
  450. if (! fContinue)
  451. return MakeErrorParserLast();
  452. }
  453. }
  454. return S_OK;
  455. }
  456. //---------------------------------------------------------------------------
  457. HRESULT CThemeParser::ParseBoolValue(int iSymType, LPCWSTR pszPropertyName)
  458. {
  459. WCHAR valbuff[_MAX_PATH+1];
  460. BYTE bBoolVal;
  461. if (! _scan.GetId(valbuff))
  462. return SourceError(PARSER_IDS_BOOL_EXPECTED);
  463. if (AsciiStrCmpI(valbuff, L"true")==0)
  464. bBoolVal = 1;
  465. else if (AsciiStrCmpI(valbuff, L"false")==0)
  466. bBoolVal = 0;
  467. else
  468. return SourceError(PARSER_IDS_EXPECTED_TRUE_OR_FALSE);
  469. if (_fDefiningMetrics)
  470. {
  471. if ((iSymType < TMT_FIRSTBOOL) || (iSymType > TMT_LASTBOOL))
  472. return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  473. }
  474. //---- special handling for "MirrorImage" property ----
  475. if (iSymType == TMT_MIRRORIMAGE)
  476. {
  477. //---- handle MirrorImage callbacks (packtime) ----
  478. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS))
  479. {
  480. BOOL fContinue = (*_pNameCallBack)(TCB_MIRRORIMAGE, _szClassName,
  481. _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)bBoolVal);
  482. if (! fContinue)
  483. return MakeErrorParserLast();
  484. }
  485. //---- handle getting value from string table (loadtime) ----
  486. if (_fUsingResourceProperties) // substitute resource value
  487. {
  488. WCHAR szValue[MAX_PATH];
  489. HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue));
  490. if (SUCCEEDED(hr))
  491. {
  492. bBoolVal = (*szValue == '1');
  493. }
  494. else
  495. {
  496. hr = S_OK; // non-fatal error
  497. }
  498. }
  499. }
  500. HRESULT hr = AddThemeData(iSymType, TMT_BOOL, &bBoolVal, sizeof(bBoolVal));
  501. if (FAILED(hr))
  502. return hr;
  503. return S_OK;
  504. }
  505. //---------------------------------------------------------------------------
  506. COLORREF CThemeParser::ApplyColorSubstitution(COLORREF crOld)
  507. {
  508. //---- apply SOLID color substitutions ----
  509. for (int i=0; i < _iColorCount; i++)
  510. {
  511. if (crOld == _crFromColors[i])
  512. return _crToColors[i];
  513. }
  514. //---- apply HUE color substitutions ----
  515. WORD wHue, wLum, wSat;
  516. RGBtoHLS(crOld, &wHue, &wLum, &wSat);
  517. for (i=0; i < _iHueCount; i++)
  518. {
  519. if (wHue == _bFromHues[i]) // hues match
  520. {
  521. COLORREF crNew = HLStoRGB(_bToHues[i], wLum, wSat); // substitute new hue
  522. return crNew;
  523. }
  524. }
  525. return crOld;
  526. }
  527. //---------------------------------------------------------------------------
  528. void CThemeParser::CleanupStockBitmaps()
  529. {
  530. if (s_pfnClearBitmapAttributes)
  531. {
  532. for (int i=0; i < _StockBitmapCleanupList.m_nSize; i++)
  533. {
  534. HBITMAP hbm = (*s_pfnClearBitmapAttributes)(_StockBitmapCleanupList[i], SBA_STOCK);
  535. if (hbm)
  536. {
  537. DeleteObject(hbm);
  538. }
  539. else
  540. {
  541. // We are totally out of luck today aren't we
  542. Log(LOG_TMBITMAP, L"Failed to clear stock bitmap on cleanup");
  543. }
  544. }
  545. }
  546. _StockBitmapCleanupList.RemoveAll();
  547. }
  548. //---------------------------------------------------------------------------
  549. HRESULT CThemeParser::ParseColorValue(int iSymType, COLORREF *pcrValue, COLORREF *pcrValue2)
  550. {
  551. COLORREF color;
  552. HRESULT hr = S_OK;
  553. #if 0
  554. if (_scan.GetId(idbuff)) // system color
  555. {
  556. hr = ParseSysColor(idbuff, &color);
  557. if (FAILED(hr))
  558. goto exit;
  559. }
  560. else
  561. #endif
  562. {
  563. const WCHAR *parts[] = {L"r", L"g", L"b"};
  564. int ints[3] = {0};
  565. hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 255);
  566. if (FAILED(hr))
  567. {
  568. hr = SourceError(PARSER_IDS_BAD_COLOR_VALUE);
  569. goto exit;
  570. }
  571. color = RGB(ints[0], ints[1], ints[2]);
  572. }
  573. if (! _fDefiningColorScheme)
  574. color = ApplyColorSubstitution(color);
  575. if (_fDefiningMetrics)
  576. {
  577. if ((iSymType < TMT_FIRSTCOLOR) || (iSymType > TMT_LASTCOLOR))
  578. {
  579. hr = SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  580. goto exit;
  581. }
  582. }
  583. if (pcrValue2)
  584. {
  585. *pcrValue2 = color;
  586. }
  587. if (pcrValue) // special call
  588. *pcrValue = color;
  589. else
  590. {
  591. hr = AddThemeData(iSymType, TMT_COLOR, &color, sizeof(color));
  592. if (FAILED(hr))
  593. goto exit;
  594. }
  595. exit:
  596. return hr;
  597. }
  598. //---------------------------------------------------------------------------
  599. HRESULT CThemeParser::ParseMarginsValue(int iSymType)
  600. {
  601. const WCHAR *parts[] = {L"lw", L"rw", L"th", L"bh"};
  602. int ints[4];
  603. HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0);
  604. if (FAILED(hr))
  605. return SourceError(PARSER_IDS_BAD_MARGINS_VALUE);
  606. hr = AddThemeData(iSymType, TMT_MARGINS, ints, sizeof(ints));
  607. if (FAILED(hr))
  608. return hr;
  609. return S_OK;
  610. }
  611. //---------------------------------------------------------------------------
  612. HRESULT CThemeParser::ParseIntListValue(int iSymType)
  613. {
  614. INTLIST IntList;
  615. HRESULT hr = S_OK;
  616. //---- unnamed parts ----
  617. for (int i=0; i < MAX_INTLIST_COUNT; i++)
  618. {
  619. if (! _scan.GetNumber(&IntList.iValues[i]))
  620. {
  621. if (_scan.EndOfLine())
  622. break;
  623. hr = SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p);
  624. goto exit;
  625. }
  626. _scan.GetChar(','); // optional comma
  627. }
  628. IntList.iValueCount = i;
  629. hr = AddThemeData(iSymType, TMT_INTLIST, &IntList, (1+i)*sizeof(int));
  630. if (FAILED(hr))
  631. goto exit;
  632. exit:
  633. return hr;
  634. }
  635. //---------------------------------------------------------------------------
  636. HRESULT CThemeParser::PackageNtlCode(LPCWSTR szFileName)
  637. {
  638. #if 0 // not yet supported
  639. HRESULT hr = S_OK;
  640. RESOURCE WCHAR *pszSource = NULL;
  641. BYTE *pPCode = NULL;
  642. int iPCodeLen;
  643. CNtlParser NtlParser;
  644. //---- add TMT_NTLDATA data ----
  645. WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
  646. _wsplitpath(szFileName, drive, dir, fname, ext);
  647. WCHAR szResName[_MAX_PATH+1];
  648. wsprintf(szResName, L"%s_NTL", fname);
  649. hr = AllocateTextResource(_hinstThemeDll, szResName, &pszSource);
  650. if (FAILED(hr))
  651. goto exit;
  652. hr = NtlParser.ParseBuffer(pszSource, szFileName, this, &pPCode, &iPCodeLen);
  653. if (FAILED(hr))
  654. goto exit;
  655. hr = AddThemeData(TMT_NTLDATA, TMT_NTLDATA, pPCode, iPCodeLen);
  656. if (FAILED(hr))
  657. goto exit;
  658. exit:
  659. if (pszSource)
  660. delete [] pszSource;
  661. if (pPCode)
  662. delete [] pPCode;
  663. return hr;
  664. #else
  665. return E_NOTIMPL;
  666. #endif
  667. }
  668. //---------------------------------------------------------------------------
  669. HRESULT CThemeParser::PackageImageData(LPCWSTR szFileNameR, LPCWSTR szFileNameG, LPCWSTR szFileNameB, int iDibPropNum)
  670. {
  671. HRESULT hr = S_OK;
  672. //---- add TMT_DIBDATA data ----
  673. WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
  674. _wsplitpath(szFileNameR, drive, dir, fname, ext);
  675. WCHAR szResName[_MAX_PATH+1];
  676. DWORD len = lstrlen(dir);
  677. if ((len) && (dir[len-1] == L'\\'))
  678. {
  679. dir[len-1] = L'_';
  680. }
  681. wsprintf(szResName, L"%s%s_BMP", dir, fname);
  682. HBITMAP hBitmapR = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  683. if (!hBitmapR)
  684. return SourceError(PARSER_IDS_NOOPEN_IMAGE, szResName);
  685. //---- convert to DIBDATA ----
  686. CBitmapPixels pixels;
  687. DWORD *pPixelQuads;
  688. int iWidth, iHeight, iBytesPerPixel, iBytesPerRow, iPreviousBytesPerPixel;
  689. BOOL fUseDrawStream = TRUE;
  690. #if 0 // keep this in sync with #if in imagefile.cpp
  691. //---- force old code drawing ----
  692. fUseDrawStream = FALSE;
  693. #endif
  694. // Allocate a TMBITMAPHEADER in addition to the bitmap
  695. hr = pixels.OpenBitmap(NULL, hBitmapR, TRUE, &pPixelQuads, &iWidth, &iHeight, &iBytesPerPixel,
  696. &iBytesPerRow, &iPreviousBytesPerPixel, TMBITMAPSIZE);
  697. if (FAILED(hr))
  698. {
  699. DeleteObject(hBitmapR);
  700. return hr;
  701. }
  702. BOOL fWasAlpha = (iPreviousBytesPerPixel == 4);
  703. #if 0
  704. //---- apply loaded color scheme, if any ----
  705. if ((szFileNameG && szFileNameG[0]) && (szFileNameB && szFileNameB[0]))
  706. {
  707. _wsplitpath(szFileNameG, drive, dir, fname, ext);
  708. len = lstrlen(dir);
  709. if ((len) && (dir[len-1] == L'\\'))
  710. {
  711. dir[len-1] = L'_';
  712. }
  713. wsprintf(szResName, L"%s%s_BMP", dir, fname);
  714. HBITMAP hBitmapG = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  715. _wsplitpath(szFileNameB, drive, dir, fname, ext);
  716. len = lstrlen(dir);
  717. if ((len) && (dir[len-1] == L'\\'))
  718. {
  719. dir[len-1] = L'_';
  720. }
  721. wsprintf(szResName, L"%s%s_BMP", dir, fname);
  722. HBITMAP hBitmapB = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  723. DWORD dwRWeight = GetRValue(_crBlend);
  724. DWORD dwGWeight = GetGValue(_crBlend);
  725. DWORD dwBWeight = GetBValue(_crBlend);
  726. DWORD *pPixelQuadsG = NULL;
  727. DWORD *pPixelQuadsB = NULL;
  728. if (hBitmapG && hBitmapB)
  729. {
  730. HDC hdc = GetDC(NULL);
  731. if (hdc)
  732. {
  733. int dwLen = iWidth * iHeight;
  734. pPixelQuadsG = new DWORD[dwLen];
  735. if (pPixelQuadsG)
  736. {
  737. pPixelQuadsB = new DWORD[dwLen];
  738. if (pPixelQuadsB)
  739. {
  740. BITMAPINFO bi = {0};
  741. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  742. bi.bmiHeader.biWidth = iWidth;
  743. bi.bmiHeader.biHeight = iHeight;
  744. bi.bmiHeader.biPlanes = 1;
  745. bi.bmiHeader.biBitCount = 32;
  746. bi.bmiHeader.biCompression = BI_RGB;
  747. if (GetDIBits(hdc, hBitmapG, 0, iHeight, pPixelQuadsG, &bi, DIB_RGB_COLORS) &&
  748. GetDIBits(hdc, hBitmapB, 0, iHeight, pPixelQuadsB, &bi, DIB_RGB_COLORS))
  749. {
  750. DWORD* pdwR = pPixelQuads;
  751. DWORD* pdwG = pPixelQuadsG;
  752. DWORD* pdwB = pPixelQuadsB;
  753. for (int i = 0; i < dwLen; i++)
  754. {
  755. if ((*pdwR & 0xffffff) != RGB(255,0,255))
  756. {
  757. *pdwR = (*pdwR & 0xff000000) |
  758. RGB(min(((GetRValue(*pdwR) * dwRWeight) + (GetRValue(*pdwG) * dwGWeight) + (GetRValue(*pdwB) * dwBWeight)) >> 8, 0xff),
  759. min(((GetGValue(*pdwR) * dwRWeight) + (GetGValue(*pdwG) * dwGWeight) + (GetGValue(*pdwB) * dwBWeight)) >> 8, 0xff),
  760. min(((GetBValue(*pdwR) * dwRWeight) + (GetBValue(*pdwG) * dwGWeight) + (GetBValue(*pdwB) * dwBWeight)) >> 8, 0xff));
  761. }
  762. pdwR++;
  763. pdwG++;
  764. pdwB++;
  765. }
  766. }
  767. delete[] pPixelQuadsB;
  768. }
  769. delete[] pPixelQuadsG;
  770. }
  771. ReleaseDC(NULL, hdc);
  772. }
  773. }
  774. else
  775. {
  776. OutputDebugString(L"Failed to load bitmaps");
  777. }
  778. if (hBitmapG)
  779. {
  780. DeleteObject(hBitmapG);
  781. hBitmapG = NULL;
  782. }
  783. if (hBitmapB)
  784. {
  785. DeleteObject(hBitmapB);
  786. hBitmapB = NULL;
  787. }
  788. }
  789. #endif
  790. BITMAPINFOHEADER *pBitmapHdr = pixels._hdrBitmap;
  791. //---- if alpha present, pre-multiply RGB values (as per AlphaBlend()) API ----
  792. BOOL fTrueAlpha = FALSE;
  793. // We keep per-pixel alpha bitmaps as 32 bits DIBs, not compatible bitmaps
  794. if (fWasAlpha)
  795. {
  796. fTrueAlpha = (PreMultiplyAlpha(pPixelQuads, pBitmapHdr->biWidth, pBitmapHdr->biHeight) != 0);
  797. #ifdef DEBUG
  798. if (!fTrueAlpha)
  799. Log(LOG_TMBITMAP, L"%s is 32 bits, but not true alpha", szFileNameR);
  800. #endif
  801. }
  802. HBITMAP hbmStock = NULL;
  803. BOOL fFlipped = FALSE;
  804. if (fUseDrawStream && _fGlobalTheme)
  805. {
  806. HDC hdc = ::GetWindowDC(NULL);
  807. if (hdc)
  808. {
  809. typedef struct {
  810. BITMAPINFOHEADER bmih;
  811. ULONG masks[3];
  812. } BITMAPHEADER;
  813. BITMAPHEADER bmi;
  814. bmi.bmih.biSize = sizeof(bmi.bmih);
  815. bmi.bmih.biWidth = pBitmapHdr->biWidth;
  816. bmi.bmih.biHeight = pBitmapHdr->biHeight;
  817. bmi.bmih.biPlanes = 1;
  818. bmi.bmih.biBitCount = 32;
  819. bmi.bmih.biCompression = BI_BITFIELDS;
  820. bmi.bmih.biSizeImage = 0;
  821. bmi.bmih.biXPelsPerMeter = 0;
  822. bmi.bmih.biYPelsPerMeter = 0;
  823. bmi.bmih.biClrUsed = 3;
  824. bmi.bmih.biClrImportant = 0;
  825. bmi.masks[0] = 0xff0000; // red
  826. bmi.masks[1] = 0x00ff00; // green
  827. bmi.masks[2] = 0x0000ff; // blue
  828. hbmStock = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | CBM_CREATEDIB , pPixelQuads, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
  829. // Need to Force 32-bit DIBs in Multi-mon mode
  830. // Make it match the screen resolution setting if it is not an AlphaBlended image
  831. #if 0
  832. if (hbmStock && !fTrueAlpha && !GetSystemMetrics(SM_REMOTESESSION))
  833. {
  834. BOOL fForce16 = FALSE; //(iPreviousBytesPerPixel <= 2);
  835. HDC hdcTemp = CreateCompatibleDC(hdc);
  836. if (hdcTemp)
  837. {
  838. HBITMAP hbmTemp = CreateCompatibleBitmap(hdc, 2, 2);
  839. if (hbmTemp)
  840. {
  841. BITMAPINFOHEADER bi = {0};
  842. bi.biSize = sizeof(bi);
  843. GetDIBits(hdcTemp, hbmTemp, 0, 1, NULL, (LPBITMAPINFO) &bi, DIB_RGB_COLORS);
  844. /*WCHAR szTemp[256];
  845. wsprintf(szTemp, L"We're in %d-bit mode.\n", bi.biBitCount);
  846. OutputDebugString(szTemp);*/
  847. bmi.bmih.biSize = sizeof(bmi.bmih);
  848. bmi.bmih.biWidth = pBitmapHdr->biWidth;
  849. bmi.bmih.biHeight = pBitmapHdr->biHeight;
  850. bmi.bmih.biPlanes = 1;
  851. bmi.bmih.biBitCount = 32;
  852. bmi.bmih.biCompression = BI_BITFIELDS;
  853. bmi.bmih.biSizeImage = 0;
  854. bmi.bmih.biXPelsPerMeter = 0;
  855. bmi.bmih.biYPelsPerMeter = 0;
  856. bmi.bmih.biClrUsed = 3;
  857. bmi.bmih.biClrImportant = 0;
  858. if ((bi.biBitCount == 16) || (fForce16))
  859. {
  860. COLORREF crActual = 0;
  861. if (!fForce16)
  862. {
  863. HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTemp, hbmTemp);
  864. SetPixel(hdcTemp, 0, 0, RGB(0, 255, 0));
  865. crActual = GetPixel(hdcTemp, 0, 0);
  866. SelectObject(hdcTemp, hbmOld);
  867. }
  868. bmi.bmih.biBitCount = 16;
  869. if (fForce16 || (GetGValue(crActual) == 252))// Do a lame check for 5-6-5
  870. {
  871. bmi.masks[0] = 0xF800;
  872. bmi.masks[1] = 0x07E0;
  873. bmi.masks[2] = 0x001F;
  874. }
  875. else
  876. {
  877. bmi.masks[0] = 0x7C00; // 5-5-5 mode
  878. bmi.masks[1] = 0x03E0;
  879. bmi.masks[2] = 0x001F;
  880. }
  881. }
  882. else if (bi.biBitCount == 24)
  883. {
  884. bmi.bmih.biBitCount = 24;
  885. bmi.masks[0] = 0xff0000; // red
  886. bmi.masks[1] = 0x00ff00; // green
  887. bmi.masks[2] = 0x0000ff; // blue
  888. }
  889. if (bmi.bmih.biBitCount != 32)
  890. {
  891. HBITMAP hbmNewStock = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | CBM_CREATEDIB , pPixelQuads, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
  892. if (hbmNewStock)
  893. {
  894. HDC hdcNewStock = CreateCompatibleDC(hdc);
  895. if (hdcNewStock)
  896. {
  897. HBITMAP hbmOld = (HBITMAP)SelectObject(hdcNewStock, hbmNewStock);
  898. HBITMAP hbmOld2 = (HBITMAP)SelectObject(hdcTemp, hbmStock);
  899. BitBlt(hdcNewStock, 0, 0, pBitmapHdr->biWidth, pBitmapHdr->biHeight, hdcTemp, 0, 0, SRCCOPY);
  900. SelectObject(hdcTemp, hbmOld2);
  901. SelectObject(hdcNewStock, hbmOld);
  902. DeleteObject(hbmStock);
  903. hbmStock = hbmNewStock;
  904. }
  905. else
  906. {
  907. DeleteObject(hbmNewStock);
  908. }
  909. }
  910. }
  911. DeleteObject(hbmTemp);
  912. }
  913. DeleteDC(hdcTemp);
  914. }
  915. }
  916. #endif
  917. ::ReleaseDC(NULL, hdc);
  918. }
  919. if (!hbmStock)
  920. {
  921. hr = E_OUTOFMEMORY;
  922. }
  923. else
  924. {
  925. ASSERT(s_pfnSetBitmapAttributes != NULL);
  926. ASSERT(s_pfnClearBitmapAttributes != NULL);
  927. HBITMAP hbmOld = hbmStock;
  928. hbmStock = (*s_pfnSetBitmapAttributes)(hbmStock, SBA_STOCK);
  929. if (hbmStock == NULL)
  930. {
  931. DeleteObject(hbmOld);
  932. Log(LOG_ALWAYS, L"UxTheme: SetBitmapAttributes failed in CParser::PackageImageData");
  933. hr = E_FAIL;
  934. }
  935. else
  936. {
  937. _StockBitmapCleanupList.Add(hbmStock);
  938. #ifdef DEBUG
  939. BITMAP bm;
  940. ::GetObject(hbmStock, sizeof bm, &bm);
  941. g_dwStockSize += bm.bmWidthBytes * bm.bmHeight;
  942. //Log(LOG_TMBITMAP, L"Created %d bytes of stock bitmaps, last is %8X", g_dwStockSize, hbmStock);
  943. #endif
  944. }
  945. }
  946. }
  947. ::DeleteObject(hBitmapR);
  948. // Fill in the TMBITMAPHEADER structure
  949. if (SUCCEEDED(hr))
  950. {
  951. TMBITMAPHEADER *psbh = (TMBITMAPHEADER*) pixels.Buffer();
  952. psbh->dwSize = TMBITMAPSIZE;
  953. psbh->fFlipped = fFlipped;
  954. psbh->hBitmap = hbmStock;
  955. psbh->fTrueAlpha = fTrueAlpha;
  956. psbh->dwColorDepth = iBytesPerPixel * 8;
  957. psbh->iBrushesOffset = 0;
  958. psbh->nBrushes = 0;
  959. if (hbmStock == NULL) // Pass DIB bits
  960. {
  961. int size = psbh->dwSize + sizeof(BITMAPINFOHEADER) + iHeight * iBytesPerRow;
  962. hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, size);
  963. }
  964. else // Pass the TMBITMAPHEADER structure only
  965. {
  966. hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, psbh->dwSize);
  967. }
  968. }
  969. return hr;
  970. }
  971. //---------------------------------------------------------------------------
  972. HRESULT CThemeParser::ParseFileNameValue(int iSymType, LPWSTR pszBuff, DWORD dwMaxBuffChars)
  973. {
  974. WCHAR szFileNameR[_MAX_PATH+1] = {0};
  975. WCHAR szFileNameG[_MAX_PATH+1] = {0};
  976. WCHAR szFileNameB[_MAX_PATH+1] = {0};
  977. HRESULT hr = S_OK;
  978. if (! _scan.GetFileName(szFileNameR, ARRAYSIZE(szFileNameR)))
  979. {
  980. hr = SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED);
  981. goto exit;
  982. }
  983. if (_scan.GetFileName(szFileNameG, ARRAYSIZE(szFileNameG)))
  984. {
  985. _scan.GetFileName(szFileNameB, ARRAYSIZE(szFileNameB));
  986. }
  987. if (pszBuff) // special call
  988. {
  989. hr = hr_lstrcpy(pszBuff, szFileNameR, dwMaxBuffChars);
  990. if (FAILED(hr))
  991. goto exit;
  992. }
  993. else if (_pCallBackObj) // emit data
  994. {
  995. //---- add TMT_FILENAME data ----
  996. hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameR, sizeof(WCHAR)*(1+lstrlen(szFileNameR)));
  997. if (FAILED(hr))
  998. goto exit;
  999. if ((szFileNameG[0] != 0) && (szFileNameB[0] != 0))
  1000. {
  1001. hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameG, sizeof(WCHAR)*(1+lstrlen(szFileNameR)));
  1002. if (FAILED(hr))
  1003. goto exit;
  1004. hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameB, sizeof(WCHAR)*(1+lstrlen(szFileNameR)));
  1005. if (FAILED(hr))
  1006. goto exit;
  1007. }
  1008. if (iSymType == TMT_IMAGEFILE)
  1009. {
  1010. hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA);
  1011. }
  1012. else if (iSymType == TMT_GLYPHIMAGEFILE)
  1013. {
  1014. hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_GLYPHDIBDATA);
  1015. }
  1016. else if (iSymType == TMT_STOCKIMAGEFILE)
  1017. {
  1018. hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_STOCKDIBDATA);
  1019. }
  1020. else if ((iSymType >= TMT_IMAGEFILE1) && (iSymType <= TMT_IMAGEFILE5))
  1021. {
  1022. hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA1 + (iSymType-TMT_IMAGEFILE1));
  1023. }
  1024. #if 0 // not yet implemented
  1025. else if (iSymType == TMT_NTLFILE)
  1026. {
  1027. hr = PackageNtlCode(szFileNameR);
  1028. }
  1029. #endif
  1030. if (FAILED(hr))
  1031. goto exit;
  1032. }
  1033. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILENAMES))
  1034. {
  1035. BOOL fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameR, NULL, NULL, iSymType, _lNameParam);
  1036. if (! fContinue)
  1037. {
  1038. hr = MakeErrorParserLast();
  1039. goto exit;
  1040. }
  1041. if (szFileNameG[0] && szFileNameB[0])
  1042. {
  1043. fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameG, NULL, NULL, iSymType, _lNameParam);
  1044. if (! fContinue)
  1045. {
  1046. hr = MakeErrorParserLast();
  1047. goto exit;
  1048. }
  1049. fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameB, NULL, NULL, iSymType, _lNameParam);
  1050. if (! fContinue)
  1051. {
  1052. hr = MakeErrorParserLast();
  1053. goto exit;
  1054. }
  1055. }
  1056. }
  1057. exit:
  1058. return hr;
  1059. }
  1060. //---------------------------------------------------------------------------
  1061. HRESULT CThemeParser::ParseSizeValue(int iSymType)
  1062. {
  1063. int val;
  1064. if (! _scan.GetNumber(&val))
  1065. return SourceError(PARSER_IDS_INT_EXPECTED);
  1066. int pixels;
  1067. HRESULT hr = ParseSizeInfoUnits(val, L"pixels", &pixels);
  1068. if (FAILED(hr))
  1069. return hr;
  1070. if (_fDefiningMetrics)
  1071. {
  1072. if ((iSymType < TMT_FIRSTSIZE) || (iSymType > TMT_LASTSIZE))
  1073. return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  1074. }
  1075. hr = AddThemeData(iSymType, TMT_SIZE, &pixels, sizeof(pixels));
  1076. if (FAILED(hr))
  1077. return hr;
  1078. return S_OK;
  1079. }
  1080. //---------------------------------------------------------------------------
  1081. HRESULT CThemeParser::ParsePositionValue(int iSymType)
  1082. {
  1083. const WCHAR *parts[] = {L"x", L"y"};
  1084. int ints[2];
  1085. HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0);
  1086. if (FAILED(hr))
  1087. return SourceError(PARSER_IDS_ILLEGAL_SIZE_VALUE);
  1088. hr = AddThemeData(iSymType, TMT_POSITION, ints, sizeof(ints));
  1089. if (FAILED(hr))
  1090. return hr;
  1091. return S_OK;
  1092. }
  1093. //---------------------------------------------------------------------------
  1094. HRESULT CThemeParser::ParseRectValue(int iSymType, LPCWSTR pszPropertyName)
  1095. {
  1096. const WCHAR *parts[] = {L"l", L"t", L"r", L"b"};
  1097. int ints[4];
  1098. HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0);
  1099. if (FAILED(hr))
  1100. return SourceError(PARSER_IDS_ILLEGAL_RECT_VALUE);
  1101. //---- special handling for localizable RECT properties ----
  1102. if (iSymType == TMT_DEFAULTPANESIZE)
  1103. {
  1104. //---- handle localizable callback (packtime) ----
  1105. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS))
  1106. {
  1107. BOOL fContinue = (*_pNameCallBack)(TCB_LOCALIZABLE_RECT, _szClassName,
  1108. _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)(RECT *)ints);
  1109. if (! fContinue)
  1110. return MakeErrorParserLast();
  1111. }
  1112. //---- handle getting value from string table (loadtime) ----
  1113. if (_fUsingResourceProperties) // substitute resource value
  1114. {
  1115. WCHAR szValue[MAX_PATH];
  1116. HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue));
  1117. if (SUCCEEDED(hr))
  1118. {
  1119. RECT rc;
  1120. int cnt = swscanf(szValue, L"%d, %d, %d, %d",
  1121. &rc.left, &rc.top, &rc.right, &rc.bottom);
  1122. if (cnt == 4)
  1123. {
  1124. //---- override with localized values ----
  1125. memcpy(ints, &rc, sizeof(int)*4);
  1126. }
  1127. }
  1128. else
  1129. {
  1130. hr = S_OK; // non-fatal error
  1131. }
  1132. }
  1133. }
  1134. hr = AddThemeData(iSymType, TMT_RECT, ints, sizeof(ints));
  1135. if (FAILED(hr))
  1136. return hr;
  1137. return S_OK;
  1138. }
  1139. //---------------------------------------------------------------------------
  1140. HRESULT CThemeParser::ParseSizeInfoUnits(int iVal, LPCWSTR pszDefaultUnits, int *piPixels)
  1141. {
  1142. WCHAR units[_MAX_PATH+1];
  1143. HRESULT hr;
  1144. //---- NOTE: this uses the THEME_DPI (96) for all size conversions! ----
  1145. //---- this gives us consistent LOGFONT, etc. across diff. resolution screens ----
  1146. //---- with the promise that we will do just-in-time DPI scaling, when appropriate ----
  1147. if (! _scan.GetId(units))
  1148. {
  1149. hr = hr_lstrcpy(units, pszDefaultUnits, ARRAYSIZE(units));
  1150. if (FAILED(hr))
  1151. return hr;
  1152. }
  1153. if (AsciiStrCmpI(units, L"pixels")==0)
  1154. ; // already correct
  1155. else if (AsciiStrCmpI(units, L"twips")==0)
  1156. {
  1157. iVal = -MulDiv(iVal, THEME_DPI, 20*72);
  1158. }
  1159. else if (AsciiStrCmpI(units, L"points")==0)
  1160. {
  1161. iVal = -MulDiv(iVal, THEME_DPI, 72);
  1162. }
  1163. else
  1164. return SourceError(PARSER_IDS_UNKNOWN_SIZE_UNITS, units);
  1165. *piPixels = iVal;
  1166. return S_OK;
  1167. }
  1168. //---------------------------------------------------------------------------
  1169. HRESULT CThemeParser::ParseSysColor(LPCWSTR szId, COLORREF *pcrValue)
  1170. {
  1171. if (! _scan.EndOfLine())
  1172. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1173. //---- look up value of id ----
  1174. int index = GetSymbolIndex(szId);
  1175. if (index == -1)
  1176. return SourceError(PARSER_IDS_UNKNOWN_SYS_COLOR);
  1177. int iPropNum = _Symbols[index].sTypeNum;
  1178. if ((iPropNum < TMT_FIRSTCOLOR) || (iPropNum > TMT_LASTCOLOR))
  1179. return SourceError(PARSER_IDS_UNKNOWN_SYS_COLOR);
  1180. *pcrValue = GetSysColor(iPropNum-TMT_FIRSTCOLOR);
  1181. return S_OK;
  1182. }
  1183. //---------------------------------------------------------------------------
  1184. HRESULT CThemeParser::ParseSysFont(LOGFONT *pFont)
  1185. {
  1186. if (! _scan.GetChar('['))
  1187. return SourceError(PARSER_IDS_LBRACKET_EXPECTED);
  1188. WCHAR idbuff[_MAX_PATH+1];
  1189. if (! _scan.GetId(idbuff))
  1190. return SourceError(PARSER_IDS_EXPECTED_SYSFONT_ID);
  1191. if (! _scan.GetChar(']'))
  1192. return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
  1193. if (! _scan.EndOfLine())
  1194. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1195. //---- look up value of id ----
  1196. int index = GetSymbolIndex(idbuff);
  1197. if (index == -1)
  1198. return SourceError(PARSER_IDS_UNKNOWN_SYSFONT_ID);
  1199. if ((index < TMT_FIRSTFONT) || (index > TMT_LASTFONT))
  1200. return SourceError(PARSER_IDS_EXPECTED_SYSFONT_ID);
  1201. //---- get value of specified font ----
  1202. NONCLIENTMETRICS metrics;
  1203. memset(&metrics, 0, sizeof(metrics));
  1204. metrics.cbSize = sizeof(metrics);
  1205. BOOL gotem = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(metrics),
  1206. &metrics, 0);
  1207. if (! gotem)
  1208. return MakeErrorLast();
  1209. switch (index)
  1210. {
  1211. case TMT_CAPTIONFONT:
  1212. *pFont = metrics.lfCaptionFont;
  1213. break;
  1214. case TMT_SMALLCAPTIONFONT:
  1215. *pFont = metrics.lfSmCaptionFont;
  1216. break;
  1217. case TMT_MENUFONT:
  1218. *pFont = metrics.lfMenuFont;
  1219. break;
  1220. case TMT_STATUSFONT:
  1221. *pFont = metrics.lfStatusFont;
  1222. break;
  1223. case TMT_MSGBOXFONT:
  1224. *pFont = metrics.lfMessageFont;
  1225. break;
  1226. }
  1227. return S_OK;
  1228. }
  1229. //---------------------------------------------------------------------------
  1230. HRESULT CThemeParser::ParseFontValue(int iSymType, LPCWSTR pszPropertyName)
  1231. {
  1232. LOGFONT font;
  1233. WCHAR szLineBuff[_MAX_PATH+1];
  1234. HRESULT hr;
  1235. _scan.SkipSpaces(); // trim leading blanks
  1236. memset(&font, 0, sizeof(font));
  1237. font.lfWeight = FW_NORMAL;
  1238. font.lfCharSet = _uCharSet;
  1239. #if 0 // turned off until we finalize design
  1240. if (_scan.GetKeyword(L"SysFont"))
  1241. {
  1242. hr = ParseSysFont(&font);
  1243. if (FAILED(hr))
  1244. return hr;
  1245. goto addit;
  1246. }
  1247. #endif
  1248. _iFontNumber++;
  1249. BOOL fGotFont = FALSE;
  1250. if (_fUsingResourceProperties) // substitute resource font string
  1251. {
  1252. hr = GetResourceProperty(pszPropertyName, szLineBuff, ARRAYSIZE(szLineBuff));
  1253. if (SUCCEEDED(hr))
  1254. {
  1255. fGotFont = TRUE;
  1256. }
  1257. else
  1258. {
  1259. hr = S_OK;
  1260. }
  1261. }
  1262. if (! fGotFont)
  1263. {
  1264. //---- copy font specs from scanner ----
  1265. hr = hr_lstrcpy(szLineBuff, _scan._p, ARRAYSIZE(szLineBuff));
  1266. if (FAILED(hr))
  1267. return hr;
  1268. }
  1269. //---- handle font callback ----
  1270. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS))
  1271. {
  1272. WCHAR *p = szLineBuff;
  1273. while (IsSpace(*p))
  1274. p++;
  1275. BOOL fContinue = (*_pNameCallBack)(TCB_FONT, p, _szFullSectionName,
  1276. pszPropertyName, 0, _lNameParam);
  1277. if (! fContinue)
  1278. return MakeErrorParserLast();
  1279. }
  1280. //---- family name is required and must be first ----
  1281. WCHAR *p;
  1282. p = wcschr(szLineBuff, ',');
  1283. if (! p) // whole line is family name
  1284. {
  1285. hr = hr_lstrcpy(font.lfFaceName, szLineBuff, ARRAYSIZE(font.lfFaceName));
  1286. return hr;
  1287. }
  1288. *p++ = 0;
  1289. hr = hr_lstrcpy(font.lfFaceName, szLineBuff, ARRAYSIZE(font.lfFaceName));
  1290. if (FAILED(hr))
  1291. return hr;
  1292. _scan._p = p;
  1293. int val;
  1294. if (_scan.GetNumber(&val)) // font size
  1295. {
  1296. int pixels;
  1297. hr = ParseSizeInfoUnits(val, L"points", &pixels);
  1298. if (FAILED(hr))
  1299. return hr;
  1300. font.lfHeight = pixels;
  1301. _scan.GetChar(','); // optional comma
  1302. }
  1303. WCHAR flagname[_MAX_PATH+1];
  1304. while (_scan.GetId(flagname))
  1305. {
  1306. if (AsciiStrCmpI(flagname, L"bold")==0)
  1307. font.lfWeight = FW_BOLD;
  1308. else if (AsciiStrCmpI(flagname, L"italic")==0)
  1309. font.lfItalic = TRUE;
  1310. else if (AsciiStrCmpI(flagname, L"underline")==0)
  1311. font.lfUnderline = TRUE;
  1312. else if (AsciiStrCmpI(flagname, L"strikeout")==0)
  1313. font.lfStrikeOut = TRUE;
  1314. else
  1315. return SourceError(PARSER_IDS_UNKNOWN_FONT_FLAG, flagname);
  1316. }
  1317. // addit:
  1318. if (_fDefiningMetrics)
  1319. {
  1320. if ((iSymType < TMT_FIRSTFONT) || (iSymType > TMT_LASTFONT))
  1321. return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
  1322. }
  1323. hr = AddThemeData(iSymType, TMT_FONT, &font, sizeof(font));
  1324. if (FAILED(hr))
  1325. return hr;
  1326. return S_OK;
  1327. }
  1328. //---------------------------------------------------------------------------
  1329. HRESULT CThemeParser::ParseClassLine(int *piSymType, int *piValue, LPWSTR pszBuff, DWORD dwMaxBuffChars)
  1330. {
  1331. WCHAR szNameBuff[_MAX_PATH+1];
  1332. WCHAR szSymbol[MAX_INPUT_LINE+1];
  1333. if (! _scan.GetId(szNameBuff))
  1334. return SourceError(PARSER_IDS_EXPECTED_PROP_NAME);
  1335. if (! _scan.GetChar('='))
  1336. return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN);
  1337. int cnt = _Symbols.GetSize();
  1338. for (int i=0; i < cnt; i++)
  1339. {
  1340. if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0)
  1341. break;
  1342. }
  1343. if (i == cnt)
  1344. return SourceError(PARSER_IDS_UNKNOWN_PROP, szNameBuff);
  1345. int symtype = _Symbols[i].sTypeNum;
  1346. HRESULT hr;
  1347. // Handle substituted symbols
  1348. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS))
  1349. {
  1350. if (wcschr(_scan._p, INI_MACRO_SYMBOL))
  1351. {
  1352. // Pass ##
  1353. if (_scan.GetChar(INI_MACRO_SYMBOL) &&
  1354. _scan.GetChar(INI_MACRO_SYMBOL))
  1355. {
  1356. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
  1357. _wsplitpath(_scan._szFileName, szDrive, szDir, szBaseName, szExt);
  1358. BOOL fContinue = (*_pNameCallBack)(TCB_NEEDSUBST, szBaseName, _scan._p, szSymbol,
  1359. 0, _lNameParam);
  1360. if (! fContinue)
  1361. return MakeErrorParserLast();
  1362. _scan.UseSymbol(szSymbol);
  1363. }
  1364. }
  1365. }
  1366. switch (_Symbols[i].ePrimVal)
  1367. {
  1368. case TMT_ENUM:
  1369. hr = ParseEnumValue(symtype);
  1370. break;
  1371. case TMT_STRING:
  1372. hr = ParseStringValue(symtype, pszBuff, dwMaxBuffChars);
  1373. break;
  1374. case TMT_INT:
  1375. hr = ParseIntValue(symtype, piValue);
  1376. break;
  1377. case TMT_INTLIST:
  1378. hr = ParseIntListValue(symtype);
  1379. break;
  1380. case TMT_BOOL:
  1381. hr = ParseBoolValue(symtype, szNameBuff);
  1382. break;
  1383. case TMT_COLOR:
  1384. {
  1385. COLORREF cr;
  1386. hr = ParseColorValue(symtype, (COLORREF *)piValue, &cr);
  1387. if (SUCCEEDED(hr))
  1388. {
  1389. if (lstrcmpi(_Symbols[i].csName, L"BLENDCOLOR") == 0)
  1390. {
  1391. _crBlend = cr;
  1392. }
  1393. }
  1394. }
  1395. break;
  1396. case TMT_MARGINS:
  1397. hr = ParseMarginsValue(symtype);
  1398. break;
  1399. case TMT_FILENAME:
  1400. hr = ParseFileNameValue(symtype, pszBuff, dwMaxBuffChars);
  1401. break;
  1402. case TMT_SIZE:
  1403. hr = ParseSizeValue(symtype);
  1404. break;
  1405. case TMT_POSITION:
  1406. hr = ParsePositionValue(symtype);
  1407. break;
  1408. case TMT_RECT:
  1409. hr = ParseRectValue(symtype, szNameBuff);
  1410. break;
  1411. case TMT_FONT:
  1412. hr = ParseFontValue(symtype, szNameBuff);
  1413. break;
  1414. default:
  1415. hr = E_FAIL;
  1416. break;
  1417. }
  1418. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS))
  1419. {
  1420. _scan.UseSymbol(NULL);
  1421. }
  1422. *_szResPropValue = 0; // not yet set
  1423. if (FAILED(hr))
  1424. return hr;
  1425. if (piSymType) // special call
  1426. *piSymType = symtype;
  1427. if (! _scan.EndOfLine())
  1428. return SourceError(PARSER_IDS_EXTRA_PROP_TEXT, _scan._p);
  1429. _scan.ForceNextLine();
  1430. return S_OK;
  1431. }
  1432. //---------------------------------------------------------------------------
  1433. HRESULT CThemeParser::ParseColorSchemeSection()
  1434. {
  1435. HRESULT hr;
  1436. WCHAR SchemeName[_MAX_PATH+1];
  1437. WCHAR DisplayName[_MAX_PATH+1];
  1438. WCHAR ToolTip[MAX_INPUT_LINE+1];
  1439. WCHAR szBuff[MAX_INPUT_LINE+1];
  1440. if (! _scan.GetChar('.'))
  1441. return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
  1442. if (! _scan.GetId(SchemeName, ARRAYSIZE(SchemeName)))
  1443. return SourceError(PARSER_IDS_CS_NAME_EXPECTED);
  1444. if (! _scan.GetChar(']'))
  1445. return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
  1446. if (! _scan.EndOfLine())
  1447. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1448. _scan.ForceNextLine(); // get line after section line
  1449. *ToolTip = 0;
  1450. *DisplayName = 0;
  1451. bool fCorrectScheme = (lstrcmpi(_ColorParam, SchemeName)==0);
  1452. if (fCorrectScheme) // initialize all subst. tables
  1453. {
  1454. hr = hr_lstrcpy(DisplayName, SchemeName, ARRAYSIZE(DisplayName)); // in case not specified
  1455. if (FAILED(hr))
  1456. return hr;
  1457. for (int i=0; i < HUE_SUBCNT; i++)
  1458. {
  1459. _bFromHues[i] = 0;
  1460. _bToHues[i] = 0;
  1461. }
  1462. for (i=0; i < COLOR_SUBCNT; i++)
  1463. {
  1464. _crFromColors[i] = 0;
  1465. _crToColors[i] = 0;
  1466. }
  1467. }
  1468. //----- put into vars to make coding/debugging easier ----
  1469. int firstFromHue = TMT_FROMHUE1;
  1470. int lastFromHue = TMT_FROMHUE1 + HUE_SUBCNT - 1;
  1471. int firstToHue = TMT_TOHUE1;
  1472. int lastToHue = TMT_TOHUE1 + HUE_SUBCNT - 1;
  1473. int firstFromColor = TMT_FROMCOLOR1;
  1474. int lastFromColor = TMT_FROMCOLOR1 + COLOR_SUBCNT - 1;
  1475. int firstToColor = TMT_TOCOLOR1;
  1476. int lastToColor = TMT_TOCOLOR1 + COLOR_SUBCNT - 1;
  1477. while (1) // parse each line
  1478. {
  1479. if (_scan.EndOfFile())
  1480. break;
  1481. if (_scan.GetChar('[')) // start of new section
  1482. break;
  1483. int iSymType, iValue;
  1484. _fDefiningColorScheme = TRUE;
  1485. //---- parse the COLOR or INT property line ----
  1486. hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff));
  1487. _fDefiningColorScheme = FALSE;
  1488. if (FAILED(hr))
  1489. return hr;
  1490. //---- store the HUE or COLOR param in local tables ----
  1491. if ((iSymType >= firstFromHue) && (iSymType <= lastFromHue))
  1492. {
  1493. if (fCorrectScheme)
  1494. _bFromHues[iSymType-firstFromHue] = (BYTE)iValue;
  1495. }
  1496. else if ((iSymType >= firstToHue) && (iSymType <= lastToHue))
  1497. {
  1498. if (fCorrectScheme)
  1499. _bToHues[iSymType-firstToHue] = (BYTE)iValue;
  1500. }
  1501. else if ((iSymType >= firstFromColor) && (iSymType <= lastFromColor))
  1502. {
  1503. if (fCorrectScheme)
  1504. _crFromColors[iSymType-firstFromColor] = (COLORREF)iValue;
  1505. }
  1506. else if ((iSymType >= firstToColor) && (iSymType <= lastToColor))
  1507. {
  1508. if (fCorrectScheme)
  1509. _crToColors[iSymType-firstToColor] = (COLORREF)iValue;
  1510. }
  1511. else if (iSymType == TMT_DISPLAYNAME)
  1512. {
  1513. hr = hr_lstrcpy(DisplayName, szBuff, ARRAYSIZE(DisplayName));
  1514. if (FAILED(hr))
  1515. return hr;
  1516. }
  1517. else if (iSymType == TMT_TOOLTIP)
  1518. {
  1519. hr = hr_lstrcpy(ToolTip, szBuff, ARRAYSIZE(ToolTip));
  1520. if (FAILED(hr))
  1521. return hr;
  1522. }
  1523. else
  1524. {
  1525. return SourceError(PARSER_IDS_ILLEGAL_CS_PROPERTY);
  1526. }
  1527. }
  1528. if (fCorrectScheme) // adjust counts
  1529. {
  1530. _iHueCount = HUE_SUBCNT;
  1531. while (_iHueCount > 0)
  1532. {
  1533. if (_bFromHues[_iHueCount-1] == _bToHues[_iHueCount-1])
  1534. _iHueCount--;
  1535. else
  1536. break;
  1537. }
  1538. _iColorCount = COLOR_SUBCNT;
  1539. while (_iColorCount > 0)
  1540. {
  1541. if (_crFromColors[_iColorCount-1] == _crToColors[_iColorCount-1])
  1542. _iColorCount--;
  1543. else
  1544. break;
  1545. }
  1546. }
  1547. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_COLORSECTION))
  1548. {
  1549. BOOL fContinue = (*_pNameCallBack)(TCB_COLORSCHEME, SchemeName,
  1550. DisplayName, ToolTip, 0, _lNameParam);
  1551. if (! fContinue)
  1552. return MakeErrorParserLast();
  1553. }
  1554. // Create an empty subst table
  1555. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE))
  1556. {
  1557. BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, SchemeName,
  1558. NULL, NULL, 0, _lNameParam);
  1559. if (! fContinue)
  1560. return MakeErrorParserLast();
  1561. }
  1562. return S_OK;
  1563. }
  1564. //---------------------------------------------------------------------------
  1565. HRESULT CThemeParser::ParseSizeSection()
  1566. {
  1567. HRESULT hr;
  1568. WCHAR szSizeName[_MAX_PATH+1];
  1569. WCHAR szDisplayName[_MAX_PATH+1];
  1570. WCHAR szToolTip[MAX_INPUT_LINE+1];
  1571. WCHAR szBuff[MAX_INPUT_LINE+1];
  1572. if (! _scan.GetChar('.'))
  1573. return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
  1574. if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName)))
  1575. return SourceError(PARSER_IDS_SS_NAME_EXPECTED);
  1576. if (! _scan.GetChar(']'))
  1577. return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
  1578. if (! _scan.EndOfLine())
  1579. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1580. _scan.ForceNextLine(); // get line after section line
  1581. while (1) // parse each line of section
  1582. {
  1583. if (_scan.EndOfFile())
  1584. break;
  1585. if (_scan.GetChar('[')) // start of new section
  1586. break;
  1587. int iSymType, iValue;
  1588. //---- parse the property line ----
  1589. hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff));
  1590. if (FAILED(hr))
  1591. return hr;
  1592. if (iSymType == TMT_DISPLAYNAME)
  1593. {
  1594. hr = hr_lstrcpy(szDisplayName, szBuff, ARRAYSIZE(szDisplayName));
  1595. if (FAILED(hr))
  1596. return hr;
  1597. }
  1598. else if (iSymType == TMT_TOOLTIP)
  1599. {
  1600. hr = hr_lstrcpy(szToolTip, szBuff, ARRAYSIZE(szToolTip));
  1601. if (FAILED(hr))
  1602. return hr;
  1603. }
  1604. else
  1605. {
  1606. return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY);
  1607. }
  1608. }
  1609. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SIZESECTION))
  1610. {
  1611. BOOL fContinue = (*_pNameCallBack)(TCB_SIZENAME, szSizeName,
  1612. szDisplayName, szToolTip, 0, _lNameParam);
  1613. if (! fContinue)
  1614. return MakeErrorParserLast();
  1615. }
  1616. // Create an empty subst table
  1617. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE))
  1618. {
  1619. BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName,
  1620. NULL, NULL, 0, _lNameParam);
  1621. if (! fContinue)
  1622. return MakeErrorParserLast();
  1623. }
  1624. return S_OK;
  1625. }
  1626. //---------------------------------------------------------------------------
  1627. HRESULT CThemeParser::ParseFileSection()
  1628. {
  1629. HRESULT hr;
  1630. WCHAR szSizeName[_MAX_PATH+1];
  1631. WCHAR szFileName[_MAX_PATH+1];
  1632. WCHAR szColorSchemes[_MAX_PATH+1];
  1633. WCHAR szSizes[MAX_INPUT_LINE+1];
  1634. WCHAR szBuff[MAX_INPUT_LINE+1];
  1635. if (! _scan.GetChar('.'))
  1636. return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
  1637. if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName)))
  1638. return SourceError(PARSER_IDS_FS_NAME_EXPECTED);
  1639. if (! _scan.GetChar(']'))
  1640. return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
  1641. if (! _scan.EndOfLine())
  1642. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1643. _scan.ForceNextLine(); // get line after section line
  1644. while (1) // parse each line of section
  1645. {
  1646. if (_scan.EndOfFile())
  1647. break;
  1648. if (_scan.GetChar('[')) // start of new section
  1649. break;
  1650. int iSymType, iValue;
  1651. //---- parse the property line ----
  1652. hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff));
  1653. if (FAILED(hr))
  1654. return hr;
  1655. if (iSymType == TMT_FILENAME)
  1656. {
  1657. hr = hr_lstrcpy(szFileName, szBuff, ARRAYSIZE(szFileName));
  1658. }
  1659. else if (iSymType == TMT_COLORSCHEMES)
  1660. {
  1661. hr = hr_lstrcpy(szColorSchemes, szBuff, ARRAYSIZE(szColorSchemes));
  1662. }
  1663. else if (iSymType == TMT_SIZES)
  1664. {
  1665. hr = hr_lstrcpy(szSizes, szBuff, ARRAYSIZE(szSizes));
  1666. }
  1667. else
  1668. {
  1669. return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY);
  1670. }
  1671. if (FAILED(hr))
  1672. return hr;
  1673. }
  1674. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILESECTION))
  1675. {
  1676. BOOL fContinue = (*_pNameCallBack)(TCB_CDFILENAME, szSizeName,
  1677. szFileName, NULL, 0, _lNameParam);
  1678. if (! fContinue)
  1679. return MakeErrorParserLast();
  1680. fContinue = (*_pNameCallBack)(TCB_CDFILECOMBO, szSizeName,
  1681. szColorSchemes, szSizes, 0, _lNameParam);
  1682. if (! fContinue)
  1683. return MakeErrorParserLast();
  1684. }
  1685. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE))
  1686. {
  1687. BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName,
  1688. SUBST_TABLE_INCLUDE, szColorSchemes, 0, _lNameParam);
  1689. if (! fContinue)
  1690. return MakeErrorParserLast();
  1691. fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName,
  1692. SUBST_TABLE_INCLUDE, szSizes, 0, _lNameParam);
  1693. if (! fContinue)
  1694. return MakeErrorParserLast();
  1695. }
  1696. return S_OK;
  1697. }
  1698. //---------------------------------------------------------------------------
  1699. HRESULT CThemeParser::ParseSubstSection()
  1700. {
  1701. WCHAR szSubstTableName[_MAX_PATH+1];
  1702. WCHAR szId[MAX_INPUT_LINE+1];
  1703. WCHAR szValue[MAX_INPUT_LINE+1];
  1704. BOOL fFirst = TRUE;
  1705. if (! _scan.GetChar('.'))
  1706. return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
  1707. if (! _scan.GetId(szSubstTableName, ARRAYSIZE(szSubstTableName)))
  1708. return SourceError(PARSER_IDS_FS_NAME_EXPECTED);
  1709. if (! _scan.GetChar(']'))
  1710. return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
  1711. if (! _scan.EndOfLine())
  1712. return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
  1713. _scan.ForceNextLine(); // get line after section line
  1714. while (1) // parse each line of section
  1715. {
  1716. if (_scan.EndOfFile())
  1717. break;
  1718. if (_scan.GetChar('[')) // start of new section
  1719. {
  1720. // Call the callback once for creating the empty table
  1721. if (fFirst && (_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE))
  1722. {
  1723. BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName,
  1724. NULL, NULL, 0, _lNameParam);
  1725. if (! fContinue)
  1726. return MakeErrorParserLast();
  1727. }
  1728. break;
  1729. }
  1730. //---- parse the property line ----
  1731. if (!_scan.GetIdPair(szId, szValue, ARRAYSIZE(szId)))
  1732. return SourceError(PARSER_IDS_BAD_SUBST_SYMBOL);
  1733. fFirst = FALSE;
  1734. _scan.ForceNextLine();
  1735. if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE))
  1736. {
  1737. BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName,
  1738. szId, szValue, 0, _lNameParam);
  1739. if (! fContinue)
  1740. return MakeErrorParserLast();
  1741. }
  1742. }
  1743. return S_OK;
  1744. }
  1745. //---------------------------------------------------------------------------
  1746. HRESULT CThemeParser::GenerateEmptySection(LPCWSTR pszSectionName, int iPartId, int iStateId)
  1747. {
  1748. int iStartIndex = 0;
  1749. if (_pCallBackObj)
  1750. iStartIndex = _pCallBackObj->GetNextDataIndex();
  1751. int index = 0; // will be updated later
  1752. HRESULT hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index));
  1753. if (FAILED(hr))
  1754. return hr;
  1755. if (_pCallBackObj)
  1756. {
  1757. int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex;
  1758. hr = _pCallBackObj->AddIndex(L"", pszSectionName, iPartId, iStateId,
  1759. iStartIndex, iLen);
  1760. if (FAILED(hr))
  1761. return hr;
  1762. }
  1763. return S_OK;
  1764. }
  1765. //---------------------------------------------------------------------------
  1766. HRESULT CThemeParser::ParseClassSection(LPCWSTR pszFirstName)
  1767. {
  1768. HRESULT hr;
  1769. int iStartIndex = 0;
  1770. BOOL fGlobals = (AsciiStrCmpI(pszFirstName, GLOBALS_SECTION_NAME)==0);
  1771. BOOL fMetrics = (AsciiStrCmpI(pszFirstName, SYSMETRICS_SECTION_NAME)==0);
  1772. if (fGlobals)
  1773. {
  1774. if (_fClassSectionDefined)
  1775. return SourceError(PARSER_IDS_GLOBALS_MUST_BE_FIRST);
  1776. }
  1777. else // regular class section
  1778. {
  1779. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  1780. {
  1781. if (! _fGlobalsDefined) // insert an empty [fGlobals] section
  1782. {
  1783. hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0);
  1784. if (FAILED(hr))
  1785. return hr;
  1786. _fGlobalsDefined = true;
  1787. }
  1788. if ((! fMetrics) && (! _fMetricsDefined)) // insert an empty [sysmetrics] section
  1789. {
  1790. hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0);
  1791. if (FAILED(hr))
  1792. return hr;
  1793. _fMetricsDefined = true;
  1794. }
  1795. else if ((fMetrics) && (_fClassSectionDefined))
  1796. return SourceError(PARSER_IDS_METRICS_MUST_COME_BEFORE_CLASSES);
  1797. }
  1798. _fClassSectionDefined = TRUE;
  1799. }
  1800. WCHAR appsym[_MAX_PATH+1];
  1801. if (_pCallBackObj)
  1802. iStartIndex = _pCallBackObj->GetNextDataIndex();
  1803. hr = ParseClassSectionName(pszFirstName, appsym);
  1804. if (FAILED(hr))
  1805. return hr;
  1806. _scan.ForceNextLine(); // get line after section line
  1807. while (1) // parse each line
  1808. {
  1809. if (_scan.EndOfFile())
  1810. break;
  1811. if (_scan.GetChar('[')) // start of new section
  1812. break;
  1813. hr = ParseClassLine();
  1814. if (FAILED(hr))
  1815. return hr;
  1816. }
  1817. //---- end this section of theme data ----
  1818. int index = 0; // will be updated later
  1819. hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index));
  1820. if (FAILED(hr))
  1821. return hr;
  1822. if (_pCallBackObj)
  1823. {
  1824. int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex;
  1825. hr = _pCallBackObj->AddIndex(appsym, _szClassName, _iPartId,
  1826. _iStateId, iStartIndex, iLen);
  1827. if (FAILED(hr))
  1828. return hr;
  1829. }
  1830. if (fGlobals)
  1831. _fGlobalsDefined = true;
  1832. else if (fMetrics)
  1833. _fMetricsDefined = true;
  1834. return S_OK;
  1835. }
  1836. //---------------------------------------------------------------------------
  1837. HRESULT CThemeParser::ParseThemeFile(LPCTSTR pszFileName, LPCWSTR pszColorParam,
  1838. IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags)
  1839. {
  1840. _pszDocProperty = NULL;
  1841. HRESULT hr = InitializeSymbols();
  1842. if (FAILED(hr))
  1843. goto exit;
  1844. hr = _scan.AttachFile(pszFileName); // "pszBuffer" contains the filename
  1845. if (FAILED(hr))
  1846. goto exit;
  1847. if (pszColorParam)
  1848. {
  1849. hr = hr_lstrcpy(_ColorParam, pszColorParam, ARRAYSIZE(_ColorParam));
  1850. if (FAILED(hr))
  1851. return hr;
  1852. }
  1853. else
  1854. *_ColorParam = 0;
  1855. _hinstThemeDll = NULL;
  1856. hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags);
  1857. exit:
  1858. return hr;
  1859. }
  1860. //---------------------------------------------------------------------------
  1861. HRESULT CThemeParser::ParseThemeBuffer(LPCWSTR pszBuffer, LPCWSTR pszFileName,
  1862. LPCWSTR pszColorParam, HINSTANCE hinstThemeDll,
  1863. IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack,
  1864. LPARAM lNameParam, DWORD dwParseFlags, LPCWSTR pszDocProperty, OUT LPWSTR pszResult,
  1865. DWORD dwMaxResultChars)
  1866. {
  1867. _pszDocProperty = pszDocProperty;
  1868. _pszResult = pszResult;
  1869. //---- initialize in case not found ----
  1870. if (_pszResult)
  1871. *_pszResult = 0;
  1872. _dwMaxResultChars = dwMaxResultChars;
  1873. HRESULT hr = InitializeSymbols();
  1874. if (FAILED(hr))
  1875. goto exit;
  1876. _hinstThemeDll = hinstThemeDll;
  1877. _scan.AttachMultiLineBuffer(pszBuffer, pszFileName);
  1878. if (pszColorParam)
  1879. {
  1880. hr = hr_lstrcpy(_ColorParam, pszColorParam, ARRAYSIZE(_ColorParam));
  1881. if (FAILED(hr))
  1882. return hr;
  1883. }
  1884. else
  1885. *_ColorParam = 0;
  1886. hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags);
  1887. //---- make error if doc property not found ----
  1888. if ((SUCCEEDED(hr)) && (_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (! *_pszResult))
  1889. {
  1890. hr = MakeError32(ERROR_NOT_FOUND);
  1891. }
  1892. exit:
  1893. return hr;
  1894. }
  1895. //---------------------------------------------------------------------------
  1896. HRESULT CThemeParser::LoadResourceProperties()
  1897. {
  1898. WCHAR szFullString[2*MAX_PATH];
  1899. WCHAR szBaseIniName[_MAX_PATH];
  1900. HRESULT hr = S_OK;
  1901. //---- extract base .ini name ----
  1902. WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], ext[_MAX_EXT];
  1903. _wsplitpath(_scan._szFileName, drive, dir, szBaseIniName, ext);
  1904. //---- remove optional "_INI" part ----
  1905. LPWSTR pszExt = wcsstr(szBaseIniName, L"_INI");
  1906. if (pszExt)
  1907. *pszExt = 0;
  1908. //---- read all localizable property name/value pairs into memory ----
  1909. for (int i=RES_BASENUM_PROPVALUEPAIRS; ; i++)
  1910. {
  1911. if (! LoadString(_hinstThemeDll, i, szFullString, ARRAYSIZE(szFullString)))
  1912. {
  1913. //---- no more properties avail ----
  1914. break;
  1915. }
  1916. lstrcpy(_szResPropValue, szFullString); // for proper error reporting
  1917. _iResPropId = i;
  1918. //---- does this property belong to current file? ----
  1919. LPWSTR pszAtSign = wcschr(szFullString, '@');
  1920. if (! pszAtSign)
  1921. {
  1922. hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY);
  1923. break;
  1924. }
  1925. //---- zero terminate ini name ----
  1926. *pszAtSign = 0;
  1927. if (lstrcmpi(szBaseIniName, szFullString) != 0)
  1928. continue;
  1929. //---- strip off the .ini name for faster comparing ----
  1930. LPCWSTR pszName = pszAtSign+1;
  1931. LPWSTR pszValue = wcschr(pszName, '=');
  1932. if (pszValue)
  1933. {
  1934. pszValue++; // skip over equals sign
  1935. }
  1936. else
  1937. {
  1938. hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY);
  1939. break;
  1940. }
  1941. //---- add the value ----
  1942. CWideString cwValue(pszValue);
  1943. _PropertyValues.Add(cwValue);
  1944. //---- zero-terminate the name ----
  1945. *pszValue = 0;
  1946. //---- add the name ----
  1947. CWideString cwName(pszName);
  1948. _PropertyNames.Add(cwName);
  1949. //---- add the id ----
  1950. _iPropertyIds.Add(i);
  1951. }
  1952. return hr;
  1953. }
  1954. //---------------------------------------------------------------------------
  1955. void CThemeParser::EmptyResourceProperties()
  1956. {
  1957. _PropertyNames.RemoveAll();
  1958. _PropertyValues.RemoveAll();
  1959. }
  1960. //---------------------------------------------------------------------------
  1961. HRESULT CThemeParser::GetResourceProperty(LPCWSTR pszPropName, LPWSTR pszValueBuff,
  1962. int cchMaxValueChars)
  1963. {
  1964. WCHAR szPropTarget[2*MAX_PATH];
  1965. HRESULT hr = S_OK;
  1966. BOOL fFound = FALSE;
  1967. wsprintf(szPropTarget, L"[%s]%s=", _szFullSectionName, pszPropName);
  1968. for (int i=0; i < _PropertyNames.m_nSize; i++)
  1969. {
  1970. if (AsciiStrCmpI(szPropTarget, _PropertyNames[i])==0)
  1971. {
  1972. fFound = TRUE;
  1973. hr = hr_lstrcpy(pszValueBuff, _PropertyValues[i], cchMaxValueChars);
  1974. if (SUCCEEDED(hr))
  1975. {
  1976. hr = hr_lstrcpy(_szResPropValue, _PropertyValues[i], ARRAYSIZE(_szResPropValue));
  1977. _iResPropId = _iPropertyIds[i];
  1978. }
  1979. break;
  1980. }
  1981. }
  1982. if (! fFound)
  1983. hr = E_FAIL;
  1984. return hr;
  1985. }
  1986. //---------------------------------------------------------------------------
  1987. HRESULT CThemeParser::ParseThemeScanner(IParserCallBack *pCallBack,
  1988. THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags)
  1989. {
  1990. HRESULT hr;
  1991. _pCallBackObj = pCallBack;
  1992. _pNameCallBack = pNameCallBack;
  1993. _lNameParam = lNameParam;
  1994. _dwParseFlags = dwParseFlags;
  1995. _fClassSectionDefined = FALSE;
  1996. //---- setup for properties in the .res file ----
  1997. EmptyResourceProperties();
  1998. _fUsingResourceProperties = (pCallBack != NULL);
  1999. if (_fUsingResourceProperties)
  2000. {
  2001. hr = LoadResourceProperties();
  2002. if (FAILED(hr))
  2003. goto exit;
  2004. //---- set the error context for normal .ini parsing ----
  2005. *_szResPropValue = 0; // not yet set
  2006. }
  2007. //---- scan the first, non-comment WCHAR ----
  2008. if (! _scan.GetChar('['))
  2009. {
  2010. if (! _scan.EndOfFile())
  2011. {
  2012. hr = SourceError(PARSER_IDS_LBRACKET_EXPECTED);
  2013. goto exit;
  2014. }
  2015. }
  2016. while (! _scan.EndOfFile()) // process each section
  2017. {
  2018. WCHAR section[_MAX_PATH+1];
  2019. _scan.GetId(section);
  2020. if (AsciiStrCmpI(section, L"documentation")==0)
  2021. {
  2022. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2023. return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
  2024. hr = ParseDocSection();
  2025. if (_dwParseFlags & PTF_QUERY_DOCPROPERTY)
  2026. break; // quicker to leave in middle of file
  2027. }
  2028. else if (AsciiStrCmpI(section, L"ColorScheme")==0)
  2029. {
  2030. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2031. return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
  2032. hr = ParseColorSchemeSection();
  2033. }
  2034. else if (AsciiStrCmpI(section, L"Size")==0)
  2035. {
  2036. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2037. return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
  2038. hr = ParseSizeSection();
  2039. }
  2040. else if (AsciiStrCmpI(section, L"File")==0)
  2041. {
  2042. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2043. return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
  2044. hr = ParseFileSection();
  2045. }
  2046. else if (AsciiStrCmpI(section, L"Subst")==0)
  2047. {
  2048. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2049. return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
  2050. hr = ParseSubstSection();
  2051. }
  2052. else // "globals", "sysmetrics", or class section
  2053. {
  2054. if (_dwParseFlags & PTF_CONTAINER_PARSE)
  2055. return SourceError(PARSER_IDS_BADSECT_THEMES_INI);
  2056. hr = ParseClassSection(section);
  2057. }
  2058. if (FAILED(hr))
  2059. goto exit;
  2060. }
  2061. //---- check for empty theme ----
  2062. if (_dwParseFlags & PTF_CLASSDATA_PARSE)
  2063. {
  2064. if (! _fGlobalsDefined) // insert an empty [fGlobals] section
  2065. {
  2066. hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0);
  2067. if (FAILED(hr))
  2068. return hr;
  2069. _fGlobalsDefined = true;
  2070. }
  2071. if (! _fMetricsDefined) // insert an empty [sysmetrics] section
  2072. {
  2073. hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0);
  2074. if (FAILED(hr))
  2075. return hr;
  2076. }
  2077. }
  2078. hr = S_OK;
  2079. exit:
  2080. _outfile.Close();
  2081. _pCallBackObj = NULL;
  2082. _pNameCallBack = NULL;
  2083. return hr;
  2084. }
  2085. //---------------------------------------------------------------------------
  2086. HRESULT CThemeParser::GetIntList(int *pInts, LPCWSTR *pParts, int iCount,
  2087. int iMin, int iMax)
  2088. {
  2089. bool bSet[255]; // assume 255 max ints
  2090. //---- ensure we set each one once ----
  2091. for (int i=0; i < iCount; i++)
  2092. bSet[i] = false;
  2093. if (wcschr(_scan._p, ':'))
  2094. {
  2095. //---- named parts ----
  2096. for (int i=0; i < iCount; i++)
  2097. {
  2098. WCHAR idbuff[_MAX_PATH+1];
  2099. if (! _scan.GetId(idbuff))
  2100. return SourceError(PARSER_IDS_VALUE_NAME_EXPECTED, _scan._p);
  2101. for (int j=0; j < iCount; j++)
  2102. {
  2103. if (AsciiStrCmpI(pParts[j], idbuff)==0)
  2104. break;
  2105. }
  2106. if (j == iCount) // unknown part name
  2107. return SourceError(PARSER_IDS_UNKNOWN_VALUE_NAME, idbuff);
  2108. if (bSet[j]) // name set twice
  2109. return SourceError(PARSER_IDS_VALUE_PART_SPECIFIED_TWICE, idbuff);
  2110. if (! _scan.GetChar(':'))
  2111. return SourceError(PARSER_IDS_COLOR_EXPECTED, _scan._p);
  2112. if (! _scan.GetNumber(&pInts[j]))
  2113. return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p);
  2114. bSet[j] = true;
  2115. _scan.GetChar(','); // optional comma
  2116. }
  2117. }
  2118. else
  2119. {
  2120. //---- unnamed parts ----
  2121. for (int i=0; i < iCount; i++)
  2122. {
  2123. if (! _scan.GetNumber(&pInts[i]))
  2124. return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p);
  2125. _scan.GetChar(','); // optional comma
  2126. }
  2127. }
  2128. //---- range check ----
  2129. if (iMin != iMax)
  2130. {
  2131. for (i=0; i < iCount; i++)
  2132. {
  2133. if ((pInts[i] < iMin) || (pInts[i] > iMax))
  2134. return SourceError(PARSER_IDS_NUMBER_OUT_OF_RANGE);
  2135. }
  2136. }
  2137. return S_OK;
  2138. }
  2139. //---------------------------------------------------------------------------
  2140. HRESULT CThemeParser::GetPropertyNum(LPCWSTR pszName, int *piPropNum)
  2141. {
  2142. //---- for perf, avoid loading all symbols each time this func is called ----
  2143. //---- by using "GetSchemaInfo()" ----
  2144. //---- get tm & comctl symbols ----
  2145. const TMSCHEMAINFO *si = GetSchemaInfo();
  2146. int cnt = si->iPropCount;
  2147. const TMPROPINFO *pi = si->pPropTable;
  2148. for (int i=0; i < cnt; i++)
  2149. {
  2150. if (pi[i].sEnumVal < TMT_FIRST_RCSTRING_NAME)
  2151. continue;
  2152. if (pi[i].sEnumVal > TMT_LAST_RCSTRING_NAME)
  2153. break;
  2154. if (AsciiStrCmpI(pszName, pi[i].pszName)==0)
  2155. {
  2156. *piPropNum = pi[i].sEnumVal - TMT_FIRST_RCSTRING_NAME; // zero based
  2157. return S_OK;
  2158. }
  2159. }
  2160. return MakeError32(ERROR_NOT_FOUND);
  2161. }
  2162. //---------------------------------------------------------------------------
  2163. HRESULT CThemeParser::BitmapColorReplacement(DWORD *pPixelBuff, UINT iWidth, UINT iHeight)
  2164. {
  2165. if ((! _iHueCount) && (! _iColorCount))
  2166. return S_OK;
  2167. DWORD *pPixel = pPixelBuff;
  2168. for (UINT r=0; r < iHeight; r++) // for each row
  2169. {
  2170. for (UINT c=0; c < iWidth; c++, pPixel++) // for each pixel in row
  2171. {
  2172. //---- try to apply a COLOR substitution ----
  2173. if (_iColorCount)
  2174. {
  2175. COLORREF crPixel = REVERSE3(*pPixel);
  2176. for (int h=0; h < _iColorCount; h++)
  2177. {
  2178. if (_crFromColors[h] == crPixel)
  2179. {
  2180. //---- preserve alpha value when doing COLOR replacement ----
  2181. *pPixel = ((ALPHACHANNEL(*pPixel)) << 24) | REVERSE3(_crToColors[h]);
  2182. break; // only one replacement per pixel
  2183. }
  2184. }
  2185. if (h < _iColorCount) // don't try hues if we got COLOR match
  2186. continue;
  2187. }
  2188. if (_iHueCount)
  2189. {
  2190. WORD wPixelHue, wPixelLum, wPixelSat;
  2191. RGBtoHLS(REVERSE3(*pPixel), &wPixelHue, &wPixelLum, &wPixelSat);
  2192. //---- try to apply a HUE substitution ----
  2193. for (int h=0; h < _iHueCount; h++)
  2194. {
  2195. if (_bFromHues[h] == wPixelHue)
  2196. {
  2197. //---- preserve alpha value when doing HUE replacement ----
  2198. *pPixel = ((ALPHACHANNEL(*pPixel)) << 24) | REVERSE3(HLStoRGB(_bToHues[h], wPixelLum, wPixelSat));
  2199. break; // only one replacement per pixel
  2200. };
  2201. }
  2202. }
  2203. }
  2204. }
  2205. return S_OK;
  2206. }
  2207. //---------------------------------------------------------------------------
  2208. HRESULT CThemeParser::GetStateNum(LPCWSTR pszStateName, BYTE *piNum)
  2209. {
  2210. WCHAR statesname[_MAX_PATH+1];
  2211. HRESULT hr = S_OK;
  2212. if (! *_szBaseSectionName)
  2213. {
  2214. Log(LOG_ERROR, L"szBaseSectionName not set by caller of NtlRun");
  2215. hr = SourceError(PARSER_IDS_INTERNAL_TM_ERROR);
  2216. goto exit;
  2217. }
  2218. wsprintf(statesname, L"%sStates", _szBaseSectionName);
  2219. int iSymIndex;
  2220. iSymIndex = GetSymbolIndex(statesname);
  2221. if (iSymIndex == -1)
  2222. {
  2223. hr = SourceError(PARSER_IDS_UNKNOWN_STATE, statesname);
  2224. goto exit;
  2225. }
  2226. int iStateIndex;
  2227. hr = ValidateEnumSymbol(statesname, iSymIndex, &iStateIndex);
  2228. if (FAILED(hr))
  2229. goto exit;
  2230. *piNum = (BYTE)_EnumVals[iStateIndex].iValue;
  2231. exit:
  2232. return hr;
  2233. }
  2234. //---------------------------------------------------------------------------