|
|
//---------------------------------------------------------------------------
// Loader.cpp - loads the theme data into shared memory
//---------------------------------------------------------------------------
#include "stdafx.h"
#include <regstr.h>
#include "Loader.h"
#include "Parser.h"
#include "Utils.h"
#include "TmReg.h"
#include "TmUtils.h"
#include "syscolors.h"
#include "Render.h"
#include "BorderFill.h"
#include "ImageFile.h"
#include "TextDraw.h"
#include "info.h"
//---------------------------------------------------------------------------
#define POINTS_DPI96(pts) -MulDiv(pts, 96, 72)
//---------------------------------------------------------------------------
WCHAR pszColorsKey[] = L"Control Panel\\Colors"; //---------------------------------------------------------------------------
typedef struct { THEMEMETRICS tm; HANDLE hUserToken; } THEMEMETRICS_THREADINFO; //---------------------------------------------------------------------------
CThemeLoader::CThemeLoader() { _pbLocalData = NULL; _iEntryHdrLevel = -1; InitThemeMetrics(&_LoadThemeMetrics); SYSTEM_INFO si;
GetSystemInfo(&si); _dwPageSize = si.dwPageSize; } //---------------------------------------------------------------------------
CThemeLoader::~CThemeLoader() { FreeLocalTheme(); } //---------------------------------------------------------------------------
HRESULT CThemeLoader::LoadClassDataIni(HINSTANCE hInst, LPCWSTR pszColorName, LPCWSTR pszSizeName, LPWSTR pszFoundIniName, DWORD dwMaxIniNameChars, LPWSTR *ppIniData) { COLORSIZECOMBOS *combos; HRESULT hr = FindComboData(hInst, &combos); if (FAILED(hr)) return hr;
int iSizeIndex = 0; int iColorIndex = 0;
if ((pszColorName) && (* pszColorName)) { hr = GetColorSchemeIndex(hInst, pszColorName, &iColorIndex); if (FAILED(hr)) return hr; }
if ((pszSizeName) && (* pszSizeName)) { hr = GetSizeIndex(hInst, pszSizeName, &iSizeIndex); if (FAILED(hr)) return hr; }
int filenum = COMBOENTRY(combos, iColorIndex, iSizeIndex); if (filenum == -1) return MakeError32(ERROR_NOT_FOUND);
//---- locate resname for classdata file "filenum" ----
hr = GetResString(hInst, L"FILERESNAMES", filenum, pszFoundIniName, dwMaxIniNameChars); if (SUCCEEDED(hr)) { hr = AllocateTextResource(hInst, pszFoundIniName, ppIniData); if (FAILED(hr)) return hr; }
return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::LoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam, LPCWSTR pszSizeParam, OUT HANDLE *pHandle, BOOL fGlobalTheme) { HRESULT hr; CThemeParser *pParser = NULL; HINSTANCE hInst = NULL; WCHAR *pThemesIni = NULL; WCHAR *pDataIni = NULL; WCHAR szClassDataName[_MAX_PATH+1];
DWORD dwStartTime = StartTimer();
Log(LOG_TMCHANGE, L"LoadTheme: filename=%s", pszThemeName);
FreeLocalTheme();
//---- allocate a local theme data to construct ----
_pbLocalData = (BYTE*) VirtualAlloc(NULL, MAX_SHAREDMEM_SIZE, MEM_RESERVE, PAGE_READWRITE); if (NULL == _pbLocalData) { hr = MakeError32(E_OUTOFMEMORY); goto exit; } _iLocalLen = 0;
//---- load the Color Scheme from "themes.ini" ----
hr = LoadThemeLibrary(pszThemeName, &hInst); if (FAILED(hr)) goto exit; pParser = new CThemeParser(fGlobalTheme); if (! pParser) { hr = MakeError32(E_OUTOFMEMORY); goto exit; }
//---- if a color scheme is specified, ask parser to load it ----
if ((pszColorParam) && (*pszColorParam)) { //---- load the "themes.ini" text ----
hr = AllocateTextResource(hInst, CONTAINER_RESNAME, &pThemesIni); if (FAILED(hr)) goto exit;
//---- parser call to load color scheme & keep state ----
hr = pParser->ParseThemeBuffer(pThemesIni, CONTAINER_RESNAME, pszColorParam, hInst, this, NULL, NULL, PTF_CONTAINER_PARSE); if (FAILED(hr)) goto exit; }
//---- load the classdata file resource into memory ----
hr = LoadClassDataIni(hInst, pszColorParam, pszSizeParam, szClassDataName, ARRAYSIZE(szClassDataName), &pDataIni); if (FAILED(hr)) goto exit;
//---- parse & build binary theme ----
hr = pParser->ParseThemeBuffer(pDataIni, szClassDataName, pszColorParam, hInst, this, NULL, NULL, PTF_CLASSDATA_PARSE); if (FAILED(hr)) goto exit;
_fGlobalTheme = fGlobalTheme;
hr = PackAndLoadTheme(pszThemeName, pszColorParam, pszSizeParam, hInst); if (FAILED(hr)) goto exit;
if (LogOptionOn(LO_TMLOAD)) { DWORD dwTicks; dwTicks = StopTimer(dwStartTime);
WCHAR buff[100]; TimeToStr(dwTicks, buff, ARRAYSIZE(buff)); Log(LOG_TMLOAD, L"LoadTheme took: %s", buff); }
exit:
if (FAILED(hr) && pParser) { pParser->CleanupStockBitmaps(); }
if (pParser) delete pParser;
if (hInst) FreeLibrary(hInst); if (pThemesIni) delete [] pThemesIni;
if (pDataIni) delete [] pDataIni;
FreeLocalTheme();
if (SUCCEEDED(hr)) { if (_fGlobalTheme) { THEMEHDR *hdr = (THEMEHDR *) _LoadingThemeFile._pbThemeData; hdr->dwFlags |= SECTION_HASSTOCKOBJECTS; }
//---- transfer theme file handle to caller ----
*pHandle = _LoadingThemeFile.Unload(); } else { _LoadingThemeFile.CloseFile(); }
return hr; } //---------------------------------------------------------------------------
void CThemeLoader::FreeLocalTheme() { if (_pbLocalData) { VirtualFree(_pbLocalData, 0, MEM_RELEASE); _pbLocalData = NULL; _iLocalLen = 0; }
_LocalIndexes.RemoveAll(); } //---------------------------------------------------------------------------
HRESULT CThemeLoader::EmitAndCopyBlock(MIXEDPTRS &u, void *pSrc, DWORD dwLen) { HRESULT hr = AllocateThemeFileBytes(u.pb, dwLen); if (FAILED(hr)) return hr;
CopyMemory(u.pb, (BYTE*) pSrc, dwLen); u.pb += dwLen; return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::EmitObject(MIXEDPTRS &u, SHORT propnum, BYTE privnum, void *pHdr, DWORD dwHdrLen, void *pObj, DWORD dwObjLen) { EmitEntryHdr(u, propnum, privnum); HRESULT hr = AllocateThemeFileBytes(u.pb, dwHdrLen + dwObjLen); if (FAILED(hr)) return hr;
CopyMemory(u.pb, (BYTE*) pHdr, dwHdrLen); u.pb += dwHdrLen; CopyMemory(u.pb, (BYTE*) pObj, dwObjLen); u.pb += dwObjLen; EndEntry(u);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::EmitString(MIXEDPTRS &u, LPCWSTR pszSrc, DWORD cchSrc, int *piOffSet) { HRESULT hr = AllocateThemeFileBytes(u.pb, (cchSrc + 1) * sizeof(WCHAR)); if (FAILED(hr)) return hr;
StringCchCopyW(u.px, cchSrc + 1, pszSrc);
if (piOffSet) { *piOffSet = THEME_OFFSET(u.pb); } u.px += cchSrc + 1; return S_OK; } //---------------------------------------------------------------------------
int CThemeLoader::GetMaxState(APPCLASSLOCAL *ac, int iPartNum) { //---- calculate max. state index ----
int iMaxState = -1; int pscnt = ac->PartStateIndexes.GetSize();
for (int i=0; i < pscnt; i++) { PART_STATE_INDEX *psi = &ac->PartStateIndexes[i];
if (psi->iPartNum == iPartNum) { if (psi->iStateNum > iMaxState) iMaxState = psi->iStateNum; } }
return iMaxState; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::CopyPartGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iPartNum, int *piPartJumpTable, int iPartZeroIndex, int iGlobalsOffset, BOOL fGlobalsGroup) { HRESULT hr = S_OK; int *piStateJumpTable = NULL;
//---- calculate max. state index ----
int iMaxState = GetMaxState(ac, iPartNum); if (iMaxState < 0) // no states to copy
goto exit;
//---- update part jump table index ----
if (piPartJumpTable) piPartJumpTable[iPartNum] = THEME_OFFSET(u.pb);
if (iMaxState > 0) // create a state jump table
{ //---- create state jump table ----
hr = EmitEntryHdr(u, TMT_STATEJUMPTABLE, TMT_STATEJUMPTABLE); if (FAILED(hr)) goto exit;
int statecnt = 1 + iMaxState;
hr = AllocateThemeFileBytes(u.pb, 1 + statecnt * sizeof(int)); if (FAILED(hr)) goto exit;
// 1 byte table entry count
*u.pb++ = (BYTE)statecnt;
piStateJumpTable = u.pi;
//---- default "not avail" indexes for children ----
for (int j=0; j < statecnt; j++) *u.pi++ = -1;
EndEntry(u); }
int pscnt, iStateZeroIndex; iStateZeroIndex = THEME_OFFSET(u.pb); pscnt = ac->PartStateIndexes.GetSize();
//---- copy each defined part/state section ----
for (int state=0; state <= iMaxState; state++) { PART_STATE_INDEX *psi = NULL;
//---- find entry for "state" ----
for (int i=0; i < pscnt; i++) { psi = &ac->PartStateIndexes[i];
if ((psi->iPartNum == iPartNum) && (psi->iStateNum == state)) break; }
if (i == pscnt) // not found
continue;
//---- update state jump table entry ----
if (piStateJumpTable) piStateJumpTable[state] = THEME_OFFSET(u.pb);
//---- copy the actual PART/STATE DATA ----
hr = EmitAndCopyBlock(u, _pbLocalData+psi->iIndex, psi->iLen);
//---- update child's "JumpToParent" value ----
if (! state) { if (fGlobalsGroup) { *(u.pi-1) = -1; // end of the line
} else if (! iPartNum) // simple class jumps to globals
{ *(u.pi-1) = iGlobalsOffset; } else // parts jumps to their base class
{ *(u.pi-1) = iPartZeroIndex; } } else // states jumps to their base part
{ *(u.pi-1) = iStateZeroIndex; } }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::CopyClassGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iGlobalsOffset, int iClassNameOffset) { HRESULT hr = S_OK; int *piPartJumpTable = NULL; int *piFirstPackObj = NULL; int partcnt; int iPartZeroIndex; CRenderObj *pRender = NULL; BOOL fGlobals = (iGlobalsOffset == THEME_OFFSET(u.pb));
BYTE *pStartOfSection = u.pb;
BOOL fGlobalGroup = (THEME_OFFSET(u.pb) == iGlobalsOffset);
//---- always create a part table ----
hr = EmitEntryHdr(u, TMT_PARTJUMPTABLE, TMT_PARTJUMPTABLE); if (FAILED(hr)) goto exit;
partcnt = 1 + ac->iMaxPartNum; // offset to first packed DrawObj/TextObj
piFirstPackObj = u.pi; hr = AllocateThemeFileBytes(u.pb, 1 + (1 + partcnt) * sizeof(int)); if (FAILED(hr)) goto exit;
*u.pi++ = 0; // will update later
// partcnt
*u.pb++ = (BYTE)partcnt;
piPartJumpTable = u.pi;
//---- default "not avail" indexes for children ----
for (int j=0; j < partcnt; j++) *u.pi++ = -1;
EndEntry(u);
iPartZeroIndex = THEME_OFFSET(u.pb);
//---- copy each defined part section ----
for (int j=0; j <= ac->iMaxPartNum; j++) { CopyPartGroup(ac, u, j, piPartJumpTable, iPartZeroIndex, iGlobalsOffset, fGlobalGroup); }
//---- now, extract draw objs for each part/state as needed ----
*piFirstPackObj = THEME_OFFSET(u.pb);
//---- build a CRenderObj to access the just copied class section ----
hr = CreateRenderObj(&_LoadingThemeFile, 0, THEME_OFFSET(pStartOfSection), iClassNameOffset, 0, FALSE, NULL, NULL, 0, &pRender); if (FAILED(hr)) goto exit;
if (fGlobals) _iGlobalsDrawObj = THEME_OFFSET(u.pb);
hr = PackDrawObjects(u, pRender, ac->iMaxPartNum, fGlobals); if (FAILED(hr)) goto exit;
if (fGlobals) _iGlobalsTextObj = THEME_OFFSET(u.pb);
hr = PackTextObjects(u, pRender, ac->iMaxPartNum, fGlobals); if (FAILED(hr)) goto exit;
//---- write "end of class" marker ----
hr = EmitEntryHdr(u, TMT_ENDOFCLASS, TMT_ENDOFCLASS); if (FAILED(hr)) goto exit;
EndEntry(u);
exit: delete pRender; return hr; } //---------------------------------------------------------------------------
__inline HRESULT CThemeLoader::AllocateThemeFileBytes(BYTE *upb, DWORD dwAdditionalLen) { ASSERT(upb != NULL && _LoadingThemeFile._pbThemeData != NULL);
if (PtrToUint(upb) / _dwPageSize != PtrToUint(upb + dwAdditionalLen) / _dwPageSize) { if (NULL == VirtualAlloc(_LoadingThemeFile._pbThemeData, upb - _LoadingThemeFile._pbThemeData + 1 + dwAdditionalLen, MEM_COMMIT, PAGE_READWRITE)) { return MakeError32(ERROR_NOT_ENOUGH_MEMORY); } } return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::CopyLocalThemeToLive(int iTotalLength, LPCWSTR pszThemeName, LPCWSTR pszColorParam, LPCWSTR pszSizeParam) { int i; MIXEDPTRS u; HRESULT hr = S_OK;
u.pb = (BYTE*) VirtualAlloc(_LoadingThemeFile._pbThemeData, sizeof(THEMEHDR), MEM_COMMIT, PAGE_READWRITE); if (u.pb == NULL) { return MakeError32(ERROR_NOT_ENOUGH_MEMORY); }
_iGlobalsOffset = -1; _iSysMetricsOffset = -1; int iIndexCount = _LocalIndexes.GetSize();
//---- build header ----
THEMEHDR *hdr = (THEMEHDR *)u.pb; u.pb += sizeof(THEMEHDR);
hdr->dwTotalLength = iTotalLength;
CopyMemory(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature); // note: hdr->szSignature should not be null terminated
hdr->dwVersion = THEMEDATA_VERSION; hdr->dwFlags = 0; // not yet ready to be accessed
hdr->iDllNameOffset = 0; // will be updated
hdr->iColorParamOffset = 0; // will be updated
hdr->iSizeParamOffset = 0; // will be updated
hdr->dwLangID = (DWORD) GetUserDefaultUILanguage(); hdr->iLoadId = 0; // was iLoadCounter
hdr->iGlobalsOffset = 0; // will be updated
hdr->iGlobalsTextObjOffset = 0; // will be updated
hdr->iGlobalsDrawObjOffset = 0; // will be updated
hdr->dwCheckSum = 0; // will be updated
// Store the time stamp of the .msstyles file in the live file, this will be written to the cache file
// for later comparison (Whistler:190202).
ZeroMemory(&hdr->ftModifTimeStamp, sizeof hdr->ftModifTimeStamp);
HANDLE hFile = CreateFile(pszThemeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) { // There's nothing we can do if GetFileTime() fails
GetFileTime(hFile, NULL, NULL, &hdr->ftModifTimeStamp); CloseHandle(hFile); }
//---- build string section ----
hdr->iStringsOffset = THEME_OFFSET(u.pb); DWORD *pdwFirstString = u.pdw; int len;
//---- add header strings ----
len = lstrlen(pszThemeName); if (len) { hr = EmitString(u, pszThemeName, len, &hdr->iDllNameOffset); if (FAILED(hr)) goto exit; } len = lstrlen(pszColorParam); if (len) { hr = EmitString(u, pszColorParam, len, &hdr->iColorParamOffset); if (FAILED(hr)) goto exit; } len = lstrlen(pszSizeParam); if (len) { hr = EmitString(u, pszSizeParam, len, &hdr->iSizeParamOffset); if (FAILED(hr)) goto exit; }
//---- add strings from class index ----
for (i=0; i < iIndexCount; i++) { APPCLASSLOCAL *ac = &_LocalIndexes[i];
int len = ac->csAppName.GetLength(); if (len) { hr = EmitString(u, ac->csAppName, len, (int*) &ac->LiveIndex.dwAppNameIndex); if (FAILED(hr)) goto exit; } else ac->LiveIndex.dwAppNameIndex = 0;
len = ac->csClassName.GetLength(); if (len) { hr = EmitString(u, ac->csClassName, len, (int*) &ac->LiveIndex.dwClassNameIndex); if (FAILED(hr)) goto exit; } else ac->LiveIndex.dwClassNameIndex = 0; }
//---- copy strings from LOADTHEMEMETRICS -----
for (i=0; i < TM_STRINGCOUNT; i++) { CWideString *ws = &_LoadThemeMetrics.wsStrings[i]; int len = ws->GetLength(); if (len) { hr = EmitString(u, *ws, len, &_LoadThemeMetrics.iStringOffsets[i]); if (FAILED(hr)) goto exit; } else _LoadThemeMetrics.iStringOffsets[i] = 0; }
int iStringLength = int(u.pb - ((BYTE *)pdwFirstString)); hdr->iStringsLength = iStringLength;
//---- write index header ----
hdr->iSectionIndexOffset = THEME_OFFSET(u.pb); hdr->iSectionIndexLength = iIndexCount * sizeof(APPCLASSLIVE);
APPCLASSLIVE *acl = (APPCLASSLIVE *)u.pb; // will write these in parallel with theme data
hr = AllocateThemeFileBytes(u.pb, hdr->iSectionIndexLength); if (FAILED(hr)) goto exit;
u.pb += hdr->iSectionIndexLength;
//---- write index AND theme data in parallel ----
//---- first pass thru, copy [globals] and all [app::xxx] sections ----
for (i=0; i < iIndexCount; i++) // for each parent section
{ APPCLASSLOCAL *ac = &_LocalIndexes[i];
if ((i) && (! ac->LiveIndex.dwAppNameIndex)) // not an [app::] section
continue;
acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex; acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
acl->iIndex = THEME_OFFSET(u.pb);
if (AsciiStrCmpI(ac->csClassName, L"globals")== 0) // globals section
_iGlobalsOffset = acl->iIndex;
hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex); if (FAILED(hr)) goto exit;
acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex;
acl++; }
//---- second pass thru, copy all non-[app::xxx] sections (except [globals]) ----
for (i=0; i < iIndexCount; i++) // for each parent section
{ APPCLASSLOCAL *ac = &_LocalIndexes[i];
if ((! i) || (ac->LiveIndex.dwAppNameIndex)) // don't process [app::] sections
continue;
acl->dwAppNameIndex = ac->LiveIndex.dwAppNameIndex; acl->dwClassNameIndex = ac->LiveIndex.dwClassNameIndex;
acl->iIndex = THEME_OFFSET(u.pb);
if (AsciiStrCmpI(ac->csClassName, L"sysmetrics")== 0) // SysMetrics section
{ _iSysMetricsOffset = acl->iIndex;
hr = EmitEntryHdr(u, TMT_THEMEMETRICS, TMT_THEMEMETRICS); if (FAILED(hr)) goto exit;
DWORD len = sizeof(THEMEMETRICS); hr = EmitAndCopyBlock(u, (BYTE*) (THEMEMETRICS*) &_LoadThemeMetrics, len);
EndEntry(u);
//---- add a "jump to parent" to be consistent (not used) ----
hr = EmitEntryHdr(u, TMT_JUMPTOPARENT, TMT_JUMPTOPARENT); if (FAILED(hr)) goto exit;
hr = AllocateThemeFileBytes(u.pb, sizeof(int)); if (FAILED(hr)) goto exit;
*u.pi++ = -1; EndEntry(u); } else // regular section
{ hr = CopyClassGroup(ac, u, _iGlobalsOffset, acl->dwClassNameIndex); if (FAILED(hr)) goto exit; }
acl->iLen = THEME_OFFSET(u.pb) - acl->iIndex; acl++; }
hr = EmitAndCopyBlock(u, (BYTE*) kszEndCacheFileSignature, kcbEndSignature); if (FAILED(hr)) goto exit; //---- ensure we got the calc size right ----
DWORD dwActualLen; dwActualLen = THEME_OFFSET(u.pb); if (hdr->dwTotalLength != dwActualLen) { //---- make this growable so we really have enough room ----
//Log(LOG_TMCHANGE, L"ThemeLoader - calculated len=%d, actual len=%d",
// hdr->dwTotalLength, dwActualLen);
hdr->dwTotalLength = dwActualLen; }
Log(LOG_TMCHANGE, L"ThemeLoader - theme size: %d", dwActualLen);
//----- update header fields ----
hdr->dwFlags |= SECTION_READY; hdr->iGlobalsOffset = _iGlobalsOffset; hdr->iSysMetricsOffset = _iSysMetricsOffset; hdr->iGlobalsTextObjOffset = _iGlobalsTextObj; hdr->iGlobalsDrawObjOffset = _iGlobalsDrawObj; hdr->dwCheckSum = 0; // Reserved for future use. (old checksum was too slow.).
exit: return hr;
} //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackMetrics() { //---- find the optional [SysMetrics] section ----
int iIndexCount = _LocalIndexes.GetSize(); APPCLASSLOCAL *ac = NULL;
for (int i=0; i < iIndexCount; i++) { ac = &_LocalIndexes[i]; if (AsciiStrCmpI(ac->csClassName, L"SysMetrics")==0) break; }
if (i == iIndexCount) // not found
return S_OK; //---- walk thru the properties & put into _LoadThemeMetrics ----
if (! ac->PartStateIndexes.GetSize()) // no data
return S_OK;
MIXEDPTRS u; //---- parts & states not allowed so just use entry "0" ----
u.pb = _pbLocalData + ac->PartStateIndexes[0].iIndex; UCHAR *lastpb = u.pb + ac->PartStateIndexes[0].iLen;
while ((u.pb < lastpb) && (*u.pw != TMT_JUMPTOPARENT)) { UNPACKED_ENTRYHDR hdr;
FillAndSkipHdr(u, &hdr);
switch (hdr.ePrimVal) { case TMT_FONT: _LoadThemeMetrics.lfFonts[hdr.usTypeNum-TMT_FIRSTFONT] = *(LOGFONT *)u.pb; break;
case TMT_COLOR: _LoadThemeMetrics.crColors[hdr.usTypeNum-TMT_FIRSTCOLOR] = *(COLORREF *)u.pb; break;
case TMT_BOOL: _LoadThemeMetrics.fBools[hdr.usTypeNum-TMT_FIRSTBOOL] = (BOOL)*u.pb; break;
case TMT_SIZE: _LoadThemeMetrics.iSizes[hdr.usTypeNum-TMT_FIRSTSIZE] = *(int *)u.pb; break;
case TMT_INT: _LoadThemeMetrics.iInts[hdr.usTypeNum-TMT_FIRSTINT] = *(int *)u.pb; break;
case TMT_STRING: _LoadThemeMetrics.wsStrings[hdr.usTypeNum-TMT_FIRSTSTRING] = (WCHAR *)u.pb; break; }
u.pb += hdr.dwDataLen; // skip to next entry
}
//---- compute packed size of theme metrics ----
//---- the actual entry ----
ac->iPackedSize = ENTRYHDR_SIZE + sizeof(THEMEMETRICS);
//---- a "jump to parent" entry ----
ac->iPackedSize += ENTRYHDR_SIZE + sizeof(int);
//---- add strings used in sysmetrics ----
for (i=0; i < TM_STRINGCOUNT; i++) { int len = _LoadThemeMetrics.wsStrings[i].GetLength(); ac->iPackedSize += sizeof(WCHAR)*(1 + len); } return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackThemeStructs() { HRESULT hr = PackMetrics(); if (FAILED(hr)) return hr;
//---- IMAGEDATA and TEXTDATA packing go here ----
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackAndLoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam, LPCWSTR pszSizeParam, HINSTANCE hInst) { WCHAR szColor[MAX_PATH]; WCHAR szSize[MAX_PATH];
HRESULT hr = PackThemeStructs();
//---- if color not specifed, get default color ----
if ((! pszColorParam) || (! *pszColorParam)) { hr = GetResString(hInst, L"COLORNAMES", 0, szColor, ARRAYSIZE(szColor)); if (FAILED(hr)) goto exit;
pszColorParam = szColor; }
//---- if size not specifed, get default size ----
if ((! pszSizeParam) || (! *pszSizeParam)) { hr = GetResString(hInst, L"SIZENAMES", 0, szSize, ARRAYSIZE(szSize)); if (FAILED(hr)) goto exit;
pszSizeParam = szSize; }
hr = _LoadingThemeFile.CreateFile(MAX_SHAREDMEM_SIZE, TRUE); if (FAILED(hr)) goto exit;
//---- copy local theme data to live ----
hr = CopyLocalThemeToLive(MAX_SHAREDMEM_SIZE, pszThemeName, pszColorParam, pszSizeParam); if (FAILED(hr)) goto exit;
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::AddMissingParent(LPCWSTR pszAppName, LPCWSTR pszClassName, int iPartNum, int iStateNum) { //---- add missing parent section ----
int iData = 0; int iStart = GetNextDataIndex();
HRESULT hr = AddData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &iData, sizeof(iData)); if (FAILED(hr)) return hr;
int iLen = GetNextDataIndex() - iStart; hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum, iStart, iLen); if (FAILED(hr)) return hr; return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName, int iPartNum, int iStateNum, int iIndex, int iLen) { HRESULT hr;
if (iPartNum) // ensure parent exists
{ if (! IndexExists(pszAppName, pszClassName, 0, 0)) { hr = AddMissingParent(pszAppName, pszClassName, 0, 0); if (FAILED(hr)) return hr; } }
if (iStateNum) // ensure parent exists
{ if (! IndexExists(pszAppName, pszClassName, iPartNum, 0)) { hr = AddMissingParent(pszAppName, pszClassName, iPartNum, 0); if (FAILED(hr)) return hr; } }
hr = AddIndexInternal(pszAppName, pszClassName, iPartNum, iStateNum, iIndex, iLen); if (FAILED(hr)) return hr; return S_OK; } //---------------------------------------------------------------------------
BOOL CThemeLoader::IndexExists(LPCWSTR pszAppName, LPCWSTR pszClassName, int iPartNum, int iStateNum) { //---- try to find existing entry ----
int cnt = _LocalIndexes.GetSize();
for (int i=0; i < cnt; i++) { LPCWSTR localAppName = _LocalIndexes[i].csAppName;
if ((pszAppName) && (*pszAppName)) { if ((! localAppName) || (! *localAppName)) continue; if (AsciiStrCmpI(pszAppName, localAppName) != 0) continue; } else if ((localAppName) && (*localAppName)) continue;
if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0) break; }
if (i == cnt) // not found
return FALSE;
//---- find matching child info ----
APPCLASSLOCAL *acl = &_LocalIndexes[i];
for (int c=0; c < acl->PartStateIndexes.m_nSize; c++) { if (acl->PartStateIndexes[c].iPartNum == iPartNum) { if (acl->PartStateIndexes[c].iStateNum == iStateNum) return TRUE; } }
return FALSE; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::AddIndexInternal(LPCWSTR pszAppName, LPCWSTR pszClassName, int iPartNum, int iStateNum, int iIndex, int iLen) { //---- try to find existing entry ----
int cnt = _LocalIndexes.GetSize();
for (int i=0; i < cnt; i++) { LPCWSTR localAppName = _LocalIndexes[i].csAppName;
if ((pszAppName) && (*pszAppName)) { if ((! localAppName) || (! *localAppName)) continue; if (AsciiStrCmpI(pszAppName, localAppName) != 0) continue; } else if ((localAppName) && (*localAppName)) continue;
if (AsciiStrCmpI(pszClassName, _LocalIndexes[i].csClassName)==0) break; }
APPCLASSLOCAL *acl;
if (i == cnt) // not found - create a new entry
{ APPCLASSLOCAL local;
local.csAppName = pszAppName; local.csClassName = pszClassName; local.iMaxPartNum = 0; local.iPackedSize = 0;
_LocalIndexes.Add(local);
int last = _LocalIndexes.GetSize()-1; acl = &_LocalIndexes[last]; } else // update existing entry with child info
{ acl = &_LocalIndexes[i];
// child info should not be there already
for (int c=0; c < acl->PartStateIndexes.m_nSize; c++) { if (acl->PartStateIndexes[c].iPartNum == iPartNum) { if (acl->PartStateIndexes[c].iStateNum == iStateNum) { return MakeError32(ERROR_ALREADY_EXISTS); } } } }
//---- add the part ----
if (iPartNum > acl->iMaxPartNum) acl->iMaxPartNum = iPartNum;
PART_STATE_INDEX psi; psi.iPartNum = iPartNum; psi.iStateNum = iStateNum; psi.iIndex = iIndex; psi.iLen = iLen;
acl->PartStateIndexes.Add(psi);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen) { DWORD dwFullLen = ENTRYHDR_SIZE + dwLen; HRESULT hr; BYTE bFiller = ALIGN_FACTOR - 1;
MIXEDPTRS u; u.pb = _pbLocalData + _iLocalLen;
//---- add to local copy of theme data ----
if ((PtrToUint(u.pb) / _dwPageSize != PtrToUint(u.pb + dwFullLen + bFiller) / _dwPageSize) || _iLocalLen == 0) { if (NULL == VirtualAlloc(_pbLocalData, _iLocalLen + 1 + dwFullLen + bFiller, MEM_COMMIT, PAGE_READWRITE)) { return MakeError32(ERROR_NOT_ENOUGH_MEMORY); } }
hr = EmitEntryHdr(u, sTypeNum, ePrimVal); if (FAILED(hr)) goto exit;
if (dwLen) { CopyMemory(u.pb, pData, dwLen); u.pb += dwLen; }
//---- this may generate filler bytes ----
bFiller = (BYTE)EndEntry(u);
_iLocalLen += (dwFullLen + bFiller);
exit: return hr; } //---------------------------------------------------------------------------
int CThemeLoader::GetNextDataIndex() { return _iLocalLen; } //---------------------------------------------------------------------------
void SetSysBool(THEMEMETRICS* ptm, int iBoolNum, int iSpiSetNum) { BOOL fVal = ptm->fBools[iBoolNum - TMT_FIRSTBOOL]; BOOL fSet = ClassicSystemParametersInfo(iSpiSetNum, 0, IntToPtr(fVal), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); if (! fSet) { Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo() call to set BOOL"); } } //---------------------------------------------------------------------------
void SetSystemMetrics_Worker(THEMEMETRICS* ptm) { #ifdef DEBUG
if (LogOptionOn(LO_TMLOAD)) { WCHAR szUserName[MAX_PATH]; DWORD dwSize = ARRAYSIZE(szUserName); GetUserName(szUserName, &dwSize);
Log(LOG_TMLOAD, L"SetSystemMetrics_Worker: User=%s, SM_REMOTESESSION=%d", szUserName, GetSystemMetrics(SM_REMOTESESSION)); } #endif
//---- apply nonclient metrics ----
NONCLIENTMETRICS ncm = {sizeof(ncm)}; BOOL fSet;
//----- scale all sizes from 96-dpi to match current screen logical DPI ----
ncm.iBorderWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE]);
ncm.iCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE]); ncm.iCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE]); ncm.iSmCaptionWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE]); ncm.iSmCaptionHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE]); ncm.iMenuWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE]); ncm.iMenuHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE]); ncm.iScrollWidth = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE]); ncm.iScrollHeight = ScaleSizeForScreenDpi(ptm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE]);
//---- transfer font info (stored internally at 96 dpi) ----
ncm.lfCaptionFont = ptm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT]; ncm.lfSmCaptionFont = ptm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT]; ncm.lfMenuFont = ptm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT]; ncm.lfStatusFont = ptm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT]; ncm.lfMessageFont = ptm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT];
//---- scale fonts (from 96 dpi to current screen dpi) ----
ScaleFontForScreenDpi(&ncm.lfCaptionFont); ScaleFontForScreenDpi(&ncm.lfSmCaptionFont); ScaleFontForScreenDpi(&ncm.lfMenuFont); ScaleFontForScreenDpi(&ncm.lfStatusFont); ScaleFontForScreenDpi(&ncm.lfMessageFont);
fSet = ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); if (! fSet) { Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETNONCLIENTMETRICS)"); }
//---- apply the remaining font ----
LOGFONT lf = ptm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT]; ScaleFontForScreenDpi(&lf); fSet = ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT, sizeof(LOGFONT), &lf, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE); if (! fSet) { Log(LOG_ALWAYS, L"Error returned from ClassicSystemParametersInfo(SPI_SETICONTITLELOGFONT)"); }
//---- apply the sys bools (one at a time, unfortunately) ----
SetSysBool(ptm, TMT_FLATMENUS, SPI_SETFLATMENU);
//---- apply system colors ----
int iIndexes[TM_COLORCOUNT]; for (int i=0; i < TM_COLORCOUNT; i++) { iIndexes[i] = i; }
fSet = SetSysColors(TM_COLORCOUNT, iIndexes, ptm->crColors); if (! fSet) { Log(LOG_ALWAYS, L"Error returned from SetSysColors()"); }
HRESULT hr = PersistSystemColors(ptm); // write them to registry
if (FAILED(hr)) { Log(LOG_ALWAYS, L"failed to persist SysColors"); } } //---------------------------------------------------------------------------
STDAPI_(DWORD) SetSystemMetrics_WorkerThread(void* pv) { THEMEMETRICS_THREADINFO* ptm = (THEMEMETRICS_THREADINFO*)pv; ASSERT(ptm); BOOL fSuccess = TRUE;
if (ptm->hUserToken) { fSuccess = ImpersonateLoggedOnUser(ptm->hUserToken);
if (!fSuccess) { Log(LOG_ALWAYS, L"ImpersonateLoggedOnUser failed in SetSystemMetrics"); } } if (fSuccess) { SetSystemMetrics_Worker(&ptm->tm); }
if (ptm->hUserToken) { if (fSuccess) { RevertToSelf(); } CloseHandle(ptm->hUserToken); } LocalFree(ptm); FreeLibraryAndExitThread(g_hInst, 0); } //---------------------------------------------------------------------------
void SetSystemMetrics(THEMEMETRICS* ptm, BOOL fSyncLoad) { if (ptm != NULL) { BOOL fSuccess = FALSE; HMODULE hmod;
if (!fSyncLoad) // ok to use a new thread
{ // add a dllref for the thread we are creating
hmod = LoadLibrary(TEXT("uxtheme.dll")); if (hmod) { THEMEMETRICS_THREADINFO* ptmCopy = (THEMEMETRICS_THREADINFO*)LocalAlloc(LPTR, sizeof(THEMEMETRICS_THREADINFO));
if (ptmCopy) { // fill in all of the thememetrics info for the thread we are going to create
CopyMemory(ptmCopy, ptm, sizeof(THEMEMETRICS));
HANDLE hToken = NULL; // If the calling thread is impersonating, use the same token
// OpenThreadToken can fail if the thread is not impersonating
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, &hToken)) { ptmCopy->hUserToken = hToken;
// we want to do this async since we end up calling xxxSendMessage for a TON of things which blocks this
// thread which can cause deadlocks
HANDLE hThread = CreateThread(NULL, 0, SetSystemMetrics_WorkerThread, ptmCopy, 0, NULL);
if (hThread) { CloseHandle(hThread); fSuccess = TRUE; } } else { Log(LOG_TMCHANGE, L"OpenThreadToken failed in SetSystemMetrics, last error=%d", GetLastError()); }
if (!fSuccess) { LocalFree(ptmCopy); } }
if (!fSuccess) { FreeLibrary(hmod); } } }
if (!fSuccess) { // failed, fall back to calling synchronously
SetSystemMetrics_Worker(ptm); } } } //---------------------------------------------------------------------------
void SetFont(LOGFONT *plf, LPCWSTR lszFontName, int iPointSize) { memset(plf, 0, sizeof(*plf));
plf->lfWeight = FW_NORMAL; plf->lfCharSet = DEFAULT_CHARSET; plf->lfHeight = iPointSize;
StringCchCopyW(plf->lfFaceName, ARRAYSIZE(plf->lfFaceName), lszFontName); } //---------------------------------------------------------------------------
COLORREF DefaultColors[] = { RGB(212, 208, 200), // Scrollbar (0)
RGB(58, 110, 165), // Background (1)
RGB(10, 36, 106), // ActiveCaption (2)
RGB(128, 128, 128), // InactiveCaption (3)
RGB(212, 208, 200), // Menu (4)
RGB(255, 255, 255), // Window (5)
RGB(0, 0, 0), // WindowFrame (6)
RGB(0, 0, 0), // MenuText (7)
RGB(0, 0, 0), // WindowText (8)
RGB(255, 255, 255), // CaptionText (9)
RGB(212, 208, 200), // ActiveBorder (10)
RGB(212, 208, 200), // InactiveBorder (11)
RGB(128, 128, 128), // AppWorkSpace (12)
RGB(10, 36, 106), // Highlight (13)
RGB(255, 255, 255), // HighlightText (14)
RGB(212, 208, 200), // BtnFace (15)
RGB(128, 128, 128), // BtnShadow (16)
RGB(128, 128, 128), // GrayText (17)
RGB(0, 0, 0), // BtnText (18)
RGB(212, 208, 200), // InactiveCaptionText (19)
RGB(255, 255, 255), // BtnHighlight (20)
RGB(64, 64, 64), // DkShadow3d (21)
RGB(212, 208, 200), // Light3d (22)
RGB(0, 0, 0), // InfoText (23)
RGB(255, 255, 225), // InfoBk (24)
RGB(181, 181, 181), // ButtonAlternateFace (25)
RGB(0, 0, 128), // HotTracking (26)
RGB(166, 202, 240), // GradientActiveCaption (27)
RGB(192, 192, 192), // GradientInactiveCaption (28)
RGB(206, 211, 225), // MenuiHilight (29)
RGB(244, 244, 240), // MenuBar (30)
}; //---------------------------------------------------------------------------
HRESULT InitThemeMetrics(LOADTHEMEMETRICS *tm) { memset(tm, 0, sizeof(*tm)); // zero out in case we miss a property
//---- init fonts ----
SetFont(&tm->lfFonts[TMT_CAPTIONFONT - TMT_FIRSTFONT], L"tahoma bold", POINTS_DPI96(8)); SetFont(&tm->lfFonts[TMT_SMALLCAPTIONFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8)); SetFont(&tm->lfFonts[TMT_MENUFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8)); SetFont(&tm->lfFonts[TMT_STATUSFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8)); SetFont(&tm->lfFonts[TMT_MSGBOXFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8)); SetFont(&tm->lfFonts[TMT_ICONTITLEFONT - TMT_FIRSTFONT], L"tahoma", POINTS_DPI96(8));
//---- init bools ----
tm->fBools[TMT_FLATMENUS - TMT_FIRSTBOOL] = FALSE;
//---- init sizes ----
tm->iSizes[TMT_SIZINGBORDERWIDTH - TMT_FIRSTSIZE] = 1; tm->iSizes[TMT_SCROLLBARWIDTH - TMT_FIRSTSIZE] = 16; tm->iSizes[TMT_SCROLLBARHEIGHT - TMT_FIRSTSIZE] = 16; tm->iSizes[TMT_CAPTIONBARWIDTH - TMT_FIRSTSIZE] = 18; tm->iSizes[TMT_CAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19; tm->iSizes[TMT_SMCAPTIONBARWIDTH - TMT_FIRSTSIZE] = 12; tm->iSizes[TMT_SMCAPTIONBARHEIGHT - TMT_FIRSTSIZE] = 19; tm->iSizes[TMT_MENUBARWIDTH - TMT_FIRSTSIZE] = 18; tm->iSizes[TMT_MENUBARHEIGHT - TMT_FIRSTSIZE] = 19;
//---- init strings ----
tm->iStringOffsets[TMT_CSSNAME - TMT_FIRSTSTRING] = 0; tm->iStringOffsets[TMT_XMLNAME - TMT_FIRSTSTRING] = 0;
tm->wsStrings[TMT_CSSNAME - TMT_FIRSTSTRING] = L""; tm->wsStrings[TMT_XMLNAME - TMT_FIRSTSTRING] = L""; //---- init ints ----
tm->iInts[TMT_MINCOLORDEPTH - TMT_FIRSTINT] = 16;
//---- init colors ----
for (int i=0; i < TM_COLORCOUNT; i++) tm->crColors[i] = DefaultColors[i];
return S_OK; } //---------------------------------------------------------------------------
HRESULT PersistSystemColors(THEMEMETRICS *tm) { HRESULT hr; LONG lErrorCode; HKEY hkcu; CCurrentUser hKeyCurrentUser(KEY_SET_VALUE);
lErrorCode = RegOpenKeyEx(hKeyCurrentUser, REGSTR_PATH_COLORS, 0, KEY_SET_VALUE, &hkcu); if (ERROR_SUCCESS == lErrorCode) { hr = S_OK;
//---- believe it or not, we have to manually write each color ----
//---- as a string to the registry to persist them ----
ASSERT(iSysColorSize == TM_COLORCOUNT); // should also match winuser.h entries
//---- are gradients turned on? ----
BOOL fGradientsEnabled = FALSE; ClassicSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&fGradientsEnabled, 0);
//---- enough colors for a gradient? ----
HDC hdc = GetDC(NULL); if (hdc) { if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) fGradientsEnabled = FALSE; ReleaseDC(NULL, hdc); }
for (int i=0; i < iSysColorSize; i++) { // If this is the Gradient Caption setting and the system does
// not currently show gradient captions then don't write them out
// to the theme file.
if ((i == COLOR_GRADIENTACTIVECAPTION) || (i == COLOR_GRADIENTINACTIVECAPTION)) { if (! fGradientsEnabled) continue; }
//---- translate color into "r, g, b" value string ----
WCHAR buff[100]; COLORREF cr = tm->crColors[i]; StringCchPrintfW(buff, ARRAYSIZE(buff), L"%d %d %d", RED(cr), GREEN(cr), BLUE(cr));
//---- write color key/value to registry ----
lErrorCode = RegSetValueEx(hkcu, pszSysColorNames[i], 0, REG_SZ, reinterpret_cast<BYTE*>(buff), (lstrlen(buff) + 1) * sizeof(WCHAR)); if (ERROR_SUCCESS != lErrorCode) { if (SUCCEEDED(hr)) { hr = MakeError32(lErrorCode); } } } (LONG)RegCloseKey(hkcu); } else { hr = MakeError32(lErrorCode); }
return hr; } //---------------------------------------------------------------------------
BOOL CThemeLoader::KeyDrawPropertyFound(int iStateDataOffset) { BOOL fFound = FALSE; MIXEDPTRS u; UNPACKED_ENTRYHDR hdr; u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
while (*u.ps != TMT_JUMPTOPARENT) { if (CBorderFill::KeyProperty((*u.ps))) { fFound = TRUE; break; }
if (CImageFile::KeyProperty((*u.ps))) { fFound = TRUE; break; }
//---- skip to next entry ----
FillAndSkipHdr(u, &hdr); u.pb += hdr.dwDataLen; }
return fFound; } //---------------------------------------------------------------------------
BOOL CThemeLoader::KeyTextPropertyFound(int iStateDataOffset) { BOOL fFound = FALSE; MIXEDPTRS u; UNPACKED_ENTRYHDR hdr;
u.pb = _LoadingThemeFile._pbThemeData + iStateDataOffset;
while (*u.ps != TMT_JUMPTOPARENT) { if (CTextDraw::KeyProperty((*u.ps))) { fFound = TRUE; break; }
//---- skip to next entry ----
FillAndSkipHdr(u, &hdr); u.pb += hdr.dwDataLen; }
return fFound; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackImageFileInfo(DIBINFO *pdi, CImageFile *pImageObj, MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId) { HRESULT hr = S_OK;
//---- write custom region data ----
int iMaxState; if ((! iStateId) && (pImageObj->HasRegionImageFile(pdi, &iMaxState))) { //---- update object's _iRgnDataOffset field ----
pImageObj->SetRgnListOffset(pdi, THEME_OFFSET(u.pb));
//---- write the TMT_RGNLIST entry ----
hr = EmitEntryHdr(u, TMT_RGNLIST, TMT_RGNLIST); if (FAILED(hr)) goto exit;
int cEntries = iMaxState + 1; // number of jump table entries
hr = AllocateThemeFileBytes(u.pb, 1 + cEntries * sizeof(int)); if (FAILED(hr)) goto exit;
*u.pb++ = static_cast<BYTE>(cEntries);
//---- write jump table now and update asap ----
int *piJumpTable = u.pi;
for (int i=0; i <= iMaxState; i++) *u.pi++ = 0;
for (int iRgnState=0; iRgnState <= iMaxState; iRgnState++) { //---- build & pack custom region data for each state in this object's imagefile ----
CAutoArrayPtr<RGNDATA> pRgnData; int iDataLen;
hr = pImageObj->BuildRgnData(pdi, pRender, iRgnState, &pRgnData, &iDataLen); if (FAILED(hr)) goto exit;
if (iDataLen) // if we got a non-empty region
{ piJumpTable[iRgnState] = THEME_OFFSET(u.pb);
RGNDATAHDR rdHdr = {iPartId, iRgnState, 0};
//---- copy rgndata hdr ----
hr = EmitObject(u, TMT_RGNDATA, TMT_RGNDATA, &rdHdr, sizeof(rdHdr), pRgnData, iDataLen); if (FAILED(hr)) goto exit; } }
EndEntry(u); }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackDrawObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId) { HRESULT hr = S_OK;
BGTYPE eBgType; if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_BGTYPE, (int *)&eBgType))) eBgType = BT_BORDERFILL; // default value
DRAWOBJHDR hdr = {iPartId, iStateId};
if ((eBgType == BT_BORDERFILL) || (eBgType == BT_NONE)) { CBorderFill bfobj;
hr = bfobj.PackProperties(pRender, (eBgType == BT_NONE), iPartId, iStateId); if (FAILED(hr)) goto exit;
//---- copy "bfobj" to packed bytes ----
hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &bfobj, sizeof(bfobj)); if (FAILED(hr)) goto exit; } else // imagefile
{ CMaxImageFile maxif; int iMultiCount;
hr = maxif.PackMaxProperties(pRender, iPartId, iStateId, &iMultiCount); if (FAILED(hr)) goto exit;
//---- process all DIBINFO structs in the CImageFile obj ----
for (int i=0; ; i++) { DIBINFO *pdi = maxif.EnumImageFiles(i); if (! pdi) break; hr = PackImageFileInfo(pdi, &maxif, u, pRender, iPartId, iStateId); if (FAILED(hr)) goto exit; }
//---- copy imagefile obj & multi DIB's to packed bytes ----
DWORD dwLen = sizeof(CImageFile) + sizeof(DIBINFO)*iMultiCount;
hr = EmitObject(u, TMT_DRAWOBJ, TMT_DRAWOBJ, &hdr, sizeof(hdr), &maxif, dwLen); if (FAILED(hr)) goto exit; }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackTextObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId) { HRESULT hr; DRAWOBJHDR hdr = {iPartId, iStateId}; CTextDraw ctobj;
hr = ctobj.PackProperties(pRender, iPartId, iStateId); if (FAILED(hr)) goto exit;
hr = EmitObject(u, TMT_TEXTOBJ, TMT_TEXTOBJ, &hdr, sizeof(hdr), &ctobj, sizeof(ctobj)); if (FAILED(hr)) goto exit;
exit: return hr; } //---------------------------------------------------------------------------
int CThemeLoader::GetPartOffset(CRenderObj *pRender, int iPartNum) { int iOffset; int iPartCount; MIXEDPTRS u;
//---- see if state table exists for this part ----
u.pb = pRender->_pbSectionData;
if (*u.ps != TMT_PARTJUMPTABLE) { iOffset = -1; goto exit; }
u.pb += ENTRYHDR_SIZE + sizeof(int); // skip over hdr + PackedObjOffset
iPartCount = *u.pb++; if (iPartNum >= iPartCount) // iPartCount is MaxPart+1
{ iOffset = -1; goto exit; }
iOffset = u.pi[iPartNum];
exit: return iOffset; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackDrawObjects(MIXEDPTRS &uOut, CRenderObj *pRender, int iMaxPart, BOOL fGlobals) { HRESULT hr = S_OK; MIXEDPTRS u;
//---- build a draw obj for each part ----
for (int iPart=0; iPart <= iMaxPart; iPart++) { int iPartOff = GetPartOffset(pRender, iPart); if (iPartOff == -1) continue;
u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
if (*u.ps == TMT_STATEJUMPTABLE) { u.pb += ENTRYHDR_SIZE; int iMaxState = (*u.pb++) - 1; int *piStateJumpTable = u.pi;
//---- build a draw obj for each needed state ----
for (int iState=0; iState <= iMaxState; iState++) { int iStateDataOffset = piStateJumpTable[iState]; if (iStateDataOffset == -1) continue;
if ((fGlobals) || (KeyDrawPropertyFound(iStateDataOffset))) { hr = PackDrawObject(uOut, pRender, iPart, iState); if (FAILED(hr)) goto exit;
if (fGlobals) // just needed to force (part=0, state=0)
fGlobals = FALSE; } } } else // no state jump table
{ if ((fGlobals) || (KeyDrawPropertyFound(THEME_OFFSET(u.pb)))) { hr = PackDrawObject(uOut, pRender, iPart, 0); if (FAILED(hr)) goto exit; } } }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::PackTextObjects(MIXEDPTRS &uOut, CRenderObj *pRender, int iMaxPart, BOOL fGlobals) { HRESULT hr = S_OK; MIXEDPTRS u;
//---- build a text obj for each part ----
for (int iPart=0; iPart <= iMaxPart; iPart++) { int iPartOff = GetPartOffset(pRender, iPart); if (iPartOff == -1) continue;
u.pb = _LoadingThemeFile._pbThemeData + iPartOff;
if (*u.ps == TMT_STATEJUMPTABLE) { u.pb += ENTRYHDR_SIZE; int iMaxState = (*u.pb++) - 1; int *piStateJumpTable = u.pi;
//---- build a text obj for each needed state ----
for (int iState=0; iState <= iMaxState; iState++) { int iStateDataOffset = piStateJumpTable[iState]; if (iStateDataOffset == -1) continue;
if ((fGlobals) || (KeyTextPropertyFound(iStateDataOffset))) { hr = PackTextObject(uOut, pRender, iPart, iState); if (FAILED(hr)) goto exit;
if (fGlobals) // just needed to force (part=0, state=0)
fGlobals = FALSE; } } } else // no state jump table
{ if ((fGlobals) || (KeyTextPropertyFound(THEME_OFFSET(u.pb)))) { hr = PackTextObject(uOut, pRender, iPart, 0); if (FAILED(hr)) goto exit; } } }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeLoader::EmitEntryHdr(MIXEDPTRS &u, SHORT propnum, BYTE privnum) { HRESULT hr = S_OK;
if (_iEntryHdrLevel == MAX_ENTRY_NESTING) { Log(LOG_ERROR, L"Maximum entry nesting exceeded"); hr = E_FAIL; goto exit; }
if (_LoadingThemeFile._pbThemeData != NULL) { hr = AllocateThemeFileBytes(u.pb, ENTRYHDR_SIZE); if (FAILED(hr)) goto exit; }
//---- bump up the nesting level of entries ----
_iEntryHdrLevel++;
*u.ps++ = propnum; *u.pb++ = privnum;
_pbEntryHdrs[_iEntryHdrLevel] = u.pb; // used to update next 2 fields in EndEntry()
*u.pb++ = 0; // filler to align end of data to 4/8 bytes
*u.pi++ = 0; // length
exit: return hr; } //---------------------------------------------------------------------------
int CThemeLoader::EndEntry(MIXEDPTRS &u) { MIXEDPTRS uHdr; uHdr.pb = _pbEntryHdrs[_iEntryHdrLevel];
//---- calcuate actual length of date emitted ----
int iActualLen = (int)(u.pb - (uHdr.pb + sizeof(BYTE) + sizeof(int)));
//---- calculate filler to be aligned ----
int iAlignLen = ((iActualLen + ALIGN_FACTOR - 1)/ALIGN_FACTOR) * ALIGN_FACTOR; BYTE bFiller = (BYTE)(iAlignLen - iActualLen);
if (_LoadingThemeFile._pbThemeData != NULL) { HRESULT hr = AllocateThemeFileBytes(u.pb, bFiller); if (FAILED(hr)) return -1; }
//---- emit filler bytes to be correctly aligned ----
for (int i=0; i < bFiller; i++) *u.pb++ = 0 ;
//---- update the entry Hdr ----
*uHdr.pb++ = bFiller; *uHdr.pi++ = iAlignLen;
//---- decrement the nesting level of entries ----
_iEntryHdrLevel--;
return bFiller; } //---------------------------------------------------------------------------
|