1851 lines
55 KiB
C++
1851 lines
55 KiB
C++
//---------------------------------------------------------------------------
|
|
// 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);
|
|
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;
|
|
|
|
memcpy(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;
|
|
|
|
memcpy(u.pb, (BYTE*) pHdr, dwHdrLen);
|
|
u.pb += dwHdrLen;
|
|
memcpy(u.pb, (BYTE*) pObj, dwObjLen);
|
|
u.pb += dwObjLen;
|
|
|
|
EndEntry(u);
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CThemeLoader::EmitString(MIXEDPTRS &u, LPCWSTR pSrc, DWORD dwLen, int *piOffSet)
|
|
{
|
|
HRESULT hr = AllocateThemeFileBytes(u.pb, (dwLen + 1) * sizeof(WCHAR));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
lstrcpy(u.px, pSrc);
|
|
if (piOffSet)
|
|
{
|
|
*piOffSet = THEME_OFFSET(u.pb);
|
|
}
|
|
u.px += dwLen + 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;
|
|
|
|
memcpy(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature);
|
|
|
|
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;
|
|
|
|
#ifdef NEVER
|
|
hdr->dwCheckSum = _LoadingThemeFile.DataCheckSum();
|
|
#else
|
|
hdr->dwCheckSum = 0;
|
|
#endif // NEVER
|
|
|
|
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;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL CThemeLoader::GetThemeName(LPTSTR NameBuff, int BuffSize)
|
|
{
|
|
Log(LOG_TM, L"GetThemeName()");
|
|
|
|
int len = _wsThemeFileName.GetLength();
|
|
if (BuffSize < len)
|
|
return FALSE;
|
|
|
|
lstrcpy(NameBuff, _wsThemeFileName);
|
|
return TRUE;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
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)
|
|
{
|
|
memcpy(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)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
HMODULE hmod;
|
|
|
|
if (!ptm)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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
|
|
#ifdef DEBUG
|
|
BOOL fSuccess =
|
|
#endif
|
|
OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, &hToken);
|
|
#ifdef DEBUG
|
|
if (!fSuccess)
|
|
{
|
|
DWORD dw = GetLastError();
|
|
Log(LOG_TMCHANGE, L"OpenThreadToken failed in SetSystemMetrics, last error=%d", dw);
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
bSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(ptmCopy);
|
|
}
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
FreeLibrary(hmod);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
// failed, fall back to calling synchronously
|
|
SetSystemMetrics_Worker(ptm);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void SetFont(LOGFONT *plf, LPCWSTR lszFontName, int iPointSize)
|
|
{
|
|
memset(plf, 0, sizeof(LOGFONT));
|
|
|
|
plf->lfWeight = FW_NORMAL;
|
|
plf->lfCharSet = DEFAULT_CHARSET;
|
|
plf->lfHeight = iPointSize;
|
|
|
|
lstrcpy(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];
|
|
wsprintf(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;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|