//--------------------------------------------------------------------------- // Parser.cpp - parses a "themes.ini" file and builds the ThemeInfo entries //--------------------------------------------------------------------------- #include "stdafx.h" #include "scanner.h" #include "Parser.h" #include "Utils.h" #include "TmUtils.h" #include "TmSchema.h" #include "TmReg.h" //--------------------------------------------------------------------------- //#include "NtlParse.h" #define SYSCOLOR_STRINGS #include "SysColors.h" //--------------------------------------------------------------------------- #define SCHEMA_STRINGS #include "TmSchema.h" // implements GetSchemaInfo() static HBITMAP (*s_pfnSetBitmapAttributes)(HBITMAP, DWORD) = NULL; static HBITMAP (*s_pfnClearBitmapAttributes)(HBITMAP, DWORD) = NULL; //-------------------------------------------------------------------- CThemeParser::CThemeParser(BOOL fGlobalTheme) { _pCallBackObj = NULL; _pNameCallBack = NULL; _fGlobalsDefined = FALSE; _fClassSectionDefined = FALSE; _fDefiningColorScheme = FALSE; _fUsingResourceProperties = FALSE; _fDefiningMetrics = FALSE; _fMetricsDefined = FALSE; _fGlobalTheme = FALSE; _crBlend = RGB(0, 0, 0xFF); // Hard code to blue *_szResPropValue = 0; // not yet set #ifdef DEBUG // Provide a means of disabling stock bitmaps BOOL fStock = TRUE; GetCurrentUserThemeInt(L"StockBitmaps", TRUE, &fStock); if (fStock && fGlobalTheme) #else if (fGlobalTheme) #endif { // Just don't use stock bitmaps when not running on Whistler if (s_pfnSetBitmapAttributes != NULL) { _fGlobalTheme = TRUE; } else { HMODULE hMod = ::LoadLibrary(L"GDI32.DLL"); // No need to free if (hMod) { s_pfnSetBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "SetBitmapAttributes"); s_pfnClearBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "ClearBitmapAttributes"); if ((s_pfnSetBitmapAttributes != NULL) && (s_pfnClearBitmapAttributes != NULL)) { _fGlobalTheme = TRUE; } } } } *_szBaseSectionName = 0; *_szFullSectionName = 0; _iColorCount = 0; _iHueCount = 0; _uCharSet = DEFAULT_CHARSET; _iFontNumber = 0; _hinstThemeDll = NULL; } //--------------------------------------------------------------------------- HRESULT CThemeParser::SourceError(int iMsgResId, LPCWSTR pszParam1, LPCWSTR pszParam2) { LPCWSTR pszSrcLine = _scan._szLineBuff; LPCWSTR pszFileName = _scan._szFileName; int iLineNum = _scan._iLineNum; if (*_szResPropValue) // error in localizable property value { pszSrcLine = _szResPropValue; pszFileName = L"StringTable#"; iLineNum = _iResPropId; } HRESULT hr = MakeParseError(iMsgResId, pszParam1, pszParam2, pszFileName, pszSrcLine, iLineNum); return hr; } //--------------------------------------------------------------------------- int CThemeParser::GetSymbolIndex(LPCWSTR pszName) { int symcnt = _Symbols.GetSize(); for (int i=0; i < symcnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, pszName)==0) return i; } return -1; } //--------------------------------------------------------------------------- HRESULT CThemeParser::AddSymbol(LPCWSTR pszName, SHORT sTypeNum, PRIMVAL ePrimVal) { //---- ensure symbol doesn't already exist ---- for (int i = 0; i < _Symbols.m_nSize; i++) { if (AsciiStrCmpI(_Symbols.m_aT[i].csName, pszName)==0) return SourceError(PARSER_IDS_TYPE_DEFINED_TWICE, pszName); } if (sTypeNum == -1) sTypeNum = (SHORT)_Symbols.GetSize(); SYMBOL symbol; symbol.csName = pszName; symbol.sTypeNum = sTypeNum; symbol.ePrimVal = ePrimVal; _Symbols.Add(symbol); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::InitializeSymbols() { _Symbols.RemoveAll(); _StockBitmapCleanupList.RemoveAll(); //---- get tm & comctl symbols ---- const TMSCHEMAINFO *si = GetSchemaInfo(); int cnt = si->iPropCount; const TMPROPINFO *pi = si->pPropTable; //---- first pass - add all symbols except ENUM definitions ---- for (int i=0; i < cnt; i++) { if (pi[i].bPrimVal == TMT_ENUMDEF) continue; if (pi[i].bPrimVal == TMT_ENUMVAL) continue; HRESULT hr = AddSymbol(pi[i].pszName, pi[i].sEnumVal, pi[i].bPrimVal); if (FAILED(hr)) return hr; } //---- second pass - add ENUM definitions ---- int iEnumPropNum = -1; for (int i=0; i < cnt; i++) { if (pi[i].bPrimVal == TMT_ENUMDEF) { int iSymIndex = GetSymbolIndex(pi[i].pszName); if (iSymIndex == -1) // not found - add it as a non-property enum symbol { HRESULT hr = AddSymbol(pi[i].pszName, -1, TMT_ENUM); if (FAILED(hr)) return hr; iSymIndex = GetSymbolIndex(pi[i].pszName); } if (iSymIndex > -1) iEnumPropNum = _Symbols[iSymIndex].sTypeNum; else iEnumPropNum = -1; } else if (pi[i].bPrimVal == TMT_ENUMVAL) { ENUMVAL enumval; enumval.csName = pi[i].pszName; enumval.iSymbolIndex = iEnumPropNum; enumval.iValue = pi[i].sEnumVal; _EnumVals.Add(enumval); } } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseDocSection() { _scan.ForceNextLine(); // get line after section line //---- just skip over all lines in this section ---- while (1) { WCHAR szNameBuff[_MAX_PATH+1]; if (_scan.GetChar('[')) // start of new section break; if (! _scan.GetId(szNameBuff)) return SourceError(PARSER_IDS_EXPECTED_PROP_NAME); if (! _scan.GetChar('=')) return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN); int cnt = _Symbols.GetSize(); for (int i=0; i < cnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0) break; } int symtype; if (i == cnt) symtype = TMT_STRING; // unknown string property else symtype = _Symbols[i].sTypeNum; HRESULT hr; //---- check to see if caller is querying for a doc property ---- if ((_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (lstrcmpi(_pszDocProperty, szNameBuff)==0)) hr = ParseStringValue(symtype, _pszResult, _dwMaxResultChars); else hr = ParseStringValue(symtype); if (FAILED(hr)) return hr; _scan.ForceNextLine(); } //---- done with [documentation] section - turn off callback flag for properties ---- _dwParseFlags &= (~PTF_CALLBACK_DOCPROPERTIES); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseClassSectionName(LPCWSTR pszFirstName, LPWSTR szAppSym, ULONG cchAppSym) { //---- validate section name ---- // // optional: szAppSym:: // _szClassName // optional: .partsym WCHAR szPartSym[_MAX_PATH+1]; WCHAR szStateSym[_MAX_PATH+1]; *szAppSym = 0; *szPartSym = 0; _iPartId = -1; _iStateId = -1; //---- copy the section name for callbacks ---- StringCchPrintfW(_szFullSectionName, ARRAYSIZE(_szFullSectionName), L"%s%s", pszFirstName, _scan._p); WCHAR *p = wcschr(_szFullSectionName, ']'); if (p) *p = 0; HRESULT hr; hr = SafeStringCchCopyW(_szClassName, ARRAYSIZE(_szClassName), pszFirstName); if (FAILED(hr)) return hr; if (_scan.GetChar(':')) { hr = SafeStringCchCopyW(szAppSym, cchAppSym, _szClassName); if (FAILED(hr)) return hr; if (! _scan.GetChar(':')) return SourceError(PARSER_IDS_EXPECTED_DOUBLE_COLON); if (! _scan.GetId(_szClassName)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_NAME); } else *szAppSym = 0; _fDefiningMetrics = (AsciiStrCmpI(_szClassName, L"SysMetrics")==0); if ((_fDefiningMetrics) && (*szAppSym)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); if (_scan.GetChar('.')) // an optional part id { //---- ensure a enum exists: Parts ---- WCHAR classparts[_MAX_PATH+1]; StringCchPrintfW(classparts, ARRAYSIZE(classparts), L"%sParts", _szClassName); int iSymIndex = GetSymbolIndex(classparts); if (iSymIndex == -1) // doesn't exist return SourceError(PARSER_IDS_PARTS_NOT_DEFINED, _szClassName); //---- _scan the part name ---- if (! _scan.GetId(szPartSym)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_PART); //---- validate that it is a value for the Parts ---- hr = ValidateEnumSymbol(szPartSym, iSymIndex, &_iPartId); if (FAILED(hr)) return hr; } if (_scan.GetChar('(')) // an optional state { //---- ensure a enum exists: States ---- WCHAR statesname[_MAX_PATH+1]; WCHAR *pszBaseName; if (_iPartId == -1) pszBaseName = _szClassName; else pszBaseName = szPartSym; StringCchPrintfW(statesname, ARRAYSIZE(statesname), L"%sStates", pszBaseName); int iSymIndex = GetSymbolIndex(statesname); if (iSymIndex == -1) return SourceError(PARSER_IDS_STATES_NOT_DEFINED, pszBaseName); if (! _scan.GetId(szStateSym)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_STATE); hr = ValidateEnumSymbol(szStateSym, iSymIndex, &_iStateId); if (FAILED(hr)) return hr; if (! _scan.GetChar(')')) return SourceError(PARSER_IDS_EXPECTED_RPAREN); } if (_iPartId > -1) { _iPartId = _EnumVals[_iPartId].iValue; StringCchCopyW(_szBaseSectionName, ARRAYSIZE(_szBaseSectionName), szPartSym); } else // not specified { StringCchCopyW(_szBaseSectionName, ARRAYSIZE(_szBaseSectionName), _szClassName); _iPartId = 0; } if (_iStateId > -1) _iStateId = _EnumVals[_iStateId].iValue; else _iStateId = 0; if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_EXPECTED_END_OF_SECTION); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ValidateEnumSymbol(LPCWSTR pszName, int iSymType, int *pIndex) { for (int i = 0; i < _EnumVals.m_nSize; i++) { if (AsciiStrCmpI(_EnumVals.m_aT[i].csName, pszName)==0) { if (_EnumVals.m_aT[i].iSymbolIndex == iSymType) { if (pIndex) *pIndex = i; return S_OK; } } } return SourceError(PARSER_IDS_NOT_ENUM_VALNAME, pszName, (LPCWSTR)_Symbols[iSymType].csName); } //--------------------------------------------------------------------------- HRESULT CThemeParser::AddThemeData(int iTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen) { //Log("AddThemeData: typenum=%d, len=%d, data=0x%x", iTypeNum, dwLen, pData); if (! _pCallBackObj) return S_FALSE; HRESULT hr = _pCallBackObj->AddData((SHORT)iTypeNum, ePrimVal, pData, dwLen); if (FAILED(hr)) return SourceError(PARSER_IDS_THEME_TOO_BIG); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseEnumValue(int iSymType) { WCHAR valbuff[_MAX_PATH+1]; HRESULT hr; int value; if (! _scan.GetId(valbuff)) return SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED); int index; hr = ValidateEnumSymbol(valbuff, iSymType, &index); if (FAILED(hr)) return hr; value = _EnumVals[index].iValue; hr = AddThemeData(iSymType, TMT_ENUM, &value, sizeof(value)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseStringValue(int iSymType, LPWSTR pszBuff, DWORD cchBuff) { HRESULT hr; //---- just store the raw string ---- _scan.SkipSpaces(); if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTSTRING) || (iSymType > TMT_LASTSTRING)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); } if (pszBuff) // special call { hr = SafeStringCchCopyW(pszBuff, cchBuff, _scan._p); if (FAILED(hr)) return hr; } else { int len = 1 + lstrlen(_scan._p); hr = AddThemeData(iSymType, TMT_STRING, _scan._p, len*sizeof(WCHAR)); if (FAILED(hr)) return hr; } if ((iSymType >= TMT_FIRST_RCSTRING_NAME) && (iSymType <= TMT_LAST_RCSTRING_NAME)) { if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_DOCPROPERTIES)) { int index = iSymType - TMT_FIRST_RCSTRING_NAME; BOOL fContinue = (*_pNameCallBack)(TCB_DOCPROPERTY, _scan._p, NULL, NULL, index, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } } //---- advance _scanner to end of line ---- _scan._p += lstrlen(_scan._p); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseIntValue(int iSymType, int *piValue) { int value; if (! _scan.GetNumber(&value)) return SourceError(PARSER_IDS_INT_EXPECTED); if (piValue) // special call *piValue = value; else { HRESULT hr = AddThemeData(iSymType, TMT_INT, &value, sizeof(value)); if (FAILED(hr)) return hr; } if (iSymType == TMT_CHARSET) { if (_iFontNumber) return SourceError(PARSER_IDS_CHARSETFIRST); if (_fGlobalsDefined) return SourceError(PARSER_IDS_CHARSET_GLOBALS_ONLY); _uCharSet = (UCHAR) value; } if (iSymType == TMT_MINCOLORDEPTH) { if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_MINCOLORDEPTH)) { BOOL fContinue = (*_pNameCallBack)(TCB_MINCOLORDEPTH, _scan._szFileName, NULL, NULL, value, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseBoolValue(int iSymType, LPCWSTR pszPropertyName) { WCHAR valbuff[_MAX_PATH+1]; BYTE bBoolVal; if (! _scan.GetId(valbuff)) return SourceError(PARSER_IDS_BOOL_EXPECTED); if (AsciiStrCmpI(valbuff, L"true")==0) bBoolVal = 1; else if (AsciiStrCmpI(valbuff, L"false")==0) bBoolVal = 0; else return SourceError(PARSER_IDS_EXPECTED_TRUE_OR_FALSE); if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTBOOL) || (iSymType > TMT_LASTBOOL)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); } //---- special handling for "MirrorImage" property ---- if (iSymType == TMT_MIRRORIMAGE) { //---- handle MirrorImage callbacks (packtime) ---- if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { BOOL fContinue = (*_pNameCallBack)(TCB_MIRRORIMAGE, _szClassName, _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)bBoolVal); if (! fContinue) return MakeErrorParserLast(); } //---- handle getting value from string table (loadtime) ---- if (_fUsingResourceProperties) // substitute resource value { WCHAR szValue[MAX_PATH]; HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue)); if (SUCCEEDED(hr)) { bBoolVal = (*szValue == '1'); } else { hr = S_OK; // non-fatal error } } } HRESULT hr = AddThemeData(iSymType, TMT_BOOL, &bBoolVal, sizeof(bBoolVal)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- COLORREF CThemeParser::ApplyColorSubstitution(COLORREF crOld) { //---- apply SOLID color substitutions ---- for (int i=0; i < _iColorCount; i++) { if (crOld == _crFromColors[i]) return _crToColors[i]; } //---- apply HUE color substitutions ---- WORD wHue, wLum, wSat; RGBtoHLS(crOld, &wHue, &wLum, &wSat); for (i=0; i < _iHueCount; i++) { if (wHue == _bFromHues[i]) // hues match { COLORREF crNew = HLStoRGB(_bToHues[i], wLum, wSat); // substitute new hue return crNew; } } return crOld; } //--------------------------------------------------------------------------- void CThemeParser::CleanupStockBitmaps() { if (s_pfnClearBitmapAttributes) { for (int i=0; i < _StockBitmapCleanupList.m_nSize; i++) { HBITMAP hbm = (*s_pfnClearBitmapAttributes)(_StockBitmapCleanupList[i], SBA_STOCK); if (hbm) { DeleteObject(hbm); } else { // We are totally out of luck today aren't we Log(LOG_TMBITMAP, L"Failed to clear stock bitmap on cleanup"); } } } _StockBitmapCleanupList.RemoveAll(); } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseColorValue(int iSymType, COLORREF *pcrValue, COLORREF *pcrValue2) { COLORREF color; HRESULT hr = S_OK; { const WCHAR *parts[] = {L"r", L"g", L"b"}; int ints[3] = {0}; hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 255); if (FAILED(hr)) { hr = SourceError(PARSER_IDS_BAD_COLOR_VALUE); goto exit; } color = RGB(ints[0], ints[1], ints[2]); } if (! _fDefiningColorScheme) color = ApplyColorSubstitution(color); if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTCOLOR) || (iSymType > TMT_LASTCOLOR)) { hr = SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); goto exit; } } if (pcrValue2) { *pcrValue2 = color; } if (pcrValue) // special call *pcrValue = color; else { hr = AddThemeData(iSymType, TMT_COLOR, &color, sizeof(color)); if (FAILED(hr)) goto exit; } exit: return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseMarginsValue(int iSymType) { const WCHAR *parts[] = {L"lw", L"rw", L"th", L"bh"}; int ints[4]; HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_BAD_MARGINS_VALUE); hr = AddThemeData(iSymType, TMT_MARGINS, ints, sizeof(ints)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseIntListValue(int iSymType) { INTLIST IntList; HRESULT hr = S_OK; //---- unnamed parts ---- for (int i=0; i < MAX_INTLIST_COUNT; i++) { if (! _scan.GetNumber(&IntList.iValues[i])) { if (_scan.EndOfLine()) break; hr = SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p); goto exit; } _scan.GetChar(','); // optional comma } IntList.iValueCount = i; hr = AddThemeData(iSymType, TMT_INTLIST, &IntList, (1+i)*sizeof(int)); if (FAILED(hr)) goto exit; exit: return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::PackageImageData(LPCWSTR szFileNameR, LPCWSTR szFileNameG, LPCWSTR szFileNameB, int iDibPropNum) { HRESULT hr = S_OK; //---- add TMT_DIBDATA data ---- WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; // The filename was parsed and validated before, so we're sure it's not longer than _MAX_PATH _wsplitpath(szFileNameR, drive, dir, fname, ext); WCHAR szResName[_MAX_PATH+1]; DWORD len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapR = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (!hBitmapR) return SourceError(PARSER_IDS_NOOPEN_IMAGE, szResName); //---- convert to DIBDATA ---- CBitmapPixels pixels; DWORD *pPixelQuads; int iWidth, iHeight, iBytesPerPixel, iBytesPerRow, iPreviousBytesPerPixel; BOOL fUseDrawStream = TRUE; // Allocate a TMBITMAPHEADER in addition to the bitmap hr = pixels.OpenBitmap(NULL, hBitmapR, TRUE, &pPixelQuads, &iWidth, &iHeight, &iBytesPerPixel, &iBytesPerRow, &iPreviousBytesPerPixel, TMBITMAPSIZE); if (FAILED(hr)) { DeleteObject(hBitmapR); return hr; } BOOL fWasAlpha = (iPreviousBytesPerPixel == 4); #if 0 //---- apply loaded color scheme, if any ---- if ((szFileNameG && szFileNameG[0]) && (szFileNameB && szFileNameB[0])) { _wsplitpath(szFileNameG, drive, dir, fname, ext); len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapG = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); _wsplitpath(szFileNameB, drive, dir, fname, ext); len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapB = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); DWORD dwRWeight = GetRValue(_crBlend); DWORD dwGWeight = GetGValue(_crBlend); DWORD dwBWeight = GetBValue(_crBlend); DWORD *pPixelQuadsG = NULL; DWORD *pPixelQuadsB = NULL; if (hBitmapG && hBitmapB) { HDC hdc = GetDC(NULL); if (hdc) { int dwLen = iWidth * iHeight; pPixelQuadsG = new DWORD[dwLen]; if (pPixelQuadsG) { pPixelQuadsB = new DWORD[dwLen]; if (pPixelQuadsB) { BITMAPINFO bi = {0}; bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = iWidth; bi.bmiHeader.biHeight = iHeight; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; if (GetDIBits(hdc, hBitmapG, 0, iHeight, pPixelQuadsG, &bi, DIB_RGB_COLORS) && GetDIBits(hdc, hBitmapB, 0, iHeight, pPixelQuadsB, &bi, DIB_RGB_COLORS)) { DWORD* pdwR = pPixelQuads; DWORD* pdwG = pPixelQuadsG; DWORD* pdwB = pPixelQuadsB; for (int i = 0; i < dwLen; i++) { if ((*pdwR & 0xffffff) != RGB(255,0,255)) { *pdwR = (*pdwR & 0xff000000) | RGB(min(((GetRValue(*pdwR) * dwRWeight) + (GetRValue(*pdwG) * dwGWeight) + (GetRValue(*pdwB) * dwBWeight)) >> 8, 0xff), min(((GetGValue(*pdwR) * dwRWeight) + (GetGValue(*pdwG) * dwGWeight) + (GetGValue(*pdwB) * dwBWeight)) >> 8, 0xff), min(((GetBValue(*pdwR) * dwRWeight) + (GetBValue(*pdwG) * dwGWeight) + (GetBValue(*pdwB) * dwBWeight)) >> 8, 0xff)); } pdwR++; pdwG++; pdwB++; } } delete[] pPixelQuadsB; } delete[] pPixelQuadsG; } ReleaseDC(NULL, hdc); } } else { OutputDebugString(L"Failed to load bitmaps"); } if (hBitmapG) { DeleteObject(hBitmapG); hBitmapG = NULL; } if (hBitmapB) { DeleteObject(hBitmapB); hBitmapB = NULL; } } #endif BITMAPINFOHEADER *pBitmapHdr = pixels._hdrBitmap; //---- if alpha present, pre-multiply RGB values (as per AlphaBlend()) API ---- BOOL fTrueAlpha = FALSE; // We keep per-pixel alpha bitmaps as 32 bits DIBs, not compatible bitmaps if (fWasAlpha) { fTrueAlpha = (PreMultiplyAlpha(pPixelQuads, pBitmapHdr->biWidth, pBitmapHdr->biHeight) != 0); #ifdef DEBUG if (!fTrueAlpha) Log(LOG_TMBITMAP, L"%s is 32 bits, but not true alpha", szFileNameR); #endif } HBITMAP hbmStock = NULL; BOOL fFlipped = FALSE; if (fUseDrawStream && _fGlobalTheme) { HDC hdc = ::GetWindowDC(NULL); if (hdc) { typedef struct { BITMAPINFOHEADER bmih; ULONG masks[3]; } BITMAPHEADER; BITMAPHEADER bmi; bmi.bmih.biSize = sizeof(bmi.bmih); bmi.bmih.biWidth = pBitmapHdr->biWidth; bmi.bmih.biHeight = pBitmapHdr->biHeight; bmi.bmih.biPlanes = 1; bmi.bmih.biBitCount = 32; bmi.bmih.biCompression = BI_BITFIELDS; bmi.bmih.biSizeImage = 0; bmi.bmih.biXPelsPerMeter = 0; bmi.bmih.biYPelsPerMeter = 0; bmi.bmih.biClrUsed = 3; bmi.bmih.biClrImportant = 0; bmi.masks[0] = 0xff0000; // red bmi.masks[1] = 0x00ff00; // green bmi.masks[2] = 0x0000ff; // blue hbmStock = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | CBM_CREATEDIB , pPixelQuads, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS); // Need to Force 32-bit DIBs in Multi-mon mode // Make it match the screen resolution setting if it is not an AlphaBlended image ::ReleaseDC(NULL, hdc); } if (!hbmStock) { hr = E_OUTOFMEMORY; } else { ASSERT(s_pfnSetBitmapAttributes != NULL); ASSERT(s_pfnClearBitmapAttributes != NULL); HBITMAP hbmOld = hbmStock; hbmStock = (*s_pfnSetBitmapAttributes)(hbmStock, SBA_STOCK); if (hbmStock == NULL) { DeleteObject(hbmOld); Log(LOG_ALWAYS, L"UxTheme: SetBitmapAttributes failed in CParser::PackageImageData"); hr = E_FAIL; } else { _StockBitmapCleanupList.Add(hbmStock); } } } ::DeleteObject(hBitmapR); // Fill in the TMBITMAPHEADER structure if (SUCCEEDED(hr)) { TMBITMAPHEADER *psbh = (TMBITMAPHEADER*) pixels.Buffer(); psbh->dwSize = TMBITMAPSIZE; psbh->fFlipped = fFlipped; psbh->hBitmap = hbmStock; psbh->fTrueAlpha = fTrueAlpha; psbh->dwColorDepth = iBytesPerPixel * 8; if (hbmStock == NULL) // Pass DIB bits { int size = psbh->dwSize + sizeof(BITMAPINFOHEADER) + iHeight * iBytesPerRow; hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, size); } else // Pass the TMBITMAPHEADER structure only { hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, psbh->dwSize); } } return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseFileNameValue(int iSymType, LPWSTR pszBuff, DWORD cchBuff) { WCHAR szFileNameR[_MAX_PATH+1] = {0}; WCHAR szFileNameG[_MAX_PATH+1] = {0}; WCHAR szFileNameB[_MAX_PATH+1] = {0}; HRESULT hr = S_OK; if (! _scan.GetFileName(szFileNameR, ARRAYSIZE(szFileNameR))) { hr = SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED); goto exit; } if (_scan.GetFileName(szFileNameG, ARRAYSIZE(szFileNameG))) { _scan.GetFileName(szFileNameB, ARRAYSIZE(szFileNameB)); } if (pszBuff) // special call { hr = SafeStringCchCopyW(pszBuff, cchBuff, szFileNameR); if (FAILED(hr)) goto exit; } else if (_pCallBackObj) // emit data { //---- add TMT_FILENAME data ---- hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameR, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; if ((szFileNameG[0] != 0) && (szFileNameB[0] != 0)) { hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameG, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameB, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; } if (iSymType == TMT_IMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA); } else if (iSymType == TMT_GLYPHIMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_GLYPHDIBDATA); } else if (iSymType == TMT_STOCKIMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_STOCKDIBDATA); } else if ((iSymType >= TMT_IMAGEFILE1) && (iSymType <= TMT_IMAGEFILE5)) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA1 + (iSymType-TMT_IMAGEFILE1)); } if (FAILED(hr)) goto exit; } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILENAMES)) { BOOL fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameR, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; } if (szFileNameG[0] && szFileNameB[0]) { fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameG, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; } fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameB, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; } } } exit: return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseSizeValue(int iSymType) { int val; if (! _scan.GetNumber(&val)) return SourceError(PARSER_IDS_INT_EXPECTED); int pixels; HRESULT hr = ParseSizeInfoUnits(val, L"pixels", &pixels); if (FAILED(hr)) return hr; if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTSIZE) || (iSymType > TMT_LASTSIZE)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); } hr = AddThemeData(iSymType, TMT_SIZE, &pixels, sizeof(pixels)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParsePositionValue(int iSymType) { const WCHAR *parts[] = {L"x", L"y"}; int ints[2]; HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_ILLEGAL_SIZE_VALUE); hr = AddThemeData(iSymType, TMT_POSITION, ints, sizeof(ints)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseRectValue(int iSymType, LPCWSTR pszPropertyName) { const WCHAR *parts[] = {L"l", L"t", L"r", L"b"}; LONG rgl[4]; HRESULT hr = GetIntList((int*)rgl, parts, ARRAYSIZE(rgl), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_ILLEGAL_RECT_VALUE); //---- special handling for localizable RECT properties ---- if (iSymType == TMT_DEFAULTPANESIZE) { //---- handle localizable callback (packtime) ---- if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { BOOL fContinue = (*_pNameCallBack)(TCB_LOCALIZABLE_RECT, _szClassName, _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)(RECT *)rgl); if (! fContinue) return MakeErrorParserLast(); } //---- handle getting value from string table (loadtime) ---- if (_fUsingResourceProperties) // substitute resource value { WCHAR szValue[MAX_PATH]; HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue)); if (SUCCEEDED(hr)) { RECT rc; int cnt = swscanf(szValue, L"%d, %d, %d, %d", &rc.left, &rc.top, &rc.right, &rc.bottom); if (cnt == 4) { //---- override with localized values ---- CopyMemory(rgl, &rc, sizeof(rgl)); } } else { hr = S_OK; // non-fatal error } } } hr = AddThemeData(iSymType, TMT_RECT, rgl, sizeof(rgl)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseSizeInfoUnits(int iVal, LPCWSTR pszDefaultUnits, int *piPixels) { WCHAR szUnits[_MAX_PATH+1]; HRESULT hr; //---- NOTE: this uses the THEME_DPI (96) for all size conversions! ---- //---- this gives us consistent LOGFONT, etc. across diff. resolution screens ---- //---- with the promise that we will do just-in-time DPI scaling, when appropriate ---- if (! _scan.GetId(szUnits)) { hr = SafeStringCchCopyW(szUnits, ARRAYSIZE(szUnits), pszDefaultUnits); if (FAILED(hr)) return hr; } if (AsciiStrCmpI(szUnits, L"pixels")==0) ; // already correct else if (AsciiStrCmpI(szUnits, L"twips")==0) { iVal = -MulDiv(iVal, THEME_DPI, 20*72); } else if (AsciiStrCmpI(szUnits, L"points")==0) { iVal = -MulDiv(iVal, THEME_DPI, 72); } else return SourceError(PARSER_IDS_UNKNOWN_SIZE_UNITS, szUnits); *piPixels = iVal; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseFontValue(int iSymType, LPCWSTR pszPropertyName) { LOGFONT font; WCHAR szLineBuff[_MAX_PATH+1]; HRESULT hr; _scan.SkipSpaces(); // trim leading blanks memset(&font, 0, sizeof(font)); font.lfWeight = FW_NORMAL; font.lfCharSet = _uCharSet; _iFontNumber++; BOOL fGotFont = FALSE; if (_fUsingResourceProperties) // substitute resource font string { hr = GetResourceProperty(pszPropertyName, szLineBuff, ARRAYSIZE(szLineBuff)); if (SUCCEEDED(hr)) { fGotFont = TRUE; } else { hr = S_OK; } } if (! fGotFont) { //---- copy font specs from scanner ---- hr = SafeStringCchCopyW(szLineBuff, ARRAYSIZE(szLineBuff), _scan._p); if (FAILED(hr)) return hr; } //---- handle font callback ---- if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { WCHAR *p = szLineBuff; while (IsSpace(*p)) p++; BOOL fContinue = (*_pNameCallBack)(TCB_FONT, p, _szFullSectionName, pszPropertyName, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } //---- family name is required and must be first ---- WCHAR *p; p = wcschr(szLineBuff, ','); if (! p) // whole line is family name { hr = StringCchCopyW(font.lfFaceName, ARRAYSIZE(font.lfFaceName), szLineBuff); return hr; } *p++ = 0; hr = StringCchCopyW(font.lfFaceName, ARRAYSIZE(font.lfFaceName), szLineBuff); if (FAILED(hr)) return hr; _scan._p = p; int val; if (_scan.GetNumber(&val)) // font size { int pixels; hr = ParseSizeInfoUnits(val, L"points", &pixels); if (FAILED(hr)) return hr; font.lfHeight = pixels; _scan.GetChar(','); // optional comma } WCHAR flagname[_MAX_PATH+1]; while (_scan.GetId(flagname)) { if (AsciiStrCmpI(flagname, L"bold")==0) font.lfWeight = FW_BOLD; else if (AsciiStrCmpI(flagname, L"italic")==0) font.lfItalic = TRUE; else if (AsciiStrCmpI(flagname, L"underline")==0) font.lfUnderline = TRUE; else if (AsciiStrCmpI(flagname, L"strikeout")==0) font.lfStrikeOut = TRUE; else return SourceError(PARSER_IDS_UNKNOWN_FONT_FLAG, flagname); } // addit: if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTFONT) || (iSymType > TMT_LASTFONT)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); } hr = AddThemeData(iSymType, TMT_FONT, &font, sizeof(font)); if (FAILED(hr)) return hr; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseClassLine(int *piSymType, int *piValue, LPWSTR pszBuff, DWORD cchBuff) { WCHAR szNameBuff[_MAX_PATH+1]; WCHAR szSymbol[MAX_INPUT_LINE+1]; if (! _scan.GetId(szNameBuff)) return SourceError(PARSER_IDS_EXPECTED_PROP_NAME); if (! _scan.GetChar('=')) return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN); int cnt = _Symbols.GetSize(); for (int i=0; i < cnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0) break; } if (i == cnt) return SourceError(PARSER_IDS_UNKNOWN_PROP, szNameBuff); int symtype = _Symbols[i].sTypeNum; HRESULT hr; // Handle substituted symbols if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS)) { if (wcschr(_scan._p, INI_MACRO_SYMBOL)) { // Pass ## if (_scan.GetChar(INI_MACRO_SYMBOL) && _scan.GetChar(INI_MACRO_SYMBOL)) { WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT]; _wsplitpath(_scan._szFileName, szDrive, szDir, szBaseName, szExt); BOOL fContinue = (*_pNameCallBack)(TCB_NEEDSUBST, szBaseName, _scan._p, szSymbol, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); _scan.UseSymbol(szSymbol); } } } switch (_Symbols[i].ePrimVal) { case TMT_ENUM: hr = ParseEnumValue(symtype); break; case TMT_STRING: hr = ParseStringValue(symtype, pszBuff, cchBuff); break; case TMT_INT: hr = ParseIntValue(symtype, piValue); break; case TMT_INTLIST: hr = ParseIntListValue(symtype); break; case TMT_BOOL: hr = ParseBoolValue(symtype, szNameBuff); break; case TMT_COLOR: { COLORREF cr; hr = ParseColorValue(symtype, (COLORREF *)piValue, &cr); if (SUCCEEDED(hr)) { if (lstrcmpi(_Symbols[i].csName, L"BLENDCOLOR") == 0) { _crBlend = cr; } } } break; case TMT_MARGINS: hr = ParseMarginsValue(symtype); break; case TMT_FILENAME: hr = ParseFileNameValue(symtype, pszBuff, cchBuff); break; case TMT_SIZE: hr = ParseSizeValue(symtype); break; case TMT_POSITION: hr = ParsePositionValue(symtype); break; case TMT_RECT: hr = ParseRectValue(symtype, szNameBuff); break; case TMT_FONT: hr = ParseFontValue(symtype, szNameBuff); break; default: hr = E_FAIL; break; } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS)) { _scan.UseSymbol(NULL); } *_szResPropValue = 0; // not yet set if (FAILED(hr)) return hr; if (piSymType) // special call *piSymType = symtype; if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_EXTRA_PROP_TEXT, _scan._p); _scan.ForceNextLine(); return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseColorSchemeSection() { HRESULT hr; WCHAR SchemeName[_MAX_PATH+1]; WCHAR DisplayName[_MAX_PATH+1]; WCHAR ToolTip[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1]; if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN); if (! _scan.GetId(SchemeName, ARRAYSIZE(SchemeName))) return SourceError(PARSER_IDS_CS_NAME_EXPECTED); if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED); if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED); _scan.ForceNextLine(); // get line after section line *ToolTip = 0; *DisplayName = 0; bool fCorrectScheme = (lstrcmpi(_ColorParam, SchemeName)==0); if (fCorrectScheme) // initialize all subst. tables { hr = SafeStringCchCopyW(DisplayName, ARRAYSIZE(DisplayName), SchemeName); // in case not specified if (FAILED(hr)) return hr; for (int i=0; i < HUE_SUBCNT; i++) { _bFromHues[i] = 0; _bToHues[i] = 0; } for (i=0; i < COLOR_SUBCNT; i++) { _crFromColors[i] = 0; _crToColors[i] = 0; } } //----- put into vars to make coding/debugging easier ---- int firstFromHue = TMT_FROMHUE1; int lastFromHue = TMT_FROMHUE1 + HUE_SUBCNT - 1; int firstToHue = TMT_TOHUE1; int lastToHue = TMT_TOHUE1 + HUE_SUBCNT - 1; int firstFromColor = TMT_FROMCOLOR1; int lastFromColor = TMT_FROMCOLOR1 + COLOR_SUBCNT - 1; int firstToColor = TMT_TOCOLOR1; int lastToColor = TMT_TOCOLOR1 + COLOR_SUBCNT - 1; while (1) // parse each line { if (_scan.EndOfFile()) break; if (_scan.GetChar('[')) // start of new section break; int iSymType, iValue; _fDefiningColorScheme = TRUE; //---- parse the COLOR or INT property line ---- hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff)); _fDefiningColorScheme = FALSE; if (FAILED(hr)) return hr; //---- store the HUE or COLOR param in local tables ---- if ((iSymType >= firstFromHue) && (iSymType <= lastFromHue)) { if (fCorrectScheme) _bFromHues[iSymType-firstFromHue] = (BYTE)iValue; } else if ((iSymType >= firstToHue) && (iSymType <= lastToHue)) { if (fCorrectScheme) _bToHues[iSymType-firstToHue] = (BYTE)iValue; } else if ((iSymType >= firstFromColor) && (iSymType <= lastFromColor)) { if (fCorrectScheme) _crFromColors[iSymType-firstFromColor] = (COLORREF)iValue; } else if ((iSymType >= firstToColor) && (iSymType <= lastToColor)) { if (fCorrectScheme) _crToColors[iSymType-firstToColor] = (COLORREF)iValue; } else if (iSymType == TMT_DISPLAYNAME) { hr = SafeStringCchCopyW(DisplayName, ARRAYSIZE(DisplayName), szBuff); if (FAILED(hr)) return hr; } else if (iSymType == TMT_TOOLTIP) { hr = SafeStringCchCopyW(ToolTip, ARRAYSIZE(ToolTip), szBuff ); if (FAILED(hr)) return hr; } else { return SourceError(PARSER_IDS_ILLEGAL_CS_PROPERTY); } } if (fCorrectScheme) // adjust counts { _iHueCount = HUE_SUBCNT; while (_iHueCount > 0) { if (_bFromHues[_iHueCount-1] == _bToHues[_iHueCount-1]) _iHueCount--; else break; } _iColorCount = COLOR_SUBCNT; while (_iColorCount > 0) { if (_crFromColors[_iColorCount-1] == _crToColors[_iColorCount-1]) _iColorCount--; else break; } } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_COLORSECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_COLORSCHEME, SchemeName, DisplayName, ToolTip, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } // Create an empty subst table if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, SchemeName, NULL, NULL, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseSizeSection() { HRESULT hr; WCHAR szSizeName[_MAX_PATH+1]; WCHAR szDisplayName[_MAX_PATH+1]; WCHAR szToolTip[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1]; if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN); if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName))) return SourceError(PARSER_IDS_SS_NAME_EXPECTED); if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED); if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED); _scan.ForceNextLine(); // get line after section line while (1) // parse each line of section { if (_scan.EndOfFile()) break; if (_scan.GetChar('[')) // start of new section break; int iSymType, iValue; //---- parse the property line ---- hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff)); if (FAILED(hr)) return hr; if (iSymType == TMT_DISPLAYNAME) { hr = SafeStringCchCopyW(szDisplayName, ARRAYSIZE(szDisplayName), szBuff ); if (FAILED(hr)) return hr; } else if (iSymType == TMT_TOOLTIP) { hr = SafeStringCchCopyW(szToolTip, ARRAYSIZE(szToolTip), szBuff ); if (FAILED(hr)) return hr; } else { return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY); } } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SIZESECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_SIZENAME, szSizeName, szDisplayName, szToolTip, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } // Create an empty subst table if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, NULL, NULL, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseFileSection() { HRESULT hr; WCHAR szSizeName[_MAX_PATH+1]; WCHAR szFileName[_MAX_PATH+1]; WCHAR szColorSchemes[_MAX_PATH+1]; WCHAR szSizes[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1]; if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN); if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName))) return SourceError(PARSER_IDS_FS_NAME_EXPECTED); if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED); if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED); _scan.ForceNextLine(); // get line after section line while (1) // parse each line of section { if (_scan.EndOfFile()) break; if (_scan.GetChar('[')) // start of new section break; int iSymType, iValue; //---- parse the property line ---- hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff)); if (FAILED(hr)) return hr; if (iSymType == TMT_FILENAME) { hr = StringCchCopyW(szFileName, ARRAYSIZE(szFileName), szBuff ); } else if (iSymType == TMT_COLORSCHEMES) { hr = StringCchCopyW(szColorSchemes, ARRAYSIZE(szColorSchemes), szBuff ); } else if (iSymType == TMT_SIZES) { hr = StringCchCopyW(szSizes, ARRAYSIZE(szSizes), szBuff ); } else { return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY); } if (FAILED(hr)) return hr; } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILESECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_CDFILENAME, szSizeName, szFileName, NULL, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); fContinue = (*_pNameCallBack)(TCB_CDFILECOMBO, szSizeName, szColorSchemes, szSizes, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, SUBST_TABLE_INCLUDE, szColorSchemes, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, SUBST_TABLE_INCLUDE, szSizes, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseSubstSection() { WCHAR szSubstTableName[_MAX_PATH+1]; WCHAR szId[MAX_INPUT_LINE+1]; WCHAR szValue[MAX_INPUT_LINE+1]; BOOL fFirst = TRUE; if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN); if (! _scan.GetId(szSubstTableName, ARRAYSIZE(szSubstTableName))) return SourceError(PARSER_IDS_FS_NAME_EXPECTED); if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED); if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED); _scan.ForceNextLine(); // get line after section line while (1) // parse each line of section { if (_scan.EndOfFile()) break; if (_scan.GetChar('[')) // start of new section { // Call the callback once for creating the empty table if (fFirst && (_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName, NULL, NULL, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } break; } //---- parse the property line ---- if (!_scan.GetIdPair(szId, szValue, ARRAYSIZE(szId))) return SourceError(PARSER_IDS_BAD_SUBST_SYMBOL); fFirst = FALSE; _scan.ForceNextLine(); if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName, szId, szValue, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); } } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::GenerateEmptySection(LPCWSTR pszSectionName, int iPartId, int iStateId) { int iStartIndex = 0; if (_pCallBackObj) iStartIndex = _pCallBackObj->GetNextDataIndex(); int index = 0; // will be updated later HRESULT hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index)); if (FAILED(hr)) return hr; if (_pCallBackObj) { int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex; hr = _pCallBackObj->AddIndex(L"", pszSectionName, iPartId, iStateId, iStartIndex, iLen); if (FAILED(hr)) return hr; } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseClassSection(LPCWSTR pszFirstName) { HRESULT hr; int iStartIndex = 0; BOOL fGlobals = (AsciiStrCmpI(pszFirstName, GLOBALS_SECTION_NAME)==0); BOOL fMetrics = (AsciiStrCmpI(pszFirstName, SYSMETRICS_SECTION_NAME)==0); if (fGlobals) { if (_fClassSectionDefined) return SourceError(PARSER_IDS_GLOBALS_MUST_BE_FIRST); } else // regular class section { if (_dwParseFlags & PTF_CLASSDATA_PARSE) { if (! _fGlobalsDefined) // insert an empty [fGlobals] section { hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr; _fGlobalsDefined = true; } if ((! fMetrics) && (! _fMetricsDefined)) // insert an empty [sysmetrics] section { hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr; _fMetricsDefined = true; } else if ((fMetrics) && (_fClassSectionDefined)) return SourceError(PARSER_IDS_METRICS_MUST_COME_BEFORE_CLASSES); } _fClassSectionDefined = TRUE; } WCHAR szAppSym[_MAX_PATH+1]; if (_pCallBackObj) iStartIndex = _pCallBackObj->GetNextDataIndex(); hr = ParseClassSectionName(pszFirstName, szAppSym, ARRAYSIZE(szAppSym)); if (FAILED(hr)) return hr; _scan.ForceNextLine(); // get line after section line while (1) // parse each line { if (_scan.EndOfFile()) break; if (_scan.GetChar('[')) // start of new section break; hr = ParseClassLine(); if (FAILED(hr)) return hr; } //---- end this section of theme data ---- int index = 0; // will be updated later hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index)); if (FAILED(hr)) return hr; if (_pCallBackObj) { int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex; hr = _pCallBackObj->AddIndex(szAppSym, _szClassName, _iPartId, _iStateId, iStartIndex, iLen); if (FAILED(hr)) return hr; } if (fGlobals) _fGlobalsDefined = true; else if (fMetrics) _fMetricsDefined = true; return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseThemeFile(LPCTSTR pszFileName, LPCWSTR pszColorParam, IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags) { _pszDocProperty = NULL; HRESULT hr = InitializeSymbols(); if (FAILED(hr)) goto exit; hr = _scan.AttachFile(pszFileName); // "pszBuffer" contains the filename if (FAILED(hr)) goto exit; if (pszColorParam) { hr = SafeStringCchCopyW(_ColorParam, ARRAYSIZE(_ColorParam), pszColorParam ); if (FAILED(hr)) return hr; } else *_ColorParam = 0; _hinstThemeDll = NULL; hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags); exit: return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseThemeBuffer(LPCWSTR pszBuffer, LPCWSTR pszFileName, LPCWSTR pszColorParam, HINSTANCE hinstThemeDll, IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags, LPCWSTR pszDocProperty, OUT LPWSTR pszResult, DWORD dwMaxResultChars) { _pszDocProperty = pszDocProperty; _pszResult = pszResult; //---- initialize in case not found ---- if (_pszResult) *_pszResult = 0; _dwMaxResultChars = dwMaxResultChars; HRESULT hr = InitializeSymbols(); if (FAILED(hr)) goto exit; _hinstThemeDll = hinstThemeDll; _scan.AttachMultiLineBuffer(pszBuffer, pszFileName); if (pszColorParam) { hr = SafeStringCchCopyW(_ColorParam, ARRAYSIZE(_ColorParam), pszColorParam ); if (FAILED(hr)) return hr; } else *_ColorParam = 0; hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags); //---- make error if doc property not found ---- if ((SUCCEEDED(hr)) && (_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (! *_pszResult)) { hr = MakeError32(ERROR_NOT_FOUND); } exit: return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::LoadResourceProperties() { WCHAR szFullString[2*MAX_PATH]; WCHAR szBaseIniName[_MAX_PATH]; HRESULT hr = S_OK; //---- extract base .ini name ---- WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], ext[_MAX_EXT]; _wsplitpath(_scan._szFileName, drive, dir, szBaseIniName, ext); //---- remove optional "_INI" part ---- LPWSTR pszExt = wcsstr(szBaseIniName, L"_INI"); if (pszExt) *pszExt = 0; //---- read all localizable property name/value pairs into memory ---- for (int i=RES_BASENUM_PROPVALUEPAIRS; ; i++) { if (! LoadString(_hinstThemeDll, i, szFullString, ARRAYSIZE(szFullString))) { //---- no more properties avail ---- break; } StringCchCopyW(_szResPropValue, ARRAYSIZE(_szResPropValue), szFullString); // for proper error reporting _iResPropId = i; //---- does this property belong to current file? ---- LPWSTR pszAtSign = wcschr(szFullString, '@'); if (! pszAtSign) { hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY); break; } //---- zero terminate ini name ---- *pszAtSign = 0; if (lstrcmpi(szBaseIniName, szFullString) != 0) continue; //---- strip off the .ini name for faster comparing ---- LPCWSTR pszName = pszAtSign+1; LPWSTR pszValue = wcschr(pszName, '='); if (pszValue) { pszValue++; // skip over equals sign } else { hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY); break; } //---- add the value ---- CWideString cwValue(pszValue); _PropertyValues.Add(cwValue); //---- zero-terminate the name ---- *pszValue = 0; //---- add the name ---- CWideString cwName(pszName); _PropertyNames.Add(cwName); //---- add the id ---- _iPropertyIds.Add(i); } return hr; } //--------------------------------------------------------------------------- void CThemeParser::EmptyResourceProperties() { _PropertyNames.RemoveAll(); _PropertyValues.RemoveAll(); } //--------------------------------------------------------------------------- HRESULT CThemeParser::GetResourceProperty(LPCWSTR pszPropName, LPWSTR pszValueBuff, int cchValueBuff) { WCHAR szPropTarget[2*MAX_PATH]; HRESULT hr = S_OK; BOOL fFound = FALSE; StringCchPrintfW(szPropTarget, ARRAYSIZE(szPropTarget), L"[%s]%s=", _szFullSectionName, pszPropName); for (int i=0; i < _PropertyNames.m_nSize; i++) { if (AsciiStrCmpI(szPropTarget, _PropertyNames[i])==0) { fFound = TRUE; hr = SafeStringCchCopyW(pszValueBuff, cchValueBuff, _PropertyValues[i]); if (SUCCEEDED(hr)) { hr = SafeStringCchCopyW(_szResPropValue, ARRAYSIZE(_szResPropValue), _PropertyValues[i]); _iResPropId = _iPropertyIds[i]; } break; } } if (! fFound) hr = E_FAIL; return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::ParseThemeScanner(IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags) { HRESULT hr; _pCallBackObj = pCallBack; _pNameCallBack = pNameCallBack; _lNameParam = lNameParam; _dwParseFlags = dwParseFlags; _fClassSectionDefined = FALSE; //---- setup for properties in the .res file ---- EmptyResourceProperties(); _fUsingResourceProperties = (pCallBack != NULL); if (_fUsingResourceProperties) { hr = LoadResourceProperties(); if (FAILED(hr)) goto exit; //---- set the error context for normal .ini parsing ---- *_szResPropValue = 0; // not yet set } //---- scan the first, non-comment WCHAR ---- if (! _scan.GetChar('[')) { if (! _scan.EndOfFile()) { hr = SourceError(PARSER_IDS_LBRACKET_EXPECTED); goto exit; } } while (! _scan.EndOfFile()) // process each section { WCHAR section[_MAX_PATH+1]; _scan.GetId(section); if (AsciiStrCmpI(section, L"documentation")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA); hr = ParseDocSection(); if (_dwParseFlags & PTF_QUERY_DOCPROPERTY) break; // quicker to leave in middle of file } else if (AsciiStrCmpI(section, L"ColorScheme")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA); hr = ParseColorSchemeSection(); } else if (AsciiStrCmpI(section, L"Size")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA); hr = ParseSizeSection(); } else if (AsciiStrCmpI(section, L"File")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA); hr = ParseFileSection(); } else if (AsciiStrCmpI(section, L"Subst")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA); hr = ParseSubstSection(); } else // "globals", "sysmetrics", or class section { if (_dwParseFlags & PTF_CONTAINER_PARSE) return SourceError(PARSER_IDS_BADSECT_THEMES_INI); hr = ParseClassSection(section); } if (FAILED(hr)) goto exit; } //---- check for empty theme ---- if (_dwParseFlags & PTF_CLASSDATA_PARSE) { if (! _fGlobalsDefined) // insert an empty [fGlobals] section { hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr; _fGlobalsDefined = true; } if (! _fMetricsDefined) // insert an empty [sysmetrics] section { hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr; } } hr = S_OK; exit: _outfile.Close(); _pCallBackObj = NULL; _pNameCallBack = NULL; return hr; } //--------------------------------------------------------------------------- HRESULT CThemeParser::GetIntList(int *pInts, LPCWSTR *pParts, int iCount, int iMin, int iMax) { bool bSet[255]; // assume 255 max ints //---- ensure we set each one once ---- for (int i=0; i < iCount; i++) bSet[i] = false; if (wcschr(_scan._p, ':')) { //---- named parts ---- for (int i=0; i < iCount; i++) { WCHAR idbuff[_MAX_PATH+1]; if (! _scan.GetId(idbuff)) return SourceError(PARSER_IDS_VALUE_NAME_EXPECTED, _scan._p); for (int j=0; j < iCount; j++) { if (AsciiStrCmpI(pParts[j], idbuff)==0) break; } if (j == iCount) // unknown part name return SourceError(PARSER_IDS_UNKNOWN_VALUE_NAME, idbuff); if (bSet[j]) // name set twice return SourceError(PARSER_IDS_VALUE_PART_SPECIFIED_TWICE, idbuff); if (! _scan.GetChar(':')) return SourceError(PARSER_IDS_COLOR_EXPECTED, _scan._p); if (! _scan.GetNumber(&pInts[j])) return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p); bSet[j] = true; _scan.GetChar(','); // optional comma } } else { //---- unnamed parts ---- for (int i=0; i < iCount; i++) { if (! _scan.GetNumber(&pInts[i])) return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p); _scan.GetChar(','); // optional comma } } //---- range check ---- if (iMin != iMax) { for (i=0; i < iCount; i++) { if ((pInts[i] < iMin) || (pInts[i] > iMax)) return SourceError(PARSER_IDS_NUMBER_OUT_OF_RANGE); } } return S_OK; } //--------------------------------------------------------------------------- HRESULT CThemeParser::GetPropertyNum(LPCWSTR pszName, int *piPropNum) { //---- for perf, avoid loading all symbols each time this func is called ---- //---- by using "GetSchemaInfo()" ---- //---- get tm & comctl symbols ---- const TMSCHEMAINFO *si = GetSchemaInfo(); int cnt = si->iPropCount; const TMPROPINFO *pi = si->pPropTable; for (int i=0; i < cnt; i++) { if (pi[i].sEnumVal < TMT_FIRST_RCSTRING_NAME) continue; if (pi[i].sEnumVal > TMT_LAST_RCSTRING_NAME) break; if (AsciiStrCmpI(pszName, pi[i].pszName)==0) { *piPropNum = pi[i].sEnumVal - TMT_FIRST_RCSTRING_NAME; // zero based return S_OK; } } return MakeError32(ERROR_NOT_FOUND); }