|
|
//-------------------------------------------------------------------------
// TmUtils.cpp - theme manager shared utilities
//-------------------------------------------------------------------------
#include "stdafx.h"
#include "TmUtils.h"
#include "ThemeFile.h"
#include "loader.h"
//-------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CMemoryDC::CMemoryDC() { _hBitmap = NULL; _hdc = NULL; _hOldBitmap = NULL; } //-------------------------------------------------------------------------
CMemoryDC::~CMemoryDC() { CloseDC(); } //-------------------------------------------------------------------------
HRESULT CMemoryDC::OpenDC(HDC hdcSource, int iWidth, int iHeight) { HRESULT hr; BOOL fDeskDC = FALSE;
if (! hdcSource) { hdcSource = GetWindowDC(NULL); if (! hdcSource) { hr = MakeErrorLast(); goto exit; } fDeskDC = TRUE; }
_hBitmap = CreateCompatibleBitmap(hdcSource, iWidth, iHeight); if (! _hBitmap) { hr = MakeErrorLast(); goto exit; }
_hdc = CreateCompatibleDC(hdcSource); if (! _hdc) { hr = MakeErrorLast(); goto exit; }
_hOldBitmap = (HBITMAP) SelectObject(_hdc, _hBitmap); if (! _hOldBitmap) { hr = MakeErrorLast(); goto exit; }
hr = S_OK;
exit: if (fDeskDC) ReleaseDC(NULL, hdcSource);
if (FAILED(hr)) CloseDC();
return hr; } //-------------------------------------------------------------------------
void CMemoryDC::CloseDC() { if (_hOldBitmap) { SelectObject(_hdc, _hOldBitmap); _hOldBitmap = NULL; }
if (_hdc) { DeleteDC(_hdc); _hdc = NULL; }
if (_hBitmap) { DeleteObject(_hBitmap); _hBitmap = NULL; } } //-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
CBitmapPixels::CBitmapPixels() { _hdrBitmap = NULL; _buffer = NULL; _iWidth = 0; _iHeight = 0; } //-------------------------------------------------------------------------
CBitmapPixels::~CBitmapPixels() { if (_buffer) delete [] (BYTE *)_buffer; } //-------------------------------------------------------------------------
BYTE* CBitmapPixels::Buffer() { return _buffer; } //-------------------------------------------------------------------------
HRESULT CBitmapPixels::OpenBitmap(HDC hdc, HBITMAP bitmap, BOOL fForceRGB32, DWORD OUT **pPixels, OPTIONAL OUT int *piWidth, OPTIONAL OUT int *piHeight, OPTIONAL OUT int *piBytesPerPixel, OPTIONAL OUT int *piBytesPerRow, OPTIONAL OUT int *piPreviousBytesPerPixel, OPTIONAL UINT cbBytesBefore) { if (! pPixels) return MakeError32(E_INVALIDARG);
bool fNeedRelease = false;
if (! hdc) { hdc = GetWindowDC(NULL); if (! hdc) { return MakeErrorLast(); }
fNeedRelease = true; }
BITMAP bminfo; GetObject(bitmap, sizeof(bminfo), &bminfo); _iWidth = bminfo.bmWidth; _iHeight = bminfo.bmHeight;
int iBytesPerPixel;
if (piPreviousBytesPerPixel != NULL) { *piPreviousBytesPerPixel = bminfo.bmBitsPixel / 8; }
if ((fForceRGB32) || (bminfo.bmBitsPixel == 32)) iBytesPerPixel = 4; else iBytesPerPixel = 3; int iRawBytes = _iWidth * iBytesPerPixel; int iBytesPerRow = 4*((iRawBytes+3)/4);
int size = sizeof(BITMAPINFOHEADER) + _iHeight*iBytesPerRow; _buffer = new BYTE[size + cbBytesBefore + 100]; // avoid random GetDIBits() failures with 100 bytes padding (?)
if (! _buffer) return MakeError32(E_OUTOFMEMORY);
_hdrBitmap = (BITMAPINFOHEADER *)(_buffer + cbBytesBefore); memset(_hdrBitmap, 0, sizeof(BITMAPINFOHEADER));
_hdrBitmap->biSize = sizeof(BITMAPINFOHEADER); _hdrBitmap->biWidth = _iWidth; _hdrBitmap->biHeight = _iHeight; _hdrBitmap->biPlanes = 1; _hdrBitmap->biBitCount = static_cast<WORD>(8*iBytesPerPixel); _hdrBitmap->biCompression = BI_RGB; #ifdef DEBUG
int linecnt = #endif
GetDIBits(hdc, bitmap, 0, _iHeight, DIBDATA(_hdrBitmap), (BITMAPINFO *)_hdrBitmap, DIB_RGB_COLORS); ATLASSERT(linecnt == _iHeight);
if (fNeedRelease) ReleaseDC(NULL, hdc);
*pPixels = (DWORD *)DIBDATA(_hdrBitmap);
if (piWidth) *piWidth = _iWidth; if (piHeight) *piHeight = _iHeight;
if (piBytesPerPixel) *piBytesPerPixel = iBytesPerPixel; if (piBytesPerRow) *piBytesPerRow = iBytesPerRow;
return S_OK; } //-------------------------------------------------------------------------
void CBitmapPixels::CloseBitmap(HDC hdc, HBITMAP hBitmap) { if (_hdrBitmap && _buffer) { if (hBitmap) // rewrite bitmap
{ bool fNeedRelease = false;
if (! hdc) { hdc = GetWindowDC(NULL); fNeedRelease = true; }
SetDIBits(hdc, hBitmap, 0, _iHeight, DIBDATA(_hdrBitmap), (BITMAPINFO *)_hdrBitmap, DIB_RGB_COLORS); if ((fNeedRelease) && (hdc)) ReleaseDC(NULL, hdc); }
delete [] (BYTE *)_buffer; _hdrBitmap = NULL; _buffer = NULL; } } //-------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
HRESULT LoadThemeLibrary(LPCWSTR pszThemeName, HINSTANCE *phInst) { HRESULT hr = S_OK; HINSTANCE hInst = NULL;
hInst = LoadLibraryEx(pszThemeName, NULL, LOAD_LIBRARY_AS_DATAFILE); if (! hInst) { hr = MakeErrorLast(); goto exit; }
//---- is this version supported? ----
void *pvVersion; DWORD dwVersionLength; hr = GetPtrToResource(hInst, L"PACKTHEM_VERSION", MAKEINTRESOURCE(1), &pvVersion, &dwVersionLength); if (SUCCEEDED(hr)) { if (dwVersionLength != sizeof(SHORT)) hr = E_FAIL; else { SHORT sVersionNum = *(SHORT *)pvVersion; if (sVersionNum != PACKTHEM_VERSION) hr = E_FAIL; } }
if (FAILED(hr)) { hr = MakeError32(ERROR_BAD_FORMAT); goto exit; }
*phInst = hInst;
exit: if (FAILED(hr)) { if (hInst) FreeLibrary(hInst); }
return hr; } //---------------------------------------------------------------------------
LPCWSTR ThemeString(CUxThemeFile *pThemeFile, int iOffset) { LPCWSTR p = L"";
if ((pThemeFile) && (pThemeFile->_pbThemeData) && (iOffset > 0)) { p = (LPCWSTR) (pThemeFile->_pbThemeData + iOffset); }
return p; } //---------------------------------------------------------------------------
int GetLoadIdFromTheme(CUxThemeFile *pThemeFile) { int iLoadId = 0;
if (pThemeFile) { THEMEHDR *hdr = (THEMEHDR *)pThemeFile->_pbThemeData; iLoadId = hdr->iLoadId; }
return iLoadId; } //---------------------------------------------------------------------------
HRESULT GetThemeNameId(CUxThemeFile *pThemeFile, LPWSTR pszFileNameBuff, UINT cchFileNameBuff, LPWSTR pszColorParam, UINT cchColorParam, LPWSTR pszSizeParam, UINT cchSizeParam, int *piSysMetricsOffset, LANGID *pwLangID) { HRESULT hr = S_OK; THEMEHDR *hdr = (THEMEHDR *)pThemeFile->_pbThemeData;
if (piSysMetricsOffset) *piSysMetricsOffset = hdr->iSysMetricsOffset;
if (pszFileNameBuff) { hr = SafeStringCchCopyW(pszFileNameBuff, cchFileNameBuff, ThemeString(pThemeFile, hdr->iDllNameOffset)); }
if (SUCCEEDED(hr) && pszColorParam) { hr = SafeStringCchCopyW(pszColorParam, cchColorParam, ThemeString(pThemeFile, hdr->iColorParamOffset)); }
if (SUCCEEDED(hr) && pszSizeParam) { hr = SafeStringCchCopyW(pszSizeParam, cchSizeParam, ThemeString(pThemeFile, hdr->iSizeParamOffset) ); }
if (SUCCEEDED(hr) && pwLangID) *pwLangID = (LANGID) hdr->dwLangID;
return hr; } //---------------------------------------------------------------------------
BOOL ThemeMatch (CUxThemeFile *pThemeFile, LPCWSTR pszThemeName, LPCWSTR pszColorName, LPCWSTR pszSizeName, LANGID wLangID) { WCHAR szThemeFileName[MAX_PATH]; WCHAR szColorParam[MAX_PATH]; WCHAR szSizeParam[MAX_PATH]; LANGID wThemeLangID = 0; bool bLangMatch = true;
HRESULT hr = GetThemeNameId(pThemeFile, szThemeFileName, ARRAYSIZE(szThemeFileName), szColorParam, ARRAYSIZE(szColorParam), szSizeParam, ARRAYSIZE(szSizeParam), NULL, &wThemeLangID);
if (wLangID != 0 && ((wThemeLangID != wLangID) || (wLangID != GetUserDefaultUILanguage()))) { Log(LOG_TMLOAD, L"UxTheme: Reloading theme because of language change."); Log(LOG_TMLOAD, L"UxTheme: User LangID=0x%x, current theme=0x%x, LastUserLangID=0x%x", GetUserDefaultUILanguage(), wThemeLangID, wLangID); bLangMatch = false; }
if( bLangMatch ) { if( SUCCEEDED(hr) ) { int iCmpTheme, iCmpColor, iCmpSize;
if( SUCCEEDED(SafeStringCmpIW( pszThemeName, szThemeFileName, ARRAYSIZE(szThemeFileName), &iCmpTheme )) && SUCCEEDED(SafeStringCmpIW( pszColorName, szColorParam, ARRAYSIZE(szColorParam), &iCmpColor )) && SUCCEEDED(SafeStringCmpIW( pszSizeName, szSizeParam, ARRAYSIZE(szSizeParam), &iCmpSize )) ) { return 0 == iCmpTheme && 0 == iCmpColor && 0 == iCmpSize; } } }
return FALSE; } //---------------------------------------------------------------------------
HRESULT GetColorSchemeIndex(HINSTANCE hInst, LPCWSTR pszColor, int *piIndex) { HRESULT hr; WCHAR szColor[_MAX_PATH+1];
for (int i=0; i < 1000; i++) { hr = GetResString(hInst, L"COLORNAMES", i, szColor, ARRAYSIZE(szColor)); if (FAILED(hr)) break; int iCmpColor; if( SUCCEEDED(SafeStringCmpIW( pszColor, szColor, ARRAYSIZE(szColor), &iCmpColor)) && 0 == iCmpColor ) { *piIndex = i; return S_OK; } }
return MakeError32(ERROR_NOT_FOUND); // not found
} //---------------------------------------------------------------------------
HRESULT GetSizeIndex(HINSTANCE hInst, LPCWSTR pszSize, int *piIndex) { HRESULT hr; WCHAR szSize[_MAX_PATH+1];
for (int i=0; i < 1000; i++) { hr = GetResString(hInst, L"SIZENAMES", i, szSize, ARRAYSIZE(szSize)); if (FAILED(hr)) break;
int iCmpSize; if( SUCCEEDED(SafeStringCmpIW( pszSize, szSize, ARRAYSIZE(szSize), &iCmpSize)) && 0 == iCmpSize ) { *piIndex = i; return S_OK; } }
return MakeError32(ERROR_NOT_FOUND); // not found
} //---------------------------------------------------------------------------
HRESULT FindComboData(HINSTANCE hDll, COLORSIZECOMBOS **ppCombos) { HRSRC hRsc = FindResource(hDll, L"COMBO", L"COMBODATA"); if (! hRsc) return MakeErrorLast();
HGLOBAL hGlobal = LoadResource(hDll, hRsc); if (! hGlobal) return MakeErrorLast();
*ppCombos = (COLORSIZECOMBOS *)LockResource(hGlobal); if (! *ppCombos) return MakeErrorLast();
return S_OK; } //---------------------------------------------------------------------------
BOOL FormatLocalMsg(HINSTANCE hInst, int iStringNum, LPWSTR pszMessageBuff, DWORD cchMessageBuff, DWORD *pdwParams, TMERRINFO *pErrInfo) { BOOL fGotMsg = FALSE; WCHAR szBuff[_MAX_PATH+1]; WCHAR *p;
//----- get string from string table ----
if (LoadString(hInst, iStringNum, szBuff, ARRAYSIZE(szBuff))) { //---- repl %1 or %2 with %s ----
p = szBuff; while (*p) { if (*p == '%') { p++; if ((*p == '1') || (*p == '2')) *p = 's'; p++; } else p++; }
int len = lstrlen(szBuff); if (len) { StringCchPrintfW(pszMessageBuff, cchMessageBuff, szBuff, pErrInfo->szMsgParam1, pErrInfo->szMsgParam2); fGotMsg = TRUE; } }
return fGotMsg; } //---------------------------------------------------------------------------
HRESULT _FormatParseMessage(TMERRINFO *pErrInfo, OUT LPWSTR pszMessageBuff, DWORD cchMessageBuff) { LogEntry(L"_FormatParseMessage");
HRESULT hr = S_OK;
DWORD dwParams[] = {PtrToInt(pErrInfo->szMsgParam1), PtrToInt(pErrInfo->szMsgParam2)}; DWORD dwCode = pErrInfo->dwParseErrCode; BOOL fGotMsg = FALSE;
int iStringNum = SCODE_CODE(dwCode);
//---- get process name (see if we are "packthem.exe" ----
WCHAR szPath[MAX_PATH]; if (! GetModuleFileNameW( NULL, szPath, ARRAYSIZE(szPath) )) goto exit;
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBase[_MAX_FNAME], szExt[_MAX_EXT]; _wsplitpath(szPath, szDrive, szDir, szBase, szExt);
if (lstrcmpi(szBase, L"packthem")==0) // give packthem priority
{ fGotMsg = FormatLocalMsg(GetModuleHandle(NULL), iStringNum, pszMessageBuff, cchMessageBuff, dwParams, pErrInfo); }
if (! fGotMsg) // try normal route: uxtheme.dll
{ HINSTANCE hInst = LoadLibrary(L"uxtheme.dll"); if (! hInst) { Log(LOG_ALWAYS, L"_FormatParseMessage: Could not load uxtheme.dll"); hr = E_FAIL; goto exit; }
fGotMsg = FormatLocalMsg(hInst, iStringNum, pszMessageBuff, cchMessageBuff, dwParams, pErrInfo); FreeLibrary(hInst); }
if (! fGotMsg) hr = MakeErrorLast();
exit: LogExit(L"_FormatParseMessage"); return hr; } //---------------------------------------------------------------------------
HRESULT _GetThemeParseErrorInfo(OUT PARSE_ERROR_INFO *pInfo) { LogEntry(L"_GetThemeParseErrorInfo");
HRESULT hr = S_OK;
if (pInfo->dwSize != sizeof(PARSE_ERROR_INFO)) // unsupported size
{ hr = MakeError32(E_INVALIDARG); goto exit; }
TMERRINFO *pErrInfo = GetParseErrorInfo(TRUE); if (! pErrInfo) { hr = MakeError32(E_OUTOFMEMORY); goto exit; }
//---- convert code into msg using param strings ----
hr = _FormatParseMessage(pErrInfo, pInfo->szMsg, ARRAYSIZE(pInfo->szMsg)); if (FAILED(hr)) goto exit;
//---- transfer the other info ----
pInfo->dwParseErrCode = pErrInfo->dwParseErrCode; pInfo->iLineNum = pErrInfo->iLineNum;
StringCchCopyW(pInfo->szFileName, ARRAYSIZE(pInfo->szFileName), pErrInfo->szFileName); StringCchCopyW(pInfo->szSourceLine, ARRAYSIZE(pInfo->szSourceLine), pErrInfo->szSourceLine);
exit: LogExit(L"_GetThemeParseErrorInfo"); return hr; } //---------------------------------------------------------------------------
HRESULT _ParseThemeIniFile(LPCWSTR pszFileName, DWORD dwParseFlags, OPTIONAL THEMEENUMPROC pfnCallBack, OPTIONAL LPARAM lparam) { LogEntry(L"ParseThemeIniFile"); HRESULT hr;
CThemeParser *pParser = new CThemeParser; if (! pParser) { hr = MakeError32(E_OUTOFMEMORY); goto exit; }
hr = pParser->ParseThemeFile(pszFileName, NULL, NULL, pfnCallBack, lparam, dwParseFlags);
delete pParser;
exit: LogExit(L"ParseThemeIniFile"); return hr; } //---------------------------------------------------------------------------
BOOL ThemeLibStartUp(BOOL fThreadAttach) { BOOL fInit = FALSE;
if (fThreadAttach) { //---- nothing to do here ----
} else // process
{ _tls_ErrorInfoIndex = TlsAlloc(); if (_tls_ErrorInfoIndex == (DWORD)-1) goto exit;
if (! LogStartUp()) goto exit; if (! UtilsStartUp()) goto exit; } fInit = TRUE;
exit: return fInit; } //---------------------------------------------------------------------------
BOOL ThemeLibShutDown(BOOL fThreadDetach) { if (fThreadDetach) { //---- destroy the thread-local Error Info ----
TMERRINFO * ei = GetParseErrorInfo(FALSE); if (ei) { TlsSetValue(_tls_ErrorInfoIndex, NULL); delete ei; } } else // process
{ UtilsShutDown(); LogShutDown();
if (_tls_ErrorInfoIndex != (DWORD)-1) { TlsFree(_tls_ErrorInfoIndex); _tls_ErrorInfoIndex = (DWORD)-1; } }
return TRUE; } //---------------------------------------------------------------------------
HRESULT GetThemeSizeId(int iSysSizeId, int *piThemeSizeId) { HRESULT hr = S_OK; *piThemeSizeId = 0;
switch (iSysSizeId) { case SM_CXSIZEFRAME: *piThemeSizeId = TMT_SIZINGBORDERWIDTH; break;
case SM_CYSIZEFRAME: *piThemeSizeId = TMT_SIZINGBORDERWIDTH; break;
case SM_CXVSCROLL: *piThemeSizeId = TMT_SCROLLBARWIDTH; break;
case SM_CYHSCROLL: *piThemeSizeId = TMT_SCROLLBARHEIGHT; break;
case SM_CXSIZE: *piThemeSizeId = TMT_CAPTIONBARWIDTH; break;
case SM_CYSIZE: *piThemeSizeId = TMT_CAPTIONBARHEIGHT; break;
case SM_CXSMSIZE: *piThemeSizeId = TMT_SMCAPTIONBARWIDTH; break;
case SM_CYSMSIZE: *piThemeSizeId = TMT_SMCAPTIONBARHEIGHT; break;
case SM_CXMENUSIZE: *piThemeSizeId = TMT_MENUBARWIDTH; break;
case SM_CYMENUSIZE: *piThemeSizeId = TMT_MENUBARHEIGHT; break;
default: hr = MakeError32(E_INVALIDARG); break; }
return hr; } //---------------------------------------------------------------------------
HRESULT _EnumThemeSizes(HINSTANCE hInst, LPCWSTR pszThemeName, OPTIONAL LPCWSTR pszColorScheme, DWORD dwSizeIndex, OUT THEMENAMEINFO *ptn, BOOL fCheckColorDepth) { HRESULT hr;
COLORSIZECOMBOS *combos; hr = FindComboData(hInst, &combos); if (FAILED(hr)) goto exit;
int iMinColor, iMaxColor; iMinColor = 0; iMaxColor = combos->cColorSchemes-1;
if (pszColorScheme) // translate "pszColorScheme" into a color number
{ int index;
hr = GetColorSchemeIndex(hInst, pszColorScheme, &index); if (FAILED(hr)) goto exit; //---- restrict our search to just this color ----
iMinColor = index; iMaxColor = index; }
int s, c; DWORD dwSizeNum; dwSizeNum = 0; BOOL gotall; gotall = FALSE;
DWORD dwCurMinDepth = 0; if (fCheckColorDepth) { dwCurMinDepth = MinimumDisplayColorDepth(); }
for (s=0; s < combos->cSizes; s++) { BOOL fFoundOne = FALSE;
for (c=iMinColor; c <= iMaxColor; c++) { if (COMBOENTRY(combos, c, s) != -1) { fFoundOne = TRUE; break; } }
if (fFoundOne && (!fCheckColorDepth || CheckMinColorDepth(hInst, dwCurMinDepth, COMBOENTRY(combos, c, s)))) { if (dwSizeNum++ == dwSizeIndex) { hr = GetResString(hInst, L"SIZENAMES", s, ptn->szName, ARRAYSIZE(ptn->szName)); if (FAILED(hr)) *ptn->szName = 0; if (! LoadString(hInst, s+RES_BASENUM_SIZEDISPLAYS, ptn->szDisplayName, ARRAYSIZE(ptn->szDisplayName))) *ptn->szDisplayName = 0;
if (! LoadString(hInst, s+RES_BASENUM_SIZETOOLTIPS, ptn->szToolTip, ARRAYSIZE(ptn->szToolTip))) *ptn->szToolTip = 0; gotall = TRUE; break; } } }
if ((SUCCEEDED(hr)) && (! gotall)) hr = MakeError32(ERROR_NOT_FOUND);
exit: return hr; } //---------------------------------------------------------------------------
HRESULT _EnumThemeColors(HINSTANCE hInst, LPCWSTR pszThemeName, OPTIONAL LPCWSTR pszSizeName, DWORD dwColorIndex, OUT THEMENAMEINFO *ptn, BOOL fCheckColorDepth) { HRESULT hr;
COLORSIZECOMBOS *combos; hr = FindComboData(hInst, &combos); if (FAILED(hr)) goto exit;
int iMinSize, iMaxSize; iMinSize = 0; iMaxSize = combos->cSizes-1;
if (pszSizeName) // translate "pszSizeName" into a size number
{ int index;
hr = GetSizeIndex(hInst, pszSizeName, &index); if (FAILED(hr)) goto exit;
//---- restrict our search to just this size ----
iMinSize = index; iMaxSize = index; }
int s, c; DWORD dwColorNum; dwColorNum = 0;
BOOL gotall; gotall = FALSE;
DWORD dwCurMinDepth = 0; if (fCheckColorDepth) { dwCurMinDepth = MinimumDisplayColorDepth(); }
for (c=0; c < combos->cColorSchemes; c++) { BOOL fFoundOne = FALSE;
for (s=iMinSize; s <= iMaxSize; s++) { if (COMBOENTRY(combos, c, s) != -1) { fFoundOne = TRUE; break; } }
if (fFoundOne && (!fCheckColorDepth || CheckMinColorDepth(hInst, dwCurMinDepth, COMBOENTRY(combos, c, s)))) { if (dwColorNum++ == dwColorIndex) { hr = GetResString(hInst, L"COLORNAMES", c, ptn->szName, ARRAYSIZE(ptn->szName)); if (FAILED(hr)) *ptn->szName = 0;
if (! LoadString(hInst, c+RES_BASENUM_COLORDISPLAYS, ptn->szDisplayName, ARRAYSIZE(ptn->szDisplayName))) *ptn->szDisplayName = 0;
if (! LoadString(hInst, c+RES_BASENUM_COLORTOOLTIPS, ptn->szToolTip, ARRAYSIZE(ptn->szToolTip))) *ptn->szToolTip = 0;
gotall = true; break; } } }
if ((SUCCEEDED(hr)) && (! gotall)) hr = MakeError32(ERROR_NOT_FOUND);
exit: return hr; }
|