391 lines
10 KiB
C++
391 lines
10 KiB
C++
//---------------------------------------------------------------------------
|
|
// ThemeFile.cpp - manages loaded theme files
|
|
//---------------------------------------------------------------------------
|
|
#include "stdafx.h"
|
|
#include "ThemeFile.h"
|
|
#include "Loader.h"
|
|
#include "Services.h"
|
|
//---------------------------------------------------------------------------
|
|
CUxThemeFile::CUxThemeFile()
|
|
{
|
|
strcpy(_szHead, "thmfile");
|
|
strcpy(_szTail, "end");
|
|
|
|
Reset();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
CUxThemeFile::~CUxThemeFile()
|
|
{
|
|
if (_pbThemeData || _hMemoryMap)
|
|
CloseFile();
|
|
|
|
strcpy(_szHead, "deleted");
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__inline bool CUxThemeFile::IsReady()
|
|
{
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
|
|
if (hdr != NULL && ((hdr->dwFlags & SECTION_READY) != 0))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__inline bool CUxThemeFile::IsGlobal()
|
|
{
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
|
|
if (hdr != NULL && ((hdr->dwFlags & SECTION_GLOBAL) != 0))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__inline bool CUxThemeFile::HasStockObjects()
|
|
{
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
|
|
if (hdr != NULL && ((hdr->dwFlags & SECTION_HASSTOCKOBJECTS) != 0))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CUxThemeFile::CreateFile(int iLength, BOOL fReserve)
|
|
{
|
|
Log(LOG_TM, L"CUxThemeFile::CreateFile");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_pbThemeData)
|
|
CloseFile();
|
|
|
|
//---- we rely on all theme section names containing "ThemeSection" in CHK build so ----
|
|
//---- devs/testers can verify that all handles to old theme sections are released. ----
|
|
//---- For FRE builds, we want a NULL name for security reasons. ----
|
|
WCHAR *pszName = NULL;
|
|
|
|
#ifdef DEBUG
|
|
WCHAR szSectionName[MAX_PATH];
|
|
wsprintf(szSectionName, L"Debug_Create_ThemeSection_%d_%d", GetProcessWindowStation(),
|
|
GetTickCount());
|
|
|
|
pszName = szSectionName;
|
|
#endif
|
|
|
|
_hMemoryMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
|
|
PAGE_READWRITE | (fReserve ? SEC_RESERVE : 0), 0, iLength, pszName);
|
|
if (! _hMemoryMap)
|
|
{
|
|
Log(LOG_ALWAYS, L"CUxThemeFile::CreateFile: could not create shared memory mapping");
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
_pbThemeData = (BYTE *)MapViewOfFile(_hMemoryMap, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (! _pbThemeData)
|
|
{
|
|
Log(LOG_ALWAYS, L"CUxThemeFile::CreateFile: could not create shared memory view");
|
|
CloseHandle(_hMemoryMap);
|
|
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
Log(LOG_TMHANDLE, L"CUxThemeFile::CreateFile FILE CREATED: len=%d, addr=0x%x",
|
|
iLength, _pbThemeData);
|
|
|
|
exit:
|
|
if (FAILED(hr))
|
|
Reset();
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CUxThemeFile::CreateFromSection(HANDLE hSection)
|
|
{
|
|
Log(LOG_TM, L"CUxThemeFile::CreateFromSection");
|
|
|
|
HRESULT hr = S_OK;
|
|
void *pvOld = NULL;
|
|
|
|
//---- ensure we start with all previous handles closed ----
|
|
if (_pbThemeData)
|
|
CloseFile();
|
|
|
|
//---- get access to source section data ----
|
|
pvOld = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
|
|
if (! pvOld)
|
|
{
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
THEMEHDR *pHdr = (THEMEHDR *)pvOld;
|
|
DWORD dwTrueSize = pHdr->dwTotalLength;
|
|
|
|
//---- we rely on all theme section names containing "ThemeSection" in CHK build so ----
|
|
//---- devs/testers can verify that all handles to old theme sections are released. ----
|
|
//---- For FRE builds, we want a NULL name for security reasons. ----
|
|
WCHAR *pszName = NULL;
|
|
|
|
#ifdef DEBUG
|
|
WCHAR szSectionName[MAX_PATH];
|
|
wsprintf(szSectionName, L"Debug_CreateFromSection_ThemeSection_%d_%d", GetProcessWindowStation(),
|
|
GetTickCount());
|
|
|
|
pszName = szSectionName;
|
|
#endif
|
|
|
|
//---- create the new section ----
|
|
_hMemoryMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
|
|
PAGE_READWRITE, 0, dwTrueSize, pszName);
|
|
if (! _hMemoryMap)
|
|
{
|
|
Log(LOG_ALWAYS, L"CUxThemeFile::CreateFromSection: could not create shared memory mapping");
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
//---- get access to new section data ----
|
|
_pbThemeData = (BYTE *)MapViewOfFile(_hMemoryMap, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (! _pbThemeData)
|
|
{
|
|
hr = MakeErrorLast();
|
|
Log(LOG_ALWAYS, L"CThemeFile::CreateFromSection: could not create shared memory view");
|
|
goto exit;
|
|
}
|
|
|
|
//---- copy the data from the old section to the new section ----
|
|
__try
|
|
{
|
|
CopyMemory(_pbThemeData, pvOld, dwTrueSize);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
hr = GetExceptionCode();
|
|
goto exit;
|
|
}
|
|
|
|
//---- ensure version, checksum, etc. is all looking good ----
|
|
hr = ValidateThemeData(TRUE);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
Log(LOG_TMHANDLE, L"CUxThemeFile::CreateFromSection FILE CREATED: addr=0x%x",
|
|
_pbThemeData);
|
|
|
|
exit:
|
|
if (pvOld != NULL)
|
|
UnmapViewOfFile(pvOld);
|
|
|
|
if (FAILED(hr))
|
|
CloseFile();
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// If fCleanupOnFailure is FALSE, we won't close the handle passed, even on failure.
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CUxThemeFile::OpenFromHandle(HANDLE handle, BOOL fCleanupOnFailure)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_pbThemeData)
|
|
CloseFile();
|
|
|
|
_pbThemeData = (BYTE *)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0);
|
|
if (! _pbThemeData)
|
|
{
|
|
hr = MakeErrorLast();
|
|
goto exit;
|
|
}
|
|
|
|
_hMemoryMap = handle;
|
|
|
|
//---- ensure data is valid ----
|
|
hr = ValidateThemeData(FALSE);
|
|
if (FAILED(hr))
|
|
{
|
|
if (!fCleanupOnFailure)
|
|
{
|
|
_hMemoryMap = NULL; // don't give up the refcount on the handle
|
|
CloseFile();
|
|
}
|
|
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
THEMEHDR *ph;
|
|
ph = (THEMEHDR *)_pbThemeData;
|
|
Log(LOG_TMHANDLE, L"CUxThemeFile::OpenFromHandle OPENED: num=%d, addr=0x%x",
|
|
ph->iLoadId, _pbThemeData);
|
|
#endif
|
|
|
|
exit:
|
|
if (FAILED(hr))
|
|
{
|
|
if (!fCleanupOnFailure)
|
|
{
|
|
Reset();
|
|
}
|
|
else
|
|
{
|
|
CloseFile();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT CUxThemeFile::ValidateThemeData(BOOL fFullCheck)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
THEMEHDR *hdr;
|
|
|
|
if (! ValidateObj())
|
|
{
|
|
hr = MakeError32(ERROR_INTERNAL_ERROR);
|
|
goto exit;
|
|
}
|
|
|
|
if (IsBadReadPtr(_pbThemeData, 4)) // sufficient test
|
|
{
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
hdr = (THEMEHDR *)_pbThemeData;
|
|
|
|
if (0 != memcmp(hdr->szSignature, kszBeginCacheFileSignature, kcbBeginSignature)) // bad ptr
|
|
{
|
|
#ifdef DEBUG
|
|
CHAR szSignature[kcbBeginSignature + 1];
|
|
|
|
memcpy(szSignature, hdr->szSignature, kcbBeginSignature);
|
|
szSignature[kcbBeginSignature] = '\0';
|
|
|
|
Log(LOG_ERROR, L"ValidateThemeData(): bad header signature: %S", szSignature);
|
|
#else
|
|
Log(LOG_ERROR, L"ValidateThemeData(): bad header signature");
|
|
#endif
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
if (hdr->dwVersion != THEMEDATA_VERSION)
|
|
{
|
|
Log(LOG_ALWAYS, L"ValidateThemeData(): wrong theme data version: 0x%x", hdr->dwVersion);
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
if (!IsReady()) // data not ready to use
|
|
{
|
|
Log(LOG_ALWAYS, L"ValidateThemeData(): data not READY - hdr->dwFlags=%x", hdr->dwFlags);
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
if (!fFullCheck) // we are done
|
|
goto exit;
|
|
|
|
//---- check that checksum ----
|
|
#ifdef NEVER
|
|
if (hdr->dwCheckSum != DataCheckSum())
|
|
#else // Whistler:190200:Instead of checking the checksum, check the end of file signature, to avoid paging in everything
|
|
if (0 != memcmp(_pbThemeData + hdr->dwTotalLength - kcbEndSignature, kszEndCacheFileSignature, kcbEndSignature))
|
|
{
|
|
Log(LOG_ERROR, L"ValidateThemeData(): bad end of file signature");
|
|
hr = MakeError32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
#endif // NEVER
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
DWORD CUxThemeFile::DataCheckSum()
|
|
{
|
|
DWORD sum = 0;
|
|
|
|
if (ValidateObj())
|
|
{
|
|
THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
|
|
DWORD len = hdr->dwTotalLength - sizeof(THEMEHDR);
|
|
BYTE *pData = _pbThemeData + sizeof(THEMEHDR);
|
|
|
|
while (len--)
|
|
sum += *pData++;
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void CUxThemeFile::CloseFile()
|
|
{
|
|
#ifdef DEBUG
|
|
THEMEHDR *ph = (THEMEHDR *)_pbThemeData;
|
|
if (ph != NULL)
|
|
{
|
|
Log(LOG_TMHANDLE, L"Share CLOSED: num=%d, addr=0x%x",
|
|
ph->iLoadId, _pbThemeData);
|
|
}
|
|
#endif
|
|
|
|
if (_hMemoryMap && HasStockObjects() && !IsGlobal())
|
|
{
|
|
CThemeServices::ClearStockObjects(_hMemoryMap);
|
|
}
|
|
|
|
if (_pbThemeData)
|
|
UnmapViewOfFile(_pbThemeData);
|
|
|
|
if (_hMemoryMap)
|
|
CloseHandle(_hMemoryMap);
|
|
|
|
Reset();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void CUxThemeFile::Reset()
|
|
{
|
|
_pbThemeData = NULL;
|
|
_hMemoryMap = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL CUxThemeFile::ValidateObj()
|
|
{
|
|
BOOL fValid = TRUE;
|
|
|
|
//---- check object quickly ----
|
|
if ( (! this)
|
|
|| (ULONGAT(_szHead) != 'fmht') // "thmf"
|
|
|| (ULONGAT(&_szHead[4]) != 'eli') // "ile"
|
|
|| (ULONGAT(_szTail) != 'dne')) // "end"
|
|
{
|
|
Log(LOG_ERROR, L"*** ERROR: Invalid CUxThemeFile Encountered, addr=0x%08x ****", this);
|
|
fValid = FALSE;
|
|
}
|
|
|
|
return fValid;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
HANDLE CUxThemeFile::Unload()
|
|
{
|
|
HANDLE handle = _hMemoryMap;
|
|
|
|
if (_pbThemeData != NULL)
|
|
{
|
|
UnmapViewOfFile(_pbThemeData);
|
|
}
|
|
Reset(); // don't free handle
|
|
return handle;
|
|
} |