You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2043 lines
62 KiB
2043 lines
62 KiB
//---------------------------------------------------------------------------
|
|
// PackThem.cpp - packs up theme files into a theme DLL
|
|
//---------------------------------------------------------------------------
|
|
#include "stdafx.h"
|
|
#include <uxthemep.h>
|
|
#include <utils.h>
|
|
#include "SimpStr.h"
|
|
#include "Scanner.h"
|
|
#include "shlwapip.h"
|
|
#include "parser.h"
|
|
#include "TmSchema.h"
|
|
#include "signing.h"
|
|
#include "localsign.h"
|
|
#include "ThemeLdr.h"
|
|
#include "TmUtils.h"
|
|
#include "StringTable.h"
|
|
|
|
HRESULT ParseTheme(LPCWSTR pszThemeName);
|
|
|
|
//---------------------------------------------------------------------------
|
|
struct FILEINFO
|
|
{
|
|
CWideString wsName;
|
|
BOOL fIniFile;
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
#define MAX_COLORS 50
|
|
#define MAX_SIZES 20
|
|
#define TEMP_FILENAME_BASE L"$temp$"
|
|
#define kRESFILECHAR L'$'
|
|
//---------------------------------------------------------------------------
|
|
enum PACKFILETYPE
|
|
{
|
|
PACK_INIFILE,
|
|
PACK_IMAGEFILE,
|
|
PACK_NTLFILE,
|
|
PACK_OTHER
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
CSimpleArray<FILEINFO> FileInfo;
|
|
|
|
CSimpleArray<CWideString> ColorSchemes;
|
|
CSimpleArray<CWideString> ColorDisplays;
|
|
CSimpleArray<CWideString> ColorToolTips;
|
|
|
|
CSimpleArray<int> MinDepths;
|
|
|
|
CSimpleArray<CWideString> SizeNames;
|
|
CSimpleArray<CWideString> SizeDisplays;
|
|
CSimpleArray<CWideString> SizeToolTips;
|
|
|
|
typedef struct
|
|
{
|
|
CWideString sName;
|
|
int iFirstIndex;
|
|
UINT cItems;
|
|
} sSubstTable;
|
|
CSimpleArray<sSubstTable> SubstNames;
|
|
CSimpleArray<CWideString> SubstIds;
|
|
CSimpleArray<CWideString> SubstValues;
|
|
|
|
CSimpleArray<CWideString> BaseResFileNames;
|
|
CSimpleArray<CWideString> ResFileNames;
|
|
CSimpleArray<CWideString> OrigFileNames;
|
|
|
|
CSimpleArray<CWideString> PropValuePairs;
|
|
//---------------------------------------------------------------------------
|
|
SHORT Combos[MAX_SIZES][MAX_COLORS];
|
|
|
|
int g_iMaxColor;
|
|
int g_iMaxSize;
|
|
int g_LineCount = 0;
|
|
int iTempBitmapNum = 1;
|
|
|
|
BOOL g_fQuietRun = FALSE; // don't show needless output
|
|
BOOL g_fKeepTempFiles = FALSE;
|
|
FILE *ConsoleFile = NULL;
|
|
|
|
WCHAR g_szInputDir[_MAX_PATH+1];
|
|
WCHAR g_szTempPath[_MAX_PATH+1];
|
|
WCHAR g_szBaseIniName[_MAX_PATH+1];
|
|
WCHAR g_szCurrentClass[_MAX_PATH+1];
|
|
|
|
//---------------------------------------------------------------------------
|
|
#define DOCPROPCNT (1+TMT_LAST_RCSTRING_NAME - TMT_FIRST_RCSTRING_NAME)
|
|
|
|
CWideString DocProperties[DOCPROPCNT];
|
|
//---------------------------------------------------------------------------
|
|
HRESULT ReportError(HRESULT hr, LPWSTR pszDefaultMsg)
|
|
{
|
|
WCHAR szErrorMsg[2*_MAX_PATH+1];
|
|
PARSE_ERROR_INFO Info = {sizeof(Info)};
|
|
|
|
BOOL fGotMsg = FALSE;
|
|
|
|
if (THEME_PARSING_ERROR(hr))
|
|
{
|
|
if (SUCCEEDED(_GetThemeParseErrorInfo(&Info)))
|
|
{
|
|
StringCchCopyW(szErrorMsg, ARRAYSIZE(szErrorMsg), Info.szMsg);
|
|
fGotMsg = TRUE;
|
|
}
|
|
}
|
|
|
|
if (! fGotMsg)
|
|
{
|
|
StringCchCopyW(szErrorMsg, ARRAYSIZE(szErrorMsg), pszDefaultMsg);
|
|
}
|
|
|
|
if (*Info.szFileName) // input file error
|
|
{
|
|
fwprintf(ConsoleFile, L"%s(%d): error - %s\n",
|
|
Info.szFileName, Info.iLineNum, szErrorMsg);
|
|
fwprintf(ConsoleFile, L"%s\n", Info.szSourceLine);
|
|
}
|
|
else // general error
|
|
{
|
|
fwprintf(ConsoleFile, L"%s(): error - %s\n",
|
|
g_szInputDir, szErrorMsg);
|
|
}
|
|
|
|
SET_LAST_ERROR(hr);
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void MakeResName(LPCWSTR pszName, LPWSTR pszResName, ULONG cchResName, bool bUseClassName = false)
|
|
{
|
|
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
|
|
LPWSTR pszBaseName = szBaseName;
|
|
|
|
*szDrive = *szDir = *pszBaseName = *szExt = 0;
|
|
|
|
//---- isolate base name (no path) ----
|
|
_wsplitpath(pszName, szDrive, szDir, szBaseName, szExt);
|
|
|
|
if (*pszBaseName == kRESFILECHAR) // Don't put $ in resource names
|
|
{
|
|
pszBaseName++;
|
|
}
|
|
|
|
//---- replace the "." with a '_' ----
|
|
//---- if a file section name without .ini, append _INI so that the extracted files has .ini extension
|
|
if (*szExt)
|
|
{
|
|
StringCchPrintfW(pszResName, cchResName, L"%s%s_%s", bUseClassName ? g_szCurrentClass : L"", pszBaseName, szExt+1);
|
|
} else
|
|
{
|
|
StringCchPrintfW(pszResName, cchResName, L"%s%s_INI", bUseClassName ? g_szCurrentClass : L"", pszBaseName);
|
|
}
|
|
|
|
//---- all uppercase ----
|
|
CharUpperBuff(pszResName, lstrlen(pszResName));
|
|
|
|
//---- replace any spaces with underscores ----
|
|
WCHAR *q = pszResName;
|
|
while (*q)
|
|
{
|
|
if (*q == ' ')
|
|
*q = '_';
|
|
q++;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT BuildThemeDll(LPCWSTR pszRcName, LPCWSTR pszResName, LPCWSTR pszDllName)
|
|
{
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"compiling resources\n");
|
|
|
|
HRESULT hr = SyncCmdLineRun(L"rc.exe", pszRcName);
|
|
if (FAILED(hr))
|
|
return ReportError(hr, L"Error during resource compiliation");
|
|
|
|
//---- run LINK to create the DLL ----
|
|
WCHAR szParams[2*_MAX_PATH+1];
|
|
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"linking theme dll\n");
|
|
|
|
StringCchPrintfW(szParams, ARRAYSIZE(szParams), L"/out:%s /machine:ix86 /dll /noentry %s", pszDllName, pszResName);
|
|
hr = SyncCmdLineRun(L"link.exe", szParams);
|
|
if (FAILED(hr))
|
|
return ReportError(hr, L"Error during DLL linking");
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void OutputDashLine(FILE *outfile)
|
|
{
|
|
fwprintf(outfile, L"//----------------------------------------------------------------------\n");
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
inline void ValueLine(FILE *outfile, LPCWSTR pszName, LPCWSTR pszValue)
|
|
{
|
|
fwprintf(outfile, L" VALUE \"%s\", \"%s\\0\"\n", pszName, pszValue);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OutputVersionInfo(FILE *outfile, LPCWSTR pszFileName, LPCWSTR pszBaseName)
|
|
{
|
|
fwprintf(outfile, L"1 PACKTHEM_VERSION\n");
|
|
fwprintf(outfile, L"BEGIN\n");
|
|
fwprintf(outfile, L" %d\n", PACKTHEM_VERSION);
|
|
fwprintf(outfile, L"END\n");
|
|
OutputDashLine(outfile);
|
|
|
|
WCHAR *Company = L"Microsoft";
|
|
WCHAR *Copyright = L"Copyright © 2000";
|
|
WCHAR szDescription[2*_MAX_PATH+1];
|
|
|
|
StringCchPrintfW(szDescription, ARRAYSIZE(szDescription), L"%s Theme for Windows", pszBaseName);
|
|
|
|
fwprintf(outfile, L"1 VERSIONINFO\n");
|
|
fwprintf(outfile, L" FILEVERSION 1,0,0,1\n");
|
|
fwprintf(outfile, L" PRODUCTVERSION 1,0,0,1\n");
|
|
fwprintf(outfile, L" FILEFLAGSMASK 0x3fL\n");
|
|
fwprintf(outfile, L" FILEFLAGS 0x0L\n");
|
|
fwprintf(outfile, L" FILEOS 0x40004L\n");
|
|
fwprintf(outfile, L" FILETYPE 0x1L\n");
|
|
fwprintf(outfile, L" FILESUBTYPE 0x0L\n");
|
|
|
|
fwprintf(outfile, L"BEGIN\n");
|
|
fwprintf(outfile, L" BLOCK \"StringFileInfo\"\n");
|
|
fwprintf(outfile, L" BEGIN\n");
|
|
fwprintf(outfile, L" BLOCK \"040904b0\"\n");
|
|
|
|
fwprintf(outfile, L" BEGIN\n");
|
|
|
|
ValueLine(outfile, L"Comments", L"");
|
|
ValueLine(outfile, L"CompanyName", Company);
|
|
ValueLine(outfile, L"FileDescription", szDescription);
|
|
ValueLine(outfile, L"FileVersion", L"1, 0, 0, 1");
|
|
ValueLine(outfile, L"InternalName", pszFileName);
|
|
ValueLine(outfile, L"LegalCopyright", Copyright);
|
|
ValueLine(outfile, L"LegalTrademarks", L"");
|
|
ValueLine(outfile, L"OriginalFilename", pszFileName);
|
|
ValueLine(outfile, L"PrivateBuild", L"");
|
|
ValueLine(outfile, L"ProductName", szDescription);
|
|
ValueLine(outfile, L"ProductVersion", L"1, 0, 0, 1");
|
|
ValueLine(outfile, L"SpecialBuild", L"");
|
|
|
|
fwprintf(outfile, L" END\n");
|
|
fwprintf(outfile, L" END\n");
|
|
fwprintf(outfile, L" BLOCK \"VarFileInfo\"\n");
|
|
fwprintf(outfile, L" BEGIN\n");
|
|
fwprintf(outfile, L" VALUE \"Translation\", 0x409, 1200\n");
|
|
fwprintf(outfile, L" END\n");
|
|
fwprintf(outfile, L"END\n");
|
|
|
|
OutputDashLine(outfile);
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT RemoveTempFiles(LPCWSTR szRcName, LPCWSTR szResName)
|
|
{
|
|
DeleteFile(szRcName);
|
|
DeleteFile(szResName);
|
|
|
|
//---- find & delete all temp files in temp directory ----
|
|
HANDLE hFile = NULL;
|
|
BOOL bFile = TRUE;
|
|
WIN32_FIND_DATA wfd;
|
|
WCHAR szPattern[_MAX_PATH+1];
|
|
WCHAR szTempName[_MAX_PATH+1];
|
|
|
|
StringCchPrintfW(szPattern, ARRAYSIZE(szPattern), L"%s\\%s*.*", g_szTempPath, TEMP_FILENAME_BASE);
|
|
|
|
for( hFile = FindFirstFile( szPattern, &wfd ); hFile != INVALID_HANDLE_VALUE && bFile;
|
|
bFile = FindNextFile( hFile, &wfd ) )
|
|
{
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s\\%s", g_szTempPath, wfd.cFileName);
|
|
|
|
DeleteFile(szTempName);
|
|
}
|
|
|
|
if (hFile)
|
|
{
|
|
FindClose( hFile );
|
|
}
|
|
|
|
// Remove files generated by the substitution tables
|
|
for (int i = 0; i < SubstNames.GetSize(); i++)
|
|
{
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s\\$%s.ini", g_szTempPath, SubstNames[i].sName);
|
|
DeleteFile(szTempName);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
int GetSubstTableIndex(LPCWSTR pszTableName)
|
|
{
|
|
// Search for an existing subst table
|
|
for (int i = 0; i < SubstNames.GetSize(); i++)
|
|
{
|
|
if (0 == AsciiStrCmpI(SubstNames[i].sName, pszTableName))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT GetSubstValue(LPCWSTR pszIniFileName, LPCWSTR pszName, LPWSTR pszResult, ULONG cchResult)
|
|
{
|
|
UINT cTablesCount = SubstNames.GetSize();
|
|
|
|
if (pszIniFileName && pszIniFileName[0] == kRESFILECHAR)
|
|
{
|
|
pszIniFileName++;
|
|
}
|
|
|
|
for (UINT i = 0; i < cTablesCount; i++)
|
|
{
|
|
if (0 == AsciiStrCmpI(SubstNames[i].sName, pszIniFileName))
|
|
{
|
|
for (UINT j = SubstNames[i].iFirstIndex; j < SubstNames[i].iFirstIndex + SubstNames[i].cItems; j++)
|
|
{
|
|
if (0 == AsciiStrCmpI(SubstIds[j], pszName))
|
|
{
|
|
StringCchCopyW(pszResult, cchResult, SubstValues[j]);
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return MakeError32(E_FAIL); // unknown sizename
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
LPWSTR FindSymbolToken(LPWSTR pSrc, int nLen)
|
|
{
|
|
LPWSTR p = wcschr(pSrc, INI_MACRO_SYMBOL);
|
|
|
|
// Skip single #s
|
|
while (p != NULL && (p - pSrc < nLen - 1) && *(p + 1) != INI_MACRO_SYMBOL)
|
|
{
|
|
p = wcschr(p + 1, INI_MACRO_SYMBOL);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
LPWSTR ReallocTextBuffer(LPWSTR pSrc, UINT *pnLen)
|
|
{
|
|
*pnLen *= 2; // Double the size each time
|
|
|
|
LPWSTR pszNew = (LPWSTR) LocalReAlloc(pSrc, *pnLen * sizeof(WCHAR), 0);
|
|
if (!pszNew)
|
|
{
|
|
LocalFree(pSrc);
|
|
return NULL;
|
|
}
|
|
return pszNew;
|
|
}
|
|
|
|
LPWSTR SubstituteSymbols(LPWSTR szTableName, LPWSTR pszText)
|
|
{
|
|
UINT iSymbol;
|
|
WCHAR szSymbol[MAX_INPUT_LINE+1];
|
|
|
|
UINT cchText = wcslen(pszText);
|
|
UINT cchTextNew = cchText * 2; // Reserve some additional space
|
|
UINT nBlockSize;
|
|
|
|
LPWSTR pszNew = (LPWSTR) LocalAlloc(0, cchTextNew * sizeof(WCHAR));
|
|
LPWSTR pszDest = pszNew;
|
|
|
|
LPWSTR pszSrc = FindSymbolToken(pszText, cchText);
|
|
LPWSTR pszOldSrc = pszText;
|
|
|
|
HRESULT hr;
|
|
|
|
if (!pszNew)
|
|
return NULL;
|
|
|
|
while (pszSrc != NULL)
|
|
{
|
|
nBlockSize = UINT(pszSrc - pszOldSrc);
|
|
// Check for enough space after substitution
|
|
if (pszDest + nBlockSize >= pszNew + cchTextNew &&
|
|
NULL == (pszNew = ReallocTextBuffer(pszNew, &cchTextNew)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Copy from the last # to the new one
|
|
CopyMemory(pszDest, pszOldSrc, nBlockSize * sizeof(WCHAR)); // don't want the terminating NULL!
|
|
pszDest += nBlockSize;
|
|
pszSrc += 2; // Skip the ##
|
|
|
|
// Copy the symbol name
|
|
iSymbol = 0;
|
|
while (IsCharAlphaNumericW(*pszSrc) || (*pszSrc == '_') || (*pszSrc == '-'))
|
|
{
|
|
szSymbol[iSymbol++] = *pszSrc++;
|
|
}
|
|
szSymbol[iSymbol] = 0;
|
|
|
|
// Get the symbol value
|
|
hr = GetSubstValue(szTableName, szSymbol, szSymbol, ARRAYSIZE(szSymbol));
|
|
if (FAILED(hr))
|
|
{
|
|
// There's a problem, abort and return the buffer untouched
|
|
LocalFree(pszNew);
|
|
|
|
WCHAR szErrorText[MAX_INPUT_LINE + 1];
|
|
StringCchPrintfW(szErrorText, ARRAYSIZE(szErrorText), L"Substitution symbol not found: %s", szSymbol);
|
|
|
|
ReportError(hr, szErrorText);
|
|
return NULL;
|
|
}
|
|
|
|
// Make sure we have enough room for one symbol
|
|
if (pszDest + MAX_INPUT_LINE + 1 >= pszNew + cchTextNew &&
|
|
NULL == (pszNew = ReallocTextBuffer(pszNew, &cchTextNew)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Copy the symbol value to the new text
|
|
iSymbol = 0;
|
|
while (szSymbol[iSymbol] != 0)
|
|
{
|
|
*pszDest++ = szSymbol[iSymbol++];
|
|
}
|
|
|
|
// Advance to the next iteration
|
|
pszOldSrc = pszSrc;
|
|
pszSrc = FindSymbolToken(pszSrc, cchText - UINT(pszSrc - pszText));
|
|
}
|
|
|
|
if (pszDest == pszNew)
|
|
{
|
|
// We did nothing, return NULL
|
|
LocalFree(pszNew);
|
|
return NULL;
|
|
}
|
|
|
|
// Copy the remainder text (after the last #)
|
|
if (pszDest + wcslen(pszOldSrc) >= pszNew + cchTextNew &&
|
|
NULL == (pszNew = ReallocTextBuffer(pszNew, &cchTextNew)))
|
|
{
|
|
return NULL;
|
|
}
|
|
StringCchCopyW(pszDest, lstrlenW(pszOldSrc) + 1, pszOldSrc);
|
|
|
|
return pszNew;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OutputResourceLine(LPCWSTR pszFilename, FILE *outfile, PACKFILETYPE ePackFileType)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//---- did we already process this filename? ----
|
|
UINT cNames = FileInfo.GetSize();
|
|
for (UINT c=0; c < cNames; c++)
|
|
{
|
|
if (lstrcmpi(FileInfo[c].wsName, pszFilename)==0)
|
|
return S_OK;
|
|
}
|
|
|
|
WCHAR szTempName[_MAX_PATH+1];
|
|
WCHAR szResName[_MAX_PATH];
|
|
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
|
|
WCHAR *pszBaseName = szBaseName, *filetype;
|
|
LPWSTR pszText;
|
|
BOOL fWasAnsi;
|
|
BOOL fFileChecked = FALSE;
|
|
|
|
WCHAR szOrigName[_MAX_PATH];
|
|
StringCchCopyW(szOrigName, ARRAYSIZE(szOrigName), pszFilename);
|
|
|
|
_wsplitpath(pszFilename, szDrive, szDir, pszBaseName, szExt);
|
|
|
|
if (ePackFileType == PACK_INIFILE)
|
|
{
|
|
//---- translate to UNICODE, if needed ----
|
|
hr = AllocateTextFile(pszFilename, &pszText, &fWasAnsi);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (*pszBaseName == kRESFILECHAR)
|
|
{
|
|
pszBaseName++;
|
|
}
|
|
|
|
// If this an INI file with a subst table, process the substitution
|
|
for (int i = 0; i < SubstNames.GetSize(); i++)
|
|
{
|
|
if (0 == AsciiStrCmpI(SubstNames[i].sName, pszBaseName))
|
|
{
|
|
SetLastError(0);
|
|
LPWSTR pszNewText = SubstituteSymbols(pszBaseName, pszText);
|
|
if (pszNewText != NULL)
|
|
{
|
|
LPWSTR pszTemp = pszText;
|
|
|
|
pszText = pszNewText;
|
|
LocalFree(pszTemp);
|
|
}
|
|
hr = GetLastError();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HRESULT hr = TextToFile(pszFilename, pszText); // Local hr, ignore failure later
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fWasAnsi = FALSE; // We don't need another temp file
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && fWasAnsi) // write out as temp file
|
|
{
|
|
DWORD len = lstrlen(g_szTempPath);
|
|
|
|
if ((len) && (g_szTempPath[len-1] == '\\'))
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s%s%d%s", g_szTempPath, TEMP_FILENAME_BASE, iTempBitmapNum++, L".uni");
|
|
else
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s\\%s%d%s", g_szTempPath, TEMP_FILENAME_BASE, iTempBitmapNum++, L".uni");
|
|
|
|
hr = TextToFile(szTempName, pszText);
|
|
pszFilename = szTempName; // use this name in .rc file
|
|
}
|
|
|
|
LocalFree(pszText);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
fFileChecked = TRUE;
|
|
}
|
|
|
|
if (! fFileChecked)
|
|
{
|
|
//---- ensure the file is accessible ----
|
|
if (_waccess(pszFilename, 0) != 0)
|
|
{
|
|
fwprintf(ConsoleFile, L"Error - cannot access file: %s\n", pszFilename);
|
|
|
|
return MakeError32(E_FAIL); // cannot access (open) file
|
|
}
|
|
}
|
|
|
|
bool bUseClassName = false;
|
|
|
|
if (ePackFileType == PACK_IMAGEFILE)
|
|
{
|
|
filetype = L"BITMAP";
|
|
bUseClassName = true;
|
|
}
|
|
else if (ePackFileType == PACK_NTLFILE)
|
|
{
|
|
filetype = L"NTL";
|
|
}
|
|
else if (AsciiStrCmpI(szExt, L".ini")==0)
|
|
{
|
|
filetype = L"TEXTFILE";
|
|
}
|
|
else if (AsciiStrCmpI(szExt, L".wav")==0)
|
|
{
|
|
filetype = L"WAVE";
|
|
bUseClassName = true;
|
|
}
|
|
else
|
|
{
|
|
filetype = L"CUSTOM";
|
|
bUseClassName = true;
|
|
}
|
|
|
|
MakeResName(szOrigName, szResName, ARRAYSIZE(szResName), bUseClassName);
|
|
|
|
//---- replace all single backslashes with double ones ----
|
|
WCHAR DblName[_MAX_PATH+1];
|
|
WCHAR *d = DblName;
|
|
LPCWSTR p = pszFilename;
|
|
while (*p)
|
|
{
|
|
if (*p == '\\')
|
|
*d++ = '\\';
|
|
|
|
*d++ = *p++;
|
|
}
|
|
*d = 0;
|
|
|
|
//---- output the line to the .rc file ----
|
|
fwprintf(outfile, L"%-30s \t %s DISCARDABLE \"%s\"\n", szResName, filetype, DblName);
|
|
|
|
FILEINFO fileinfo;
|
|
fileinfo.wsName = pszFilename;
|
|
fileinfo.fIniFile = (ePackFileType == PACK_INIFILE);
|
|
|
|
FileInfo.Add(fileinfo);
|
|
|
|
g_LineCount++;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void ClearCombos()
|
|
{
|
|
for (int s=0; s < MAX_SIZES; s++)
|
|
{
|
|
for (int c=0; c < MAX_COLORS; c++)
|
|
{
|
|
Combos[s][c] = -1; // -1 means no file supports this combo
|
|
}
|
|
}
|
|
|
|
g_iMaxColor = -1;
|
|
g_iMaxSize = -1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OutputCombos(FILE *outfile)
|
|
{
|
|
if ((g_iMaxColor < 0) || (g_iMaxSize < 0)) // no combos found
|
|
return ReportError(E_FAIL, L"No size/color combinations found");
|
|
|
|
fwprintf(outfile, L"COMBO COMBODATA\n");
|
|
fwprintf(outfile, L"BEGIN\n");
|
|
fwprintf(outfile, L" %d, %d // cColors, cSizes\n", g_iMaxColor+1, g_iMaxSize+1);
|
|
|
|
for (int s=0; s <= g_iMaxSize; s++)
|
|
{
|
|
for (int c=0; c <= g_iMaxColor; c++)
|
|
{
|
|
fwprintf(outfile, L" %d, ", Combos[s][c]);
|
|
}
|
|
|
|
fwprintf(outfile, L" // size=%d row\n", s);
|
|
}
|
|
|
|
fwprintf(outfile, L"END\n");
|
|
OutputDashLine(outfile);
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT GetFileIndex(LPCWSTR pszName, int *piIndex)
|
|
{
|
|
int cCount = ResFileNames.GetSize();
|
|
|
|
for (int i=0; i < cCount; i++)
|
|
{
|
|
if (lstrcmpi(ResFileNames[i], pszName)==0)
|
|
{
|
|
*piIndex = i;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return MakeError32(E_FAIL); // unknown filename
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT GetColorIndex(LPCWSTR pszName, int *piIndex)
|
|
{
|
|
int cCount = ColorSchemes.GetSize();
|
|
|
|
for (int i=0; i < cCount; i++)
|
|
{
|
|
if (lstrcmpi(ColorSchemes[i], pszName)==0)
|
|
{
|
|
*piIndex = i;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return MakeError32(E_FAIL); // unknown colorname
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT GetSizeIndex(LPCWSTR pszName, int *piIndex)
|
|
{
|
|
int cCount = SizeNames.GetSize();
|
|
|
|
for (int i=0; i < cCount; i++)
|
|
{
|
|
if (lstrcmpi(SizeNames[i], pszName)==0)
|
|
{
|
|
*piIndex = i;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return MakeError32(E_FAIL); // unknown sizename
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT ApplyCombos(LPCWSTR pszResFileName, LPCWSTR pszColors, LPCWSTR pszSizes)
|
|
{
|
|
//---- get index of pszResFileName ----
|
|
int iFileNum;
|
|
HRESULT hr = GetFileIndex(pszResFileName, &iFileNum);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
//---- parse colors in pszColors ----
|
|
CScanner scan(pszColors);
|
|
WCHAR szName[_MAX_PATH+1];
|
|
int iColors[MAX_COLORS];
|
|
int cColors = 0;
|
|
|
|
while (1)
|
|
{
|
|
if (! scan.GetId(szName))
|
|
return MakeError32(E_FAIL); // bad color list
|
|
|
|
//---- get index of szName ----
|
|
int index;
|
|
HRESULT hr = GetColorIndex(szName, &index);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (cColors == MAX_COLORS)
|
|
return MakeError32(E_FAIL); // too many colors specified
|
|
|
|
iColors[cColors++] = index;
|
|
|
|
if (scan.EndOfLine())
|
|
break;
|
|
|
|
if (! scan.GetChar(L','))
|
|
return MakeError32(E_FAIL); // names must be comma separated
|
|
}
|
|
|
|
|
|
//---- parse sizes in pszSizes ----
|
|
scan.AttachLine(pszSizes);
|
|
int iSizes[MAX_SIZES];
|
|
int cSizes = 0;
|
|
|
|
while (1)
|
|
{
|
|
if (! scan.GetId(szName))
|
|
return MakeError32(E_FAIL); // bad color list
|
|
|
|
//---- get index of szName ----
|
|
int index;
|
|
HRESULT hr = GetSizeIndex(szName, &index);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (cSizes == MAX_SIZES)
|
|
return MakeError32(E_FAIL); // too many sizes specified
|
|
|
|
iSizes[cSizes++] = index;
|
|
|
|
if (scan.EndOfLine())
|
|
break;
|
|
|
|
if (! scan.GetChar(L','))
|
|
return MakeError32(E_FAIL); // names must be comma separated
|
|
}
|
|
|
|
//---- now form all combos of specified colors & sizes ----
|
|
for (int c=0; c < cColors; c++) // for each color
|
|
{
|
|
int color = iColors[c];
|
|
|
|
for (int s=0; s < cSizes; s++) // for each size
|
|
{
|
|
int size = iSizes[s];
|
|
|
|
Combos[size][color] = (SHORT)iFileNum;
|
|
|
|
//---- update our max's ----
|
|
if (size > g_iMaxSize)
|
|
g_iMaxSize = size;
|
|
|
|
if (color > g_iMaxColor)
|
|
g_iMaxColor = color;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void WriteProperty(CSimpleArray<CWideString> &csa, LPCWSTR pszSection, LPCWSTR pszPropName,
|
|
LPCWSTR pszValue)
|
|
{
|
|
WCHAR szBuff[MAX_PATH*2];
|
|
|
|
StringCchPrintfW(szBuff, ARRAYSIZE(szBuff), L"%s@[%s]%s=%s", g_szBaseIniName, pszSection, pszPropName, pszValue);
|
|
|
|
csa.Add(CWideString(szBuff));
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL FnCallBack(enum THEMECALLBACK tcbType, LPCWSTR pszName, LPCWSTR pszName2,
|
|
LPCWSTR pszName3, int iIndex, LPARAM lParam)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int nDefaultDepth = 15;
|
|
|
|
switch (tcbType)
|
|
{
|
|
case TCB_FILENAME:
|
|
WCHAR szFullName[_MAX_PATH+1];
|
|
|
|
hr = AddPathIfNeeded(pszName, g_szInputDir, szFullName, ARRAYSIZE(szFullName));
|
|
if (FAILED(hr))
|
|
{
|
|
SET_LAST_ERROR(hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((iIndex == TMT_IMAGEFILE) || (iIndex == TMT_GLYPHIMAGEFILE) || (iIndex == TMT_STOCKIMAGEFILE))
|
|
hr = OutputResourceLine(szFullName, (FILE *)lParam, PACK_IMAGEFILE);
|
|
else if ((iIndex >= TMT_IMAGEFILE1) && (iIndex <= TMT_IMAGEFILE5))
|
|
hr = OutputResourceLine(szFullName, (FILE *)lParam, PACK_IMAGEFILE);
|
|
else
|
|
hr = MakeError32(E_FAIL); // unexpected type
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
SET_LAST_ERROR(hr);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case TCB_FONT:
|
|
WriteProperty(PropValuePairs, pszName2, pszName3, pszName);
|
|
break;
|
|
|
|
case TCB_MIRRORIMAGE:
|
|
{
|
|
LPCWSTR p;
|
|
|
|
if (lParam)
|
|
p = L"1";
|
|
else
|
|
p = L"0";
|
|
|
|
WriteProperty(PropValuePairs, pszName2, pszName3, p);
|
|
}
|
|
break;
|
|
|
|
case TCB_LOCALIZABLE_RECT:
|
|
{
|
|
WCHAR szBuff[100];
|
|
RECT *prc = (RECT *)lParam;
|
|
|
|
StringCchPrintfW(szBuff, ARRAYSIZE(szBuff), L"%d, %d, %d, %d", prc->left, prc->top, prc->right, prc->bottom);
|
|
|
|
WriteProperty(PropValuePairs, pszName2, pszName3, szBuff);
|
|
}
|
|
break;
|
|
|
|
case TCB_COLORSCHEME:
|
|
ColorSchemes.Add(CWideString(pszName));
|
|
ColorDisplays.Add(CWideString(pszName2));
|
|
ColorToolTips.Add(CWideString(pszName3));
|
|
break;
|
|
|
|
case TCB_SIZENAME:
|
|
SizeNames.Add(CWideString(pszName));
|
|
SizeDisplays.Add(CWideString(pszName2));
|
|
SizeToolTips.Add(CWideString(pszName3));
|
|
break;
|
|
|
|
case TCB_SUBSTTABLE:
|
|
{
|
|
int iTableIndex = GetSubstTableIndex(pszName);
|
|
|
|
if (iTableIndex == -1) // Not found, add one
|
|
{
|
|
sSubstTable s;
|
|
s.sName = pszName;
|
|
s.iFirstIndex = -1;
|
|
s.cItems = 0;
|
|
|
|
SubstNames.Add(s);
|
|
iTableIndex = SubstNames.GetSize() - 1;
|
|
}
|
|
if (0 == AsciiStrCmpI(pszName2, SUBST_TABLE_INCLUDE))
|
|
{
|
|
int iSecondTableIndex = GetSubstTableIndex(pszName3);
|
|
|
|
if (iSecondTableIndex == -1)
|
|
{
|
|
SET_LAST_ERROR(MakeError32(ERROR_NOT_FOUND));
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Copy the symbols in the new table
|
|
for (UINT iSymbol = SubstNames[iSecondTableIndex].iFirstIndex;
|
|
iSymbol < SubstNames[iSecondTableIndex].iFirstIndex + SubstNames[iSecondTableIndex].cItems;
|
|
iSymbol++)
|
|
{
|
|
if (SubstNames[iTableIndex].iFirstIndex == -1)
|
|
{
|
|
SubstNames[iTableIndex].iFirstIndex = SubstValues.GetSize();
|
|
}
|
|
SubstNames[iTableIndex].cItems++;
|
|
SubstIds.Add(CWideString(SubstIds[iSymbol]));
|
|
SubstValues.Add(CWideString(SubstValues[iSymbol]));
|
|
}
|
|
}
|
|
}
|
|
else if (pszName2 != NULL && pszName3 != NULL)
|
|
{
|
|
// If the table was pre-created, update it
|
|
if (SubstNames[iTableIndex].iFirstIndex == -1)
|
|
{
|
|
SubstNames[iTableIndex].iFirstIndex = SubstValues.GetSize();
|
|
}
|
|
SubstNames[iTableIndex].cItems++;
|
|
SubstIds.Add(CWideString(pszName2));
|
|
SubstValues.Add(CWideString(pszName3));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TCB_NEEDSUBST:
|
|
GetSubstValue(pszName, pszName2, (LPWSTR) pszName3, MAX_INPUT_LINE);
|
|
break;
|
|
|
|
case TCB_CDFILENAME:
|
|
WCHAR szResName[_MAX_PATH+1];
|
|
MakeResName(pszName, szResName, ARRAYSIZE(szResName));
|
|
|
|
ResFileNames.Add(CWideString(szResName));
|
|
MinDepths.Add(nDefaultDepth);
|
|
BaseResFileNames.Add(CWideString(pszName));
|
|
OrigFileNames.Add(CWideString(pszName2));
|
|
break;
|
|
|
|
case TCB_CDFILECOMBO:
|
|
MakeResName(pszName, szResName, ARRAYSIZE(szResName));
|
|
|
|
hr = ApplyCombos(szResName, pszName2, pszName3);
|
|
if (FAILED(hr))
|
|
{
|
|
SET_LAST_ERROR(hr);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case TCB_DOCPROPERTY:
|
|
if ((iIndex < 0) || (iIndex >= ARRAYSIZE(DocProperties)))
|
|
return FALSE;
|
|
DocProperties[iIndex] = pszName;
|
|
break;
|
|
|
|
case TCB_MINCOLORDEPTH:
|
|
MakeResName(pszName, szResName, ARRAYSIZE(szResName));
|
|
|
|
int iRes;
|
|
|
|
if (SUCCEEDED(GetFileIndex(szResName, &iRes)))
|
|
{
|
|
MinDepths[iRes] = iIndex;
|
|
}
|
|
break;
|
|
}
|
|
|
|
SET_LAST_ERROR(hr);
|
|
return TRUE;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OpenOutFile(FILE *&outfile, LPCWSTR pszRcName, LPCWSTR pszBaseName)
|
|
{
|
|
if (! outfile) // first time thru
|
|
{
|
|
//---- open out file ----
|
|
outfile = _wfopen(pszRcName, L"wt");
|
|
if (! outfile)
|
|
{
|
|
fwprintf(ConsoleFile, L"Error - cannot open file: %s\n", pszRcName);
|
|
|
|
return MakeError32(E_FAIL);
|
|
}
|
|
|
|
OutputDashLine(outfile);
|
|
fwprintf(outfile, L"// %s.rc - used to build the %s theme DLL\n", pszBaseName, pszBaseName);
|
|
OutputDashLine(outfile);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT ProcessContainerFile(LPCWSTR pszDir, LPCWSTR pszInputName, FILE *&outfile)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//---- output .ini filename as a resource ----
|
|
WCHAR szFullName[_MAX_PATH+1];
|
|
StringCchPrintfW(szFullName, ARRAYSIZE(szFullName), L"%s\\%s", pszDir, pszInputName);
|
|
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"processing container file: %s\n", szFullName);
|
|
|
|
hr = OutputResourceLine(szFullName, outfile, PACK_INIFILE);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Error reading themes.ini file");
|
|
goto exit;
|
|
}
|
|
|
|
OutputDashLine(outfile);
|
|
int oldcnt = g_LineCount;
|
|
|
|
//---- scan the themes.ini files for color, size, & file sections; write 'em to the .rc file ----
|
|
DWORD flags = PTF_CONTAINER_PARSE | PTF_CALLBACK_COLORSECTION | PTF_CALLBACK_SIZESECTION
|
|
| PTF_CALLBACK_FILESECTION | PTF_CALLBACK_DOCPROPERTIES | PTF_CALLBACK_SUBSTTABLE;
|
|
|
|
|
|
WCHAR szErrMsg[4096];
|
|
|
|
hr = _ParseThemeIniFile(szFullName, flags, FnCallBack, (LPARAM)outfile);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Error parsing themes.ini file");
|
|
goto exit;
|
|
}
|
|
|
|
if (g_LineCount > oldcnt)
|
|
OutputDashLine(outfile);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT ProcessClassDataFile(LPCWSTR pszFileName, FILE *&outfile, LPCWSTR pszResFileName, LPCWSTR pszInputDir)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR szFullName[MAX_PATH];
|
|
WCHAR szTempName[MAX_PATH];
|
|
LPWSTR pBS = NULL;
|
|
|
|
hr = SafeStringCchCopyW(g_szCurrentClass, ARRAYSIZE(g_szCurrentClass), pszFileName); // make avail to everybody
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pBS = wcschr(g_szCurrentClass, L'\\');
|
|
|
|
if (pBS)
|
|
{
|
|
*pBS = L'_';
|
|
*(pBS + 1) = L'\0';
|
|
}
|
|
}
|
|
if (pBS == NULL) // If there's no '\', don't use the class name
|
|
{
|
|
g_szCurrentClass[0] = 0;
|
|
}
|
|
|
|
hr = SafeStringCchCopyW(g_szInputDir, ARRAYSIZE(g_szInputDir), pszInputDir ); // make avail to everybody
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = AddPathIfNeeded(pszFileName, pszInputDir, szFullName, ARRAYSIZE(szFullName));
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//---- extract base ini name ----
|
|
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szExt[_MAX_EXT];
|
|
_wsplitpath(szFullName, szDrive, szDir, g_szBaseIniName, szExt);
|
|
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"processing classdata file: %s\n", pszFileName);
|
|
|
|
//---- Create a temporary INI file with the substituted values
|
|
UINT cTablesCount = SubstNames.GetSize();
|
|
for (UINT i = 0; i < cTablesCount; i++)
|
|
{
|
|
if (0 == AsciiStrCmpI(SubstNames[i].sName, pszResFileName))
|
|
{
|
|
// Section used in the string table
|
|
StringCchCopyW(g_szBaseIniName, ARRAYSIZE(g_szBaseIniName), SubstNames[i].sName);
|
|
// Create the temp file
|
|
DWORD len = lstrlen(g_szTempPath);
|
|
|
|
if ((len) && (g_szTempPath[len-1] == '\\'))
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s$%s%s", g_szTempPath, pszResFileName, szExt);
|
|
else
|
|
StringCchPrintfW(szTempName, ARRAYSIZE(szTempName), L"%s\\$%s%s", g_szTempPath, pszResFileName, szExt);
|
|
|
|
if (lstrcmpi(szFullName, szTempName))
|
|
{
|
|
CopyFile(szFullName, szTempName, FALSE);
|
|
SetFileAttributes(szTempName, FILE_ATTRIBUTE_NORMAL);
|
|
StringCchCopyW(szFullName, ARRAYSIZE(szFullName), szTempName);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---- output .ini filename as a resource ----
|
|
hr = OutputResourceLine(szFullName, outfile, PACK_INIFILE);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
OutputDashLine(outfile);
|
|
int oldcnt;
|
|
oldcnt = g_LineCount;
|
|
|
|
//---- scan the classdata .ini file for valid filenames & fonts; write 'em to the .rc file ----
|
|
WCHAR szErrMsg[4096];
|
|
DWORD flags;
|
|
flags = PTF_CLASSDATA_PARSE | PTF_CALLBACK_FILENAMES | PTF_CALLBACK_LOCALIZATIONS
|
|
| PTF_CALLBACK_MINCOLORDEPTH;
|
|
|
|
hr = _ParseThemeIniFile(szFullName, flags, FnCallBack, (LPARAM)outfile);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Error parsing classdata .ini file");
|
|
goto exit;
|
|
}
|
|
|
|
if (g_LineCount > oldcnt)
|
|
OutputDashLine(outfile);
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT ProcessClassDataFiles(FILE *&outfile, LPCWSTR pszInputDir)
|
|
{
|
|
int cNames = OrigFileNames.GetSize();
|
|
|
|
for (int i=0; i < cNames; i++)
|
|
{
|
|
HRESULT hr = ProcessClassDataFile(OrigFileNames[i], outfile, BaseResFileNames[i], pszInputDir);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OutputStringTable(FILE *outfile, CWideString *ppszStrings, UINT cStrings, int iBaseNum,
|
|
LPCWSTR pszTitle, BOOL fLocalizable=TRUE, BOOL fMinDepths=FALSE)
|
|
{
|
|
if (! cStrings)
|
|
return S_OK;
|
|
|
|
if (fLocalizable)
|
|
{
|
|
fwprintf(outfile, L"STRINGTABLE DISCARDABLE // %s\n", pszTitle);
|
|
}
|
|
else // custom resource type
|
|
{
|
|
fwprintf(outfile, L"1 %s DISCARDABLE\n", pszTitle);
|
|
}
|
|
|
|
fwprintf(outfile, L"BEGIN\n");
|
|
|
|
for (UINT c=0; c < cStrings; c++)
|
|
{
|
|
LPCWSTR p = ppszStrings[c];
|
|
if (! p)
|
|
p = L"";
|
|
|
|
if (fLocalizable)
|
|
fwprintf(outfile, L" %d \t\"%s\"\n", iBaseNum, p);
|
|
else
|
|
{
|
|
if (fMinDepths)
|
|
{
|
|
fwprintf(outfile, L" %d,\n", MinDepths[c]);
|
|
}
|
|
else
|
|
{
|
|
fwprintf(outfile, L" L\"%s\\0\",\n", p);
|
|
}
|
|
|
|
if (c == cStrings-1) // last entry
|
|
{
|
|
if (fMinDepths)
|
|
{
|
|
fwprintf(outfile, L" 0\n");
|
|
}
|
|
else
|
|
{
|
|
fwprintf(outfile, L" L\"\\0\",\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
iBaseNum++;
|
|
}
|
|
|
|
fwprintf(outfile, L"END\n");
|
|
OutputDashLine(outfile);
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT OutputAllStringTables(FILE *outfile)
|
|
{
|
|
//---- output all non-localizable strings ----
|
|
if (ColorSchemes.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &ColorSchemes[0], ColorSchemes.GetSize(),
|
|
0, L"COLORNAMES", FALSE);
|
|
}
|
|
|
|
if (SizeNames.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &SizeNames[0], SizeNames.GetSize(),
|
|
0, L"SIZENAMES", FALSE);
|
|
}
|
|
|
|
if (ResFileNames.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &ResFileNames[0], ResFileNames.GetSize(),
|
|
0, L"FILERESNAMES", FALSE);
|
|
}
|
|
|
|
if (MinDepths.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &ResFileNames[0], ResFileNames.GetSize(),
|
|
0, L"MINDEPTH", FALSE, TRUE);
|
|
}
|
|
|
|
if (OrigFileNames.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &OrigFileNames[0], OrigFileNames.GetSize(),
|
|
0, L"ORIGFILENAMES", FALSE);
|
|
}
|
|
|
|
//---- output all localizable strings ----
|
|
if (ColorDisplays.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &ColorDisplays[0], ColorDisplays.GetSize(),
|
|
RES_BASENUM_COLORDISPLAYS, L"Color Display Names");
|
|
}
|
|
|
|
if (ColorToolTips.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &ColorToolTips[0], ColorToolTips.GetSize(),
|
|
RES_BASENUM_COLORTOOLTIPS, L"Color ToolTips");
|
|
}
|
|
|
|
if (SizeDisplays.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &SizeDisplays[0], SizeDisplays.GetSize(),
|
|
RES_BASENUM_SIZEDISPLAYS, L"Size Display Names");
|
|
}
|
|
|
|
if (SizeToolTips.GetSize())
|
|
{
|
|
OutputStringTable(outfile, &SizeToolTips[0], SizeToolTips.GetSize(),
|
|
RES_BASENUM_SIZETOOLTIPS, L"Size ToolTips");
|
|
}
|
|
|
|
OutputStringTable(outfile, &DocProperties[0], ARRAYSIZE(DocProperties),
|
|
RES_BASENUM_DOCPROPERTIES, L"Doc PropValuePairs");
|
|
|
|
OutputStringTable(outfile, &PropValuePairs[0], PropValuePairs.GetSize(),
|
|
RES_BASENUM_PROPVALUEPAIRS, L"PropValuePairs");
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL WriteBitmapHeader(CSimpleFile &cfOut, BYTE *pBytes, DWORD dwBytes)
|
|
{
|
|
BOOL fOK = FALSE;
|
|
BYTE pbHdr1[] = {0x42, 0x4d};
|
|
BYTE pbHdr2[] = {0x0, 0x0, 0x0, 0x0};
|
|
int iFileLen;
|
|
|
|
//---- add bitmap hdr at front ----
|
|
HRESULT hr = cfOut.Write(pbHdr1, sizeof(pbHdr1));
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot write to output file");
|
|
goto exit;
|
|
}
|
|
|
|
//---- add length of data ----
|
|
iFileLen = dwBytes + sizeof(BITMAPFILEHEADER);
|
|
hr = cfOut.Write(&iFileLen, sizeof(int));
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot write to output file");
|
|
goto exit;
|
|
}
|
|
|
|
hr = cfOut.Write(pbHdr2, sizeof(pbHdr2));
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot write to output file");
|
|
goto exit;
|
|
}
|
|
|
|
//---- offset to bits (who's idea was *this* field?) ----
|
|
int iOffset, iColorTableSize;
|
|
DWORD dwSize;
|
|
|
|
iOffset = sizeof(BITMAPFILEHEADER);
|
|
dwSize = *(DWORD *)pBytes;
|
|
iOffset += dwSize;
|
|
iColorTableSize = 0;
|
|
|
|
switch (dwSize)
|
|
{
|
|
case sizeof(BITMAPCOREHEADER):
|
|
BITMAPCOREHEADER *hdr1;
|
|
hdr1 = (BITMAPCOREHEADER *)pBytes;
|
|
if (hdr1->bcBitCount == 1)
|
|
iColorTableSize = 2*sizeof(RGBTRIPLE);
|
|
else if (hdr1->bcBitCount == 4)
|
|
iColorTableSize = 16*sizeof(RGBTRIPLE);
|
|
else if (hdr1->bcBitCount == 8)
|
|
iColorTableSize = 256*sizeof(RGBTRIPLE);
|
|
break;
|
|
|
|
case sizeof(BITMAPINFOHEADER):
|
|
case sizeof(BITMAPV4HEADER):
|
|
case sizeof(BITMAPV5HEADER):
|
|
BITMAPINFOHEADER *hdr2;
|
|
hdr2 = (BITMAPINFOHEADER *)pBytes;
|
|
if (hdr2->biClrUsed)
|
|
iColorTableSize = hdr2->biClrUsed*sizeof(RGBQUAD);
|
|
else
|
|
{
|
|
if (hdr2->biBitCount == 1)
|
|
iColorTableSize = 2*sizeof(RGBQUAD);
|
|
else if (hdr2->biBitCount == 4)
|
|
iColorTableSize = 16*sizeof(RGBQUAD);
|
|
else if (hdr2->biBitCount == 8)
|
|
iColorTableSize = 256*sizeof(RGBQUAD);
|
|
}
|
|
break;
|
|
}
|
|
|
|
iOffset += iColorTableSize;
|
|
hr = cfOut.Write(&iOffset, sizeof(int));
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot write to output file");
|
|
goto exit;
|
|
}
|
|
|
|
fOK = TRUE;
|
|
|
|
exit:
|
|
return fOK;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
BOOL CALLBACK ResEnumerator(HMODULE hModule, LPCWSTR pszType, LPWSTR pszResName, LONG_PTR lParam)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fAnsi = (BOOL)lParam;
|
|
BOOL fText = FALSE;
|
|
RESOURCE BYTE *pBytes = NULL;
|
|
CSimpleFile cfOut;
|
|
DWORD dwBytes;
|
|
|
|
if (pszType != RT_BITMAP)
|
|
fText = TRUE;
|
|
|
|
hr = GetPtrToResource(hModule, pszType, pszResName, (void **)&pBytes, &dwBytes);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"error reading file resources");
|
|
goto exit;
|
|
}
|
|
|
|
//---- convert name to filename ----
|
|
WCHAR szFileName[_MAX_PATH+1];
|
|
StringCchCopyW(szFileName, ARRAYSIZE(szFileName), pszResName);
|
|
WCHAR *q;
|
|
q = wcsrchr(szFileName, '_');
|
|
if (q)
|
|
*q = '.';
|
|
|
|
if (! fText)
|
|
fAnsi = FALSE; // don't translate if binary data
|
|
|
|
hr = cfOut.Create(szFileName, fAnsi);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot create output file");
|
|
goto exit;
|
|
}
|
|
|
|
if (! fText)
|
|
{
|
|
if (! WriteBitmapHeader(cfOut, pBytes, dwBytes))
|
|
goto exit;
|
|
}
|
|
|
|
hr = cfOut.Write(pBytes, dwBytes);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Cannot write to output file");
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return (SUCCEEDED(hr));
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void WriteBitmap(LPWSTR pszFileName, BITMAPINFOHEADER* pbmi, DWORD* pdwData)
|
|
{
|
|
DWORD dwLen = pbmi->biWidth * pbmi->biHeight;
|
|
|
|
CSimpleFile cfOut;
|
|
cfOut.Create(pszFileName, FALSE);
|
|
|
|
BITMAPFILEHEADER bmfh = {0};
|
|
bmfh.bfType = 'MB';
|
|
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (dwLen * sizeof(DWORD));
|
|
bmfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
|
|
cfOut.Write(&bmfh, sizeof(BITMAPFILEHEADER));
|
|
cfOut.Write(pbmi, sizeof(BITMAPINFOHEADER));
|
|
cfOut.Write(pdwData, dwLen * sizeof(DWORD));
|
|
}
|
|
|
|
HRESULT ColorShift(LPWSTR pszFileName, int cchFileName)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
if (hdc)
|
|
{
|
|
HBITMAP hbm = (HBITMAP)LoadImage(0, pszFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
|
|
if (hbm)
|
|
{
|
|
BITMAP bm;
|
|
GetObject(hbm, sizeof(bm), &bm);
|
|
|
|
DWORD dwLen = bm.bmWidth * bm.bmHeight;
|
|
DWORD* pPixelQuads = new DWORD[dwLen];
|
|
if (pPixelQuads)
|
|
{
|
|
BITMAPINFO bi = {0};
|
|
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth = bm.bmWidth;
|
|
bi.bmiHeader.biHeight = bm.bmHeight;
|
|
bi.bmiHeader.biPlanes = 1;
|
|
bi.bmiHeader.biBitCount = 32;
|
|
bi.bmiHeader.biCompression = BI_RGB;
|
|
|
|
if (GetDIBits(hdc, hbm, 0, bm.bmHeight, pPixelQuads, &bi, DIB_RGB_COLORS))
|
|
{
|
|
pszFileName[lstrlen(pszFileName) - 4] = 0;
|
|
|
|
WCHAR szFileNameR[MAX_PATH];
|
|
StringCchPrintfW(szFileNameR, ARRAYSIZE(szFileNameR), L"%sR.bmp", pszFileName);
|
|
WCHAR szFileNameG[MAX_PATH];
|
|
StringCchPrintfW(szFileNameG, ARRAYSIZE(szFileNameG), L"%sG.bmp", pszFileName);
|
|
WCHAR szFileNameB[MAX_PATH];
|
|
StringCchPrintfW(szFileNameB, ARRAYSIZE(szFileNameB), L"%sB.bmp", pszFileName);
|
|
|
|
WriteBitmap(szFileNameB, &bi.bmiHeader, pPixelQuads);
|
|
|
|
DWORD *pdw = pPixelQuads;
|
|
for (DWORD i = 0; i < dwLen; i++)
|
|
{
|
|
COLORREF crTemp = *pdw;
|
|
if (crTemp != RGB(255, 0, 255))
|
|
{
|
|
crTemp = (crTemp & 0xff000000) | RGB(GetGValue(crTemp), GetBValue(crTemp), GetRValue(crTemp));
|
|
}
|
|
*pdw = crTemp;
|
|
pdw++;
|
|
}
|
|
|
|
WriteBitmap(szFileNameR, &bi.bmiHeader, pPixelQuads);
|
|
|
|
pdw = pPixelQuads;
|
|
for (DWORD i = 0; i < dwLen; i++)
|
|
{
|
|
COLORREF crTemp = *pdw;
|
|
if (crTemp != RGB(255, 0, 255))
|
|
{
|
|
crTemp = (crTemp & 0xff000000) | RGB(GetGValue(crTemp), GetBValue(crTemp), GetRValue(crTemp));
|
|
}
|
|
*pdw = crTemp;
|
|
pdw++;
|
|
}
|
|
|
|
WriteBitmap(szFileNameG, &bi.bmiHeader, pPixelQuads);
|
|
}
|
|
|
|
delete[] pPixelQuads;
|
|
}
|
|
DeleteObject(hbm);
|
|
}
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
HRESULT UnpackTheme(LPCWSTR pszFileName, BOOL fAnsi)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//---- load the file as a resource only DLL ----
|
|
RESOURCE HINSTANCE hInst = LoadLibraryEx(pszFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
if (hInst)
|
|
{
|
|
//---- enum all bitmaps & write as files ----
|
|
if (! EnumResourceNames(hInst, RT_BITMAP, ResEnumerator, LPARAM(fAnsi)))
|
|
hr = GetLastError();
|
|
|
|
//---- enum all .ini files & write as files ----
|
|
if (! EnumResourceNames(hInst, L"TEXTFILE", ResEnumerator, LPARAM(fAnsi)))
|
|
hr = GetLastError();
|
|
|
|
//---- close the file ----
|
|
if (hInst)
|
|
FreeLibrary(hInst);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT PackTheme(LPCWSTR pszInputDir, LPWSTR pszOutputName, DWORD cchOutputName)
|
|
{
|
|
//---- is it a valid dir ----
|
|
DWORD dwMask = GetFileAttributes(pszInputDir);
|
|
if ((dwMask == 0xffffffff) || (! (dwMask & FILE_ATTRIBUTE_DIRECTORY)))
|
|
{
|
|
fwprintf(ConsoleFile, L"\nError - not a valid directory name: %s\n", pszInputDir);
|
|
return MakeError32(E_FAIL);
|
|
}
|
|
|
|
//---- build: szDllName ----
|
|
WCHAR szDllName[_MAX_PATH+1];
|
|
BOOL fOutputDir = FALSE;
|
|
|
|
if (! *pszOutputName) // not specified - build from pszInputDir
|
|
{
|
|
WCHAR szFullDir[_MAX_PATH+1];
|
|
WCHAR *pszBaseName;
|
|
|
|
DWORD val = GetFullPathName(pszInputDir, ARRAYSIZE(szFullDir), szFullDir, &pszBaseName);
|
|
if (! val)
|
|
return MakeErrorLast();
|
|
|
|
//---- make output dir same as input dir ----
|
|
StringCchPrintfW(szDllName, ARRAYSIZE(szDllName), L"%s\\%s%s", pszInputDir, pszBaseName, THEMEDLL_EXT);
|
|
}
|
|
else // get full name of output file
|
|
{
|
|
DWORD val = GetFullPathName(pszOutputName, ARRAYSIZE(szDllName), szDllName, NULL);
|
|
if (! val)
|
|
return MakeErrorLast();
|
|
|
|
fOutputDir = TRUE; // don't remove temp files
|
|
}
|
|
|
|
// Give the caller the path so the file can be signed.
|
|
StringCchCopyW(pszOutputName, cchOutputName, szDllName);
|
|
|
|
//--- delete the old target in case we have errors ----
|
|
DeleteFile(pszOutputName);
|
|
|
|
//---- build: g_szTempPath, szDllRoot, szRcName, and szResName ----
|
|
WCHAR szDllRoot[_MAX_PATH+1];
|
|
WCHAR szResName[_MAX_PATH+1];
|
|
WCHAR szRcName[_MAX_PATH+1];
|
|
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
|
|
|
|
_wsplitpath(szDllName, szDrive, szDir, szBaseName, szExt);
|
|
|
|
_wmakepath(szDllRoot, L"", L"", szBaseName, szExt);
|
|
_wmakepath(szRcName, szDrive, szDir, szBaseName, L".rc");
|
|
_wmakepath(szResName, szDrive, szDir, szBaseName, L".res");
|
|
|
|
if (fOutputDir)
|
|
_wmakepath(g_szTempPath, szDrive, szDir, L"", L"");
|
|
else
|
|
StringCchCopyW(g_szTempPath, ARRAYSIZE(g_szTempPath), L".");
|
|
|
|
FILE *outfile = NULL;
|
|
OpenOutFile(outfile, szRcName, szBaseName);
|
|
|
|
ClearCombos();
|
|
|
|
//---- process the main container file ----
|
|
HRESULT hr = ProcessContainerFile(pszInputDir, CONTAINER_NAME, outfile);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//---- process all classdata files that were defined in container file ----
|
|
hr = ProcessClassDataFiles(outfile, pszInputDir);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//---- output all string tables ----
|
|
hr = OutputAllStringTables(outfile);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = OutputCombos(outfile);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
hr = OutputVersionInfo(outfile, szDllRoot, szBaseName);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
fclose(outfile);
|
|
outfile = NULL;
|
|
|
|
hr = BuildThemeDll(szRcName, szResName, szDllName);
|
|
|
|
exit:
|
|
if (outfile)
|
|
fclose(outfile);
|
|
|
|
if (ConsoleFile != stdout)
|
|
fclose(ConsoleFile);
|
|
|
|
if (! g_fKeepTempFiles)
|
|
RemoveTempFiles(szRcName, szResName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"Created %s\n", szDllName);
|
|
return S_OK;
|
|
}
|
|
|
|
if (! g_fQuietRun)
|
|
fwprintf(ConsoleFile, L"Error occured - theme DLL not created\n");
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void PrintUsage()
|
|
{
|
|
fwprintf(ConsoleFile, L"\nUsage: \n\n");
|
|
fwprintf(ConsoleFile, L" packthem [-o <output name> ] [-k] [-q] <dirname>\n");
|
|
fwprintf(ConsoleFile, L" -m specifies the (full path) name of the image file you want to color shift\n");
|
|
fwprintf(ConsoleFile, L" -o specifies the (full path) name of the output file\n");
|
|
fwprintf(ConsoleFile, L" -k specifies that temp. files should be kept (not deleted)\n");
|
|
fwprintf(ConsoleFile, L" -d do not sign the file when building it\n");
|
|
fwprintf(ConsoleFile, L" -q quite mode (don't print header and progress msgs)\n\n");
|
|
|
|
fwprintf(ConsoleFile, L" packthem -u [-a] <packed filename> \n");
|
|
fwprintf(ConsoleFile, L" -u unpacks the packed file into its separate files in current dir\n");
|
|
fwprintf(ConsoleFile, L" -a writes .ini files as ANSI (defaults to UNICODE)\n\n");
|
|
|
|
fwprintf(ConsoleFile, L" packthem -p [-q] <packed filename> \n");
|
|
fwprintf(ConsoleFile, L" -p Parses the localized packed file and reports errors\n\n");
|
|
|
|
fwprintf(ConsoleFile, L" packthem [-c] [-q] <packed filename> \n");
|
|
fwprintf(ConsoleFile, L" -c check the signature of the already created file\n\n");
|
|
|
|
fwprintf(ConsoleFile, L" packthem [-s] [-q] <packed filename> \n");
|
|
fwprintf(ConsoleFile, L" -s sign the already created file\n\n");
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
enum eOperation
|
|
{
|
|
opPack = 1,
|
|
opUnPack,
|
|
opSign,
|
|
opCheckSignature,
|
|
opParse,
|
|
opColorShift
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
extern "C" WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE previnst,
|
|
LPTSTR pszCmdLine, int nShowCmd)
|
|
{
|
|
//---- initialize globals from themeldr.lib ----
|
|
ThemeLibStartUp(FALSE);
|
|
|
|
//---- initialize our globals ----
|
|
HRESULT hr = S_OK;
|
|
int nWeek = -1;
|
|
|
|
UtilsStartUp();
|
|
LogStartUp();
|
|
|
|
WCHAR szOutputName[_MAX_PATH+1] = {0};
|
|
int retval = 1; // error, until prove otherwise
|
|
|
|
BOOL fAnsi = FALSE;
|
|
BOOL fSkipSigning = FALSE;
|
|
eOperation Operation = opPack;
|
|
|
|
LPCWSTR p = pszCmdLine;
|
|
szOutputName[0] = 0; // Much faster than ={0};
|
|
|
|
//---- default to console until something else is specified ----
|
|
if (! ConsoleFile)
|
|
{
|
|
ConsoleFile = stdout;
|
|
}
|
|
|
|
while ((*p == '-') || (*p == '/'))
|
|
{
|
|
p++;
|
|
WCHAR sw = *p;
|
|
|
|
if (isupper(sw))
|
|
sw = (WCHAR)tolower(sw);
|
|
|
|
if (sw == 'e')
|
|
{
|
|
ConsoleFile = _wfopen(L"packthem.err", L"wt");
|
|
g_fQuietRun = TRUE;
|
|
p++;
|
|
}
|
|
else if (sw == 'o')
|
|
{
|
|
WCHAR *q = szOutputName;
|
|
p++; // skip over switch
|
|
while (iswspace(*p))
|
|
p++;
|
|
while ((*p) && (! iswspace(*p)))
|
|
*q++ = *p++;
|
|
|
|
*q = 0; // terminate the output name
|
|
}
|
|
else if (sw == 'k')
|
|
{
|
|
g_fKeepTempFiles = TRUE;
|
|
p++;
|
|
}
|
|
else if (sw == 'q')
|
|
{
|
|
g_fQuietRun = TRUE;
|
|
p++;
|
|
}
|
|
else if (sw == 'm')
|
|
{
|
|
Operation = opColorShift;
|
|
|
|
WCHAR *q = szOutputName;
|
|
p++; // skip over switch
|
|
while (iswspace(*p))
|
|
p++;
|
|
while ((*p) && (! iswspace(*p)))
|
|
*q++ = *p++;
|
|
|
|
*q = 0; // terminate the output name
|
|
}
|
|
else if (sw == 'u')
|
|
{
|
|
Operation = opUnPack;
|
|
p++;
|
|
}
|
|
else if (sw == 'd')
|
|
{
|
|
fSkipSigning = TRUE;
|
|
p++;
|
|
}
|
|
else if (sw == 'c')
|
|
{
|
|
Operation = opCheckSignature;
|
|
p++;
|
|
}
|
|
else if (sw == 's')
|
|
{
|
|
Operation = opSign;
|
|
p++;
|
|
}
|
|
else if (sw == 'a')
|
|
{
|
|
fAnsi = TRUE;
|
|
p++;
|
|
}
|
|
else if (sw == 'w')
|
|
{
|
|
fAnsi = TRUE;
|
|
p++;
|
|
|
|
LARGE_INTEGER uli;
|
|
WCHAR szWeek[3];
|
|
|
|
szWeek[0] = p[0];
|
|
szWeek[1] = p[1];
|
|
szWeek[2] = 0;
|
|
if (StrToInt64ExInternalW(szWeek, 0, &(uli.QuadPart)) &&
|
|
(uli.QuadPart > 0))
|
|
{
|
|
nWeek = (int)uli.LowPart;
|
|
}
|
|
|
|
while ((L' ' != p[0]) && (0 != p[0]))
|
|
{
|
|
p++;
|
|
}
|
|
}
|
|
else if (sw == 'p')
|
|
{
|
|
Operation = opParse;
|
|
p++;
|
|
}
|
|
else if (sw == '?')
|
|
{
|
|
PrintUsage();
|
|
retval = 0;
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
fwprintf(ConsoleFile, L"Error - unrecognized switch: %s\n", p);
|
|
goto exit;
|
|
}
|
|
|
|
while (iswspace(*p))
|
|
p++;
|
|
}
|
|
|
|
LPCWSTR pszInputDir;
|
|
pszInputDir = p;
|
|
|
|
if (! g_fQuietRun)
|
|
{
|
|
fwprintf(ConsoleFile, L"Microsoft (R) Theme Packager (Version %d)\n", PACKTHEM_VERSION);
|
|
fwprintf(ConsoleFile, L"Copyright (C) Microsoft Corp 2000. All rights reserved.\n");
|
|
}
|
|
|
|
//---- any cmdline arg specified? ----
|
|
if (Operation != opColorShift)
|
|
{
|
|
if ((! pszInputDir) || (! *pszInputDir))
|
|
{
|
|
PrintUsage();
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
switch (Operation)
|
|
{
|
|
case opPack:
|
|
hr = PackTheme(pszInputDir, szOutputName, ARRAYSIZE(szOutputName));
|
|
if (SUCCEEDED(hr) && !fSkipSigning)
|
|
{
|
|
hr = SignTheme(szOutputName, nWeek);
|
|
if (!g_fQuietRun)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wprintf(L"Creating the signature succeeded\n");
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"The signature failed to be created. hr=%#08lx\n", hr);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case opUnPack:
|
|
hr = UnpackTheme(pszInputDir, fAnsi);
|
|
break;
|
|
case opSign:
|
|
// We don't sign it again if the signature is already valid.
|
|
if (FAILED(CheckThemeFileSignature(pszInputDir)))
|
|
{
|
|
// Needs signing.
|
|
hr = SignTheme(pszInputDir, nWeek);
|
|
if (!g_fQuietRun)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wprintf(L"Creating the signature succeeded\n");
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"The signature failed to be created. hr=%#08lx\n", hr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!g_fQuietRun)
|
|
{
|
|
wprintf(L"The file was already signed and the signature is still valid.");
|
|
}
|
|
}
|
|
break;
|
|
case opCheckSignature:
|
|
hr = CheckThemeFileSignature(pszInputDir);
|
|
if (!g_fQuietRun)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
wprintf(L"The signature is valid\n");
|
|
}
|
|
else
|
|
{
|
|
wprintf(L"The signature is not valid. hr=%#08lx\n", hr);
|
|
}
|
|
}
|
|
break;
|
|
case opParse:
|
|
hr = ParseTheme(pszInputDir);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportError(hr, L"Error during parsing");
|
|
goto exit;
|
|
} else
|
|
{
|
|
wprintf(L"No errors parsing theme file\n");
|
|
}
|
|
break;
|
|
case opColorShift:
|
|
hr = ColorShift(szOutputName, ARRAYSIZE(szOutputName));
|
|
break;
|
|
|
|
default:
|
|
if (FAILED(hr))
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
break;
|
|
};
|
|
|
|
retval = 0; // all OK
|
|
|
|
exit:
|
|
UtilsShutDown();
|
|
LogShutDown();
|
|
|
|
return retval;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
HRESULT 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);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// Parse the theme to detect localization errors
|
|
HRESULT ParseTheme(LPCWSTR pszThemeName)
|
|
{
|
|
// Dummy callback class needed by the parser
|
|
class CParserCallBack: public IParserCallBack
|
|
{
|
|
HRESULT AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName,
|
|
int iPartNum, int iStateNum, int iIndex, int iLen) { return S_OK; };
|
|
HRESULT AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen) { return S_OK; };
|
|
int GetNextDataIndex() { return 0; };
|
|
};
|
|
|
|
CParserCallBack *pParserCallBack = NULL;
|
|
CThemeParser *pParser = NULL;
|
|
|
|
HRESULT hr;
|
|
HINSTANCE hInst = NULL;
|
|
WCHAR *pDataIni = NULL;
|
|
WCHAR szClassDataName[_MAX_PATH+1];
|
|
|
|
//---- load the Color Scheme from "themes.ini" ----
|
|
hr = LoadThemeLibrary(pszThemeName, &hInst);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
pParser = new CThemeParser(FALSE);
|
|
if (! pParser)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
pParserCallBack = new CParserCallBack;
|
|
if (!pParserCallBack)
|
|
{
|
|
hr = MakeError32(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
THEMENAMEINFO tniColors;
|
|
THEMENAMEINFO tniSizes;
|
|
|
|
for (DWORD c = 0; ; c++)
|
|
{
|
|
if (FAILED(_EnumThemeColors(hInst, pszThemeName, NULL, c, &tniColors, FALSE)))
|
|
break;
|
|
|
|
for (DWORD s = 0 ; ; s++)
|
|
{
|
|
if (FAILED(_EnumThemeSizes(hInst, pszThemeName, tniColors.szName, s, &tniSizes, FALSE)))
|
|
break;
|
|
|
|
//---- load the classdata file resource into memory ----
|
|
hr = LoadClassDataIni(hInst, tniColors.szName, tniSizes.szName, szClassDataName, ARRAYSIZE(szClassDataName), &pDataIni);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//---- parse & build binary theme ----
|
|
hr = pParser->ParseThemeBuffer(pDataIni, szClassDataName, NULL, hInst,
|
|
pParserCallBack, FnCallBack, NULL, PTF_CLASSDATA_PARSE);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
if (pDataIni)
|
|
{
|
|
delete [] pDataIni;
|
|
pDataIni = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (hInst)
|
|
FreeLibrary(hInst);
|
|
|
|
if (pDataIni)
|
|
delete [] pDataIni;
|
|
|
|
if (pParser)
|
|
delete pParser;
|
|
|
|
if (pParserCallBack)
|
|
delete pParserCallBack;
|
|
|
|
return hr;
|
|
}
|