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

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