Source code of Windows XP (NT5)
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.

2051 lines
59 KiB

  1. //---------------------------------------------------------------------------
  2. // PackThem.cpp - packs up theme files into a theme DLL
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include <uxthemep.h>
  6. #include <utils.h>
  7. #include "SimpStr.h"
  8. #include "Scanner.h"
  9. #include "shlwapip.h"
  10. #include "parser.h"
  11. #include "TmSchema.h"
  12. #include "signing.h"
  13. #include "localsign.h"
  14. #include "ThemeLdr.h"
  15. #include "TmUtils.h"
  16. #include "StringTable.h"
  17. HRESULT ParseTheme(LPCWSTR pszThemeName);
  18. //---------------------------------------------------------------------------
  19. struct FILEINFO
  20. {
  21. CWideString wsName;
  22. BOOL fIniFile;
  23. };
  24. //---------------------------------------------------------------------------
  25. #define MAX_COLORS 50
  26. #define MAX_SIZES 20
  27. #define TEMP_FILENAME_BASE L"$temp$"
  28. #define kRESFILECHAR L'$'
  29. //---------------------------------------------------------------------------
  30. enum PACKFILETYPE
  31. {
  32. PACK_INIFILE,
  33. PACK_IMAGEFILE,
  34. PACK_NTLFILE,
  35. PACK_OTHER
  36. };
  37. //---------------------------------------------------------------------------
  38. CSimpleArray<FILEINFO> FileInfo;
  39. CSimpleArray<CWideString> ColorSchemes;
  40. CSimpleArray<CWideString> ColorDisplays;
  41. CSimpleArray<CWideString> ColorToolTips;
  42. CSimpleArray<int> MinDepths;
  43. CSimpleArray<CWideString> SizeNames;
  44. CSimpleArray<CWideString> SizeDisplays;
  45. CSimpleArray<CWideString> SizeToolTips;
  46. typedef struct
  47. {
  48. CWideString sName;
  49. int iFirstIndex;
  50. UINT cItems;
  51. } sSubstTable;
  52. CSimpleArray<sSubstTable> SubstNames;
  53. CSimpleArray<CWideString> SubstIds;
  54. CSimpleArray<CWideString> SubstValues;
  55. CSimpleArray<CWideString> BaseResFileNames;
  56. CSimpleArray<CWideString> ResFileNames;
  57. CSimpleArray<CWideString> OrigFileNames;
  58. CSimpleArray<CWideString> PropValuePairs;
  59. //---------------------------------------------------------------------------
  60. SHORT Combos[MAX_SIZES][MAX_COLORS];
  61. int g_iMaxColor;
  62. int g_iMaxSize;
  63. int g_LineCount = 0;
  64. int iTempBitmapNum = 1;
  65. BOOL g_fQuietRun = FALSE; // don't show needless output
  66. BOOL g_fKeepTempFiles = FALSE;
  67. FILE *ConsoleFile = NULL;
  68. WCHAR g_szInputDir[_MAX_PATH+1];
  69. WCHAR g_szTempPath[_MAX_PATH+1];
  70. WCHAR g_szBaseIniName[_MAX_PATH+1];
  71. WCHAR g_szCurrentClass[_MAX_PATH+1];
  72. //---------------------------------------------------------------------------
  73. #define DOCPROPCNT (1+TMT_LAST_RCSTRING_NAME - TMT_FIRST_RCSTRING_NAME)
  74. CWideString DocProperties[DOCPROPCNT];
  75. //---------------------------------------------------------------------------
  76. HRESULT ReportError(HRESULT hr, LPWSTR pszDefaultMsg)
  77. {
  78. WCHAR szErrorMsg[2*_MAX_PATH+1];
  79. PARSE_ERROR_INFO Info = {sizeof(Info)};
  80. BOOL fGotMsg = FALSE;
  81. if (THEME_PARSING_ERROR(hr))
  82. {
  83. if (SUCCEEDED(_GetThemeParseErrorInfo(&Info)))
  84. {
  85. lstrcpy(szErrorMsg, Info.szMsg);
  86. fGotMsg = TRUE;
  87. }
  88. }
  89. if (! fGotMsg)
  90. {
  91. lstrcpy(szErrorMsg, pszDefaultMsg);
  92. }
  93. if (*Info.szFileName) // input file error
  94. {
  95. fwprintf(ConsoleFile, L"%s(%d): error - %s\n",
  96. Info.szFileName, Info.iLineNum, szErrorMsg);
  97. fwprintf(ConsoleFile, L"%s\n", Info.szSourceLine);
  98. }
  99. else // general error
  100. {
  101. fwprintf(ConsoleFile, L"%s(): error - %s\n",
  102. g_szInputDir, szErrorMsg);
  103. }
  104. SET_LAST_ERROR(hr);
  105. return hr;
  106. }
  107. //---------------------------------------------------------------------------
  108. void MakeResName(LPCWSTR pszName, LPWSTR pszResName, bool bUseClassName = false)
  109. {
  110. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
  111. //---- isolate base name (no path) ----
  112. _wsplitpath(pszName, szDrive, szDir, szBaseName, szExt);
  113. if (szBaseName[0] == kRESFILECHAR) // Don't put $ in resource names
  114. {
  115. wcscpy(szBaseName, szBaseName + 1);
  116. }
  117. //---- replace the "." with a '_' ----
  118. //---- if a file section name without .ini, append _INI so that the extracted files has .ini extension
  119. if (*szExt)
  120. {
  121. wsprintf(pszResName, L"%s%s_%s", bUseClassName ? g_szCurrentClass : L"", szBaseName, szExt+1);
  122. } else
  123. {
  124. wsprintf(pszResName, L"%s%s_INI", bUseClassName ? g_szCurrentClass : L"", szBaseName);
  125. }
  126. //---- all uppercase ----
  127. CharUpperBuff(pszResName, lstrlen(pszResName));
  128. //---- replace any spaces with underscores ----
  129. WCHAR *q = pszResName;
  130. while (*q)
  131. {
  132. if (*q == ' ')
  133. *q = '_';
  134. q++;
  135. }
  136. }
  137. //---------------------------------------------------------------------------
  138. HRESULT BuildThemeDll(LPCWSTR pszRcName, LPCWSTR pszResName, LPCWSTR pszDllName)
  139. {
  140. if (! g_fQuietRun)
  141. fwprintf(ConsoleFile, L"compiling resources\n");
  142. HRESULT hr = SyncCmdLineRun(L"rc.exe", pszRcName);
  143. if (FAILED(hr))
  144. return ReportError(hr, L"Error during resource compiliation");
  145. //---- run LINK to create the DLL ----
  146. WCHAR params[2*_MAX_PATH+1];
  147. if (! g_fQuietRun)
  148. fwprintf(ConsoleFile, L"linking theme dll\n");
  149. wsprintf(params, L"/out:%s /machine:ix86 /dll /noentry %s", pszDllName, pszResName);
  150. hr = SyncCmdLineRun(L"link.exe", params);
  151. if (FAILED(hr))
  152. return ReportError(hr, L"Error during DLL linking");
  153. return S_OK;
  154. }
  155. //---------------------------------------------------------------------------
  156. void OutputDashLine(FILE *outfile)
  157. {
  158. fwprintf(outfile, L"//----------------------------------------------------------------------\n");
  159. }
  160. //---------------------------------------------------------------------------
  161. inline void ValueLine(FILE *outfile, LPCWSTR pszName, LPCWSTR pszValue)
  162. {
  163. fwprintf(outfile, L" VALUE \"%s\", \"%s\\0\"\n", pszName, pszValue);
  164. }
  165. //---------------------------------------------------------------------------
  166. HRESULT OutputVersionInfo(FILE *outfile, LPCWSTR pszFileName, LPCWSTR pszBaseName)
  167. {
  168. fwprintf(outfile, L"1 PACKTHEM_VERSION\n");
  169. fwprintf(outfile, L"BEGIN\n");
  170. fwprintf(outfile, L" %d\n", PACKTHEM_VERSION);
  171. fwprintf(outfile, L"END\n");
  172. OutputDashLine(outfile);
  173. WCHAR *Company = L"Microsoft";
  174. WCHAR *Copyright = L"Copyright � 2000";
  175. WCHAR szDescription[2*_MAX_PATH+1];
  176. wsprintf(szDescription, L"%s Theme for Windows", pszBaseName);
  177. fwprintf(outfile, L"1 VERSIONINFO\n");
  178. fwprintf(outfile, L" FILEVERSION 1,0,0,1\n");
  179. fwprintf(outfile, L" PRODUCTVERSION 1,0,0,1\n");
  180. fwprintf(outfile, L" FILEFLAGSMASK 0x3fL\n");
  181. fwprintf(outfile, L" FILEFLAGS 0x0L\n");
  182. fwprintf(outfile, L" FILEOS 0x40004L\n");
  183. fwprintf(outfile, L" FILETYPE 0x1L\n");
  184. fwprintf(outfile, L" FILESUBTYPE 0x0L\n");
  185. fwprintf(outfile, L"BEGIN\n");
  186. fwprintf(outfile, L" BLOCK \"StringFileInfo\"\n");
  187. fwprintf(outfile, L" BEGIN\n");
  188. fwprintf(outfile, L" BLOCK \"040904b0\"\n");
  189. fwprintf(outfile, L" BEGIN\n");
  190. ValueLine(outfile, L"Comments", L"");
  191. ValueLine(outfile, L"CompanyName", Company);
  192. ValueLine(outfile, L"FileDescription", szDescription);
  193. ValueLine(outfile, L"FileVersion", L"1, 0, 0, 1");
  194. ValueLine(outfile, L"InternalName", pszFileName);
  195. ValueLine(outfile, L"LegalCopyright", Copyright);
  196. ValueLine(outfile, L"LegalTrademarks", L"");
  197. ValueLine(outfile, L"OriginalFilename", pszFileName);
  198. ValueLine(outfile, L"PrivateBuild", L"");
  199. ValueLine(outfile, L"ProductName", szDescription);
  200. ValueLine(outfile, L"ProductVersion", L"1, 0, 0, 1");
  201. ValueLine(outfile, L"SpecialBuild", L"");
  202. fwprintf(outfile, L" END\n");
  203. fwprintf(outfile, L" END\n");
  204. fwprintf(outfile, L" BLOCK \"VarFileInfo\"\n");
  205. fwprintf(outfile, L" BEGIN\n");
  206. fwprintf(outfile, L" VALUE \"Translation\", 0x409, 1200\n");
  207. fwprintf(outfile, L" END\n");
  208. fwprintf(outfile, L"END\n");
  209. OutputDashLine(outfile);
  210. return S_OK;
  211. }
  212. //---------------------------------------------------------------------------
  213. HRESULT RemoveTempFiles(LPCWSTR szRcName, LPCWSTR szResName)
  214. {
  215. DeleteFile(szRcName);
  216. DeleteFile(szResName);
  217. //---- find & delete all temp files in temp directory ----
  218. HANDLE hFile = NULL;
  219. BOOL bFile = TRUE;
  220. WIN32_FIND_DATA wfd;
  221. WCHAR szPattern[_MAX_PATH+1];
  222. WCHAR szTempName[_MAX_PATH+1];
  223. wsprintf(szPattern, L"%s\\%s*.*", g_szTempPath, TEMP_FILENAME_BASE);
  224. for( hFile = FindFirstFile( szPattern, &wfd ); hFile != INVALID_HANDLE_VALUE && bFile;
  225. bFile = FindNextFile( hFile, &wfd ) )
  226. {
  227. wsprintf(szTempName, L"%s\\%s", g_szTempPath, wfd.cFileName);
  228. DeleteFile(szTempName);
  229. }
  230. if (hFile)
  231. {
  232. FindClose( hFile );
  233. }
  234. // Remove files generated by the substitution tables
  235. for (int i = 0; i < SubstNames.GetSize(); i++)
  236. {
  237. wsprintf(szTempName, L"%s\\$%s.ini", g_szTempPath, SubstNames[i].sName);
  238. DeleteFile(szTempName);
  239. }
  240. return S_OK;
  241. }
  242. //---------------------------------------------------------------------------
  243. int GetSubstTableIndex(LPCWSTR pszTableName)
  244. {
  245. // Search for an existing subst table
  246. for (int i = 0; i < SubstNames.GetSize(); i++)
  247. {
  248. if (0 == AsciiStrCmpI(SubstNames[i].sName, pszTableName))
  249. return i;
  250. }
  251. return -1;
  252. }
  253. //---------------------------------------------------------------------------
  254. HRESULT GetSubstValue(LPCWSTR pszIniFileName, LPCWSTR pszName, LPWSTR pszResult)
  255. {
  256. UINT cTablesCount = SubstNames.GetSize();
  257. if (pszIniFileName && pszIniFileName[0] == kRESFILECHAR)
  258. {
  259. pszIniFileName++;
  260. }
  261. for (UINT i = 0; i < cTablesCount; i++)
  262. {
  263. if (0 == AsciiStrCmpI(SubstNames[i].sName, pszIniFileName))
  264. {
  265. for (UINT j = SubstNames[i].iFirstIndex; j < SubstNames[i].iFirstIndex + SubstNames[i].cItems; j++)
  266. {
  267. if (0 == AsciiStrCmpI(SubstIds[j], pszName))
  268. {
  269. lstrcpy(pszResult, SubstValues[j]);
  270. return S_OK;
  271. }
  272. }
  273. }
  274. }
  275. return MakeError32(E_FAIL); // unknown sizename
  276. }
  277. //---------------------------------------------------------------------------
  278. LPWSTR FindSymbolToken(LPWSTR pSrc, int nLen)
  279. {
  280. LPWSTR p = wcschr(pSrc, INI_MACRO_SYMBOL);
  281. // Skip single #s
  282. while (p != NULL && (p - pSrc < nLen - 1) && *(p + 1) != INI_MACRO_SYMBOL)
  283. {
  284. p = wcschr(p + 1, INI_MACRO_SYMBOL);
  285. }
  286. return p;
  287. }
  288. LPWSTR ReallocTextBuffer(LPWSTR pSrc, UINT *pnLen)
  289. {
  290. *pnLen *= 2; // Double the size each time
  291. LPWSTR pszNew = (LPWSTR) LocalReAlloc(pSrc, *pnLen * sizeof(WCHAR), 0);
  292. if (!pszNew)
  293. {
  294. LocalFree(pSrc);
  295. return NULL;
  296. }
  297. return pszNew;
  298. }
  299. LPWSTR SubstituteSymbols(LPWSTR szTableName, LPWSTR pszText)
  300. {
  301. UINT nLen = wcslen(pszText);
  302. UINT nNewLen = nLen * 2; // Reserve some additional space
  303. UINT iSymbol;
  304. UINT nBlockSize;
  305. LPWSTR pszNew = (LPWSTR) LocalAlloc(0, nNewLen * sizeof(WCHAR));
  306. LPWSTR pSrc = FindSymbolToken(pszText, nLen);
  307. LPWSTR pOldSrc = pszText;
  308. LPWSTR pDest = pszNew;
  309. WCHAR szSymbol[MAX_INPUT_LINE+1];
  310. HRESULT hr;
  311. if (!pszNew)
  312. return NULL;
  313. while (pSrc != NULL)
  314. {
  315. nBlockSize = UINT(pSrc - pOldSrc);
  316. // Check for enough space after substitution
  317. if (pDest + nBlockSize >= pszNew + nNewLen &&
  318. NULL == (pszNew = ReallocTextBuffer(pszNew, &nNewLen)))
  319. {
  320. return NULL;
  321. }
  322. // Copy from the last # to the new one
  323. wcsncpy(pDest, pOldSrc, nBlockSize);
  324. pDest += nBlockSize;
  325. pSrc += 2; // Skip the ##
  326. // Copy the symbol name
  327. iSymbol = 0;
  328. while (IsCharAlphaNumericW(*pSrc) || (*pSrc == '_') || (*pSrc == '-'))
  329. {
  330. szSymbol[iSymbol++] = *pSrc++;
  331. }
  332. szSymbol[iSymbol] = 0;
  333. // Get the symbol value
  334. hr = GetSubstValue(szTableName, szSymbol, szSymbol);
  335. if (FAILED(hr))
  336. {
  337. // There's a problem, abort and return the buffer untouched
  338. LocalFree(pszNew);
  339. WCHAR szErrorText[MAX_INPUT_LINE + 1];
  340. wsprintf(szErrorText, L"Substitution symbol not found: %s", szSymbol);
  341. ReportError(hr, szErrorText);
  342. return NULL;
  343. }
  344. // Make sure we have enough room for one symbol
  345. if (pDest + MAX_INPUT_LINE + 1 >= pszNew + nNewLen &&
  346. NULL == (pszNew = ReallocTextBuffer(pszNew, &nNewLen)))
  347. {
  348. return NULL;
  349. }
  350. // Copy the symbol value to the new text
  351. iSymbol = 0;
  352. while (szSymbol[iSymbol] != 0)
  353. {
  354. *pDest++ = szSymbol[iSymbol++];
  355. }
  356. // Advance to the next iteration
  357. pOldSrc = pSrc;
  358. pSrc = FindSymbolToken(pSrc, nLen - UINT(pSrc - pszText));
  359. }
  360. if (pDest == pszNew)
  361. {
  362. // We did nothing, return NULL
  363. LocalFree(pszNew);
  364. return NULL;
  365. }
  366. // Copy the remainder text (after the last #)
  367. if (pDest + wcslen(pOldSrc) >= pszNew + nNewLen &&
  368. NULL == (pszNew = ReallocTextBuffer(pszNew, &nNewLen)))
  369. {
  370. return NULL;
  371. }
  372. wcscpy(pDest, pOldSrc);
  373. return pszNew;
  374. }
  375. //---------------------------------------------------------------------------
  376. HRESULT OutputResourceLine(LPCWSTR pszFilename, FILE *outfile, PACKFILETYPE ePackFileType)
  377. {
  378. HRESULT hr;
  379. //---- did we already process this filename? ----
  380. UINT cNames = FileInfo.GetSize();
  381. for (UINT c=0; c < cNames; c++)
  382. {
  383. if (lstrcmpi(FileInfo[c].wsName, pszFilename)==0)
  384. return S_OK;
  385. }
  386. WCHAR szTempName[_MAX_PATH+1];
  387. WCHAR szResName[_MAX_PATH];
  388. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
  389. WCHAR *filetype;
  390. LPWSTR pszText;
  391. BOOL fWasAnsi;
  392. BOOL fFileChecked = FALSE;
  393. WCHAR szOrigName[_MAX_PATH];
  394. lstrcpy(szOrigName, pszFilename);
  395. _wsplitpath(pszFilename, szDrive, szDir, szBaseName, szExt);
  396. if (ePackFileType == PACK_INIFILE)
  397. {
  398. //---- translate to UNICODE, if needed ----
  399. hr = AllocateTextFile(pszFilename, &pszText, &fWasAnsi);
  400. if (FAILED(hr))
  401. return hr;
  402. if (szBaseName[0] == kRESFILECHAR)
  403. {
  404. wcscpy(szBaseName, szBaseName + 1);
  405. }
  406. // If this an INI file with a subst table, process the substitution
  407. for (int i = 0; i < SubstNames.GetSize(); i++)
  408. {
  409. if (0 == AsciiStrCmpI(SubstNames[i].sName, szBaseName))
  410. {
  411. SetLastError(0);
  412. LPWSTR pszNewText = SubstituteSymbols(szBaseName, pszText);
  413. if (pszNewText != NULL)
  414. {
  415. LPWSTR pszTemp = pszText;
  416. pszText = pszNewText;
  417. LocalFree(pszTemp);
  418. }
  419. hr = GetLastError();
  420. if (SUCCEEDED(hr))
  421. {
  422. HRESULT hr = TextToFile(pszFilename, pszText); // Local hr, ignore failure later
  423. if (SUCCEEDED(hr))
  424. {
  425. fWasAnsi = FALSE; // We don't need another temp file
  426. }
  427. }
  428. break;
  429. }
  430. }
  431. if (SUCCEEDED(hr) && fWasAnsi) // write out as temp file
  432. {
  433. DWORD len = lstrlen(g_szTempPath);
  434. if ((len) && (g_szTempPath[len-1] == '\\'))
  435. wsprintf(szTempName, L"%s%s%d%s", g_szTempPath, TEMP_FILENAME_BASE, iTempBitmapNum++, L".uni");
  436. else
  437. wsprintf(szTempName, L"%s\\%s%d%s", g_szTempPath, TEMP_FILENAME_BASE, iTempBitmapNum++, L".uni");
  438. hr = TextToFile(szTempName, pszText);
  439. pszFilename = szTempName; // use this name in .rc file
  440. }
  441. LocalFree(pszText);
  442. if (FAILED(hr))
  443. return hr;
  444. fFileChecked = TRUE;
  445. }
  446. if (! fFileChecked)
  447. {
  448. //---- ensure the file is accessible ----
  449. if (_waccess(pszFilename, 0) != 0)
  450. {
  451. fwprintf(ConsoleFile, L"Error - cannot access file: %s\n", pszFilename);
  452. return MakeError32(E_FAIL); // cannot access (open) file
  453. }
  454. }
  455. bool bUseClassName = false;
  456. if (ePackFileType == PACK_IMAGEFILE)
  457. {
  458. filetype = L"BITMAP";
  459. bUseClassName = true;
  460. }
  461. else if (ePackFileType == PACK_NTLFILE)
  462. {
  463. filetype = L"NTL";
  464. }
  465. else if (AsciiStrCmpI(szExt, L".ini")==0)
  466. {
  467. filetype = L"TEXTFILE";
  468. }
  469. else if (AsciiStrCmpI(szExt, L".wav")==0)
  470. {
  471. filetype = L"WAVE";
  472. bUseClassName = true;
  473. }
  474. else
  475. {
  476. filetype = L"CUSTOM";
  477. bUseClassName = true;
  478. }
  479. MakeResName(szOrigName, szResName, bUseClassName);
  480. //---- replace all single backslashes with double ones ----
  481. WCHAR DblName[_MAX_PATH+1];
  482. WCHAR *d = DblName;
  483. LPCWSTR p = pszFilename;
  484. while (*p)
  485. {
  486. if (*p == '\\')
  487. *d++ = '\\';
  488. *d++ = *p++;
  489. }
  490. *d = 0;
  491. //---- output the line to the .rc file ----
  492. fwprintf(outfile, L"%-30s \t %s DISCARDABLE \"%s\"\n", szResName, filetype, DblName);
  493. FILEINFO fileinfo;
  494. fileinfo.wsName = pszFilename;
  495. fileinfo.fIniFile = (ePackFileType == PACK_INIFILE);
  496. FileInfo.Add(fileinfo);
  497. g_LineCount++;
  498. return S_OK;
  499. }
  500. //---------------------------------------------------------------------------
  501. void ClearCombos()
  502. {
  503. for (int s=0; s < MAX_SIZES; s++)
  504. {
  505. for (int c=0; c < MAX_COLORS; c++)
  506. {
  507. Combos[s][c] = -1; // -1 means no file supports this combo
  508. }
  509. }
  510. g_iMaxColor = -1;
  511. g_iMaxSize = -1;
  512. }
  513. //---------------------------------------------------------------------------
  514. HRESULT OutputCombos(FILE *outfile)
  515. {
  516. if ((g_iMaxColor < 0) || (g_iMaxSize < 0)) // no combos found
  517. return ReportError(E_FAIL, L"No size/color combinations found");
  518. fwprintf(outfile, L"COMBO COMBODATA\n");
  519. fwprintf(outfile, L"BEGIN\n");
  520. fwprintf(outfile, L" %d, %d // cColors, cSizes\n", g_iMaxColor+1, g_iMaxSize+1);
  521. for (int s=0; s <= g_iMaxSize; s++)
  522. {
  523. for (int c=0; c <= g_iMaxColor; c++)
  524. {
  525. fwprintf(outfile, L" %d, ", Combos[s][c]);
  526. }
  527. fwprintf(outfile, L" // size=%d row\n", s);
  528. }
  529. fwprintf(outfile, L"END\n");
  530. OutputDashLine(outfile);
  531. return S_OK;
  532. }
  533. //---------------------------------------------------------------------------
  534. HRESULT GetFileIndex(LPCWSTR pszName, int *piIndex)
  535. {
  536. int cCount = ResFileNames.GetSize();
  537. for (int i=0; i < cCount; i++)
  538. {
  539. if (lstrcmpi(ResFileNames[i], pszName)==0)
  540. {
  541. *piIndex = i;
  542. return S_OK;
  543. }
  544. }
  545. return MakeError32(E_FAIL); // unknown filename
  546. }
  547. //---------------------------------------------------------------------------
  548. HRESULT GetColorIndex(LPCWSTR pszName, int *piIndex)
  549. {
  550. int cCount = ColorSchemes.GetSize();
  551. for (int i=0; i < cCount; i++)
  552. {
  553. if (lstrcmpi(ColorSchemes[i], pszName)==0)
  554. {
  555. *piIndex = i;
  556. return S_OK;
  557. }
  558. }
  559. return MakeError32(E_FAIL); // unknown colorname
  560. }
  561. //---------------------------------------------------------------------------
  562. HRESULT GetSizeIndex(LPCWSTR pszName, int *piIndex)
  563. {
  564. int cCount = SizeNames.GetSize();
  565. for (int i=0; i < cCount; i++)
  566. {
  567. if (lstrcmpi(SizeNames[i], pszName)==0)
  568. {
  569. *piIndex = i;
  570. return S_OK;
  571. }
  572. }
  573. return MakeError32(E_FAIL); // unknown sizename
  574. }
  575. //---------------------------------------------------------------------------
  576. HRESULT ApplyCombos(LPCWSTR pszResFileName, LPCWSTR pszColors, LPCWSTR pszSizes)
  577. {
  578. //---- get index of pszResFileName ----
  579. int iFileNum;
  580. HRESULT hr = GetFileIndex(pszResFileName, &iFileNum);
  581. if (FAILED(hr))
  582. return hr;
  583. //---- parse colors in pszColors ----
  584. CScanner scan(pszColors);
  585. WCHAR szName[_MAX_PATH+1];
  586. int iColors[MAX_COLORS];
  587. int cColors = 0;
  588. while (1)
  589. {
  590. if (! scan.GetId(szName))
  591. return MakeError32(E_FAIL); // bad color list
  592. //---- get index of szName ----
  593. int index;
  594. HRESULT hr = GetColorIndex(szName, &index);
  595. if (FAILED(hr))
  596. return hr;
  597. if (cColors == MAX_COLORS)
  598. return MakeError32(E_FAIL); // too many colors specified
  599. iColors[cColors++] = index;
  600. if (scan.EndOfLine())
  601. break;
  602. if (! scan.GetChar(L','))
  603. return MakeError32(E_FAIL); // names must be comma separated
  604. }
  605. //---- parse sizes in pszSizes ----
  606. scan.AttachLine(pszSizes);
  607. int iSizes[MAX_SIZES];
  608. int cSizes = 0;
  609. while (1)
  610. {
  611. if (! scan.GetId(szName))
  612. return MakeError32(E_FAIL); // bad color list
  613. //---- get index of szName ----
  614. int index;
  615. HRESULT hr = GetSizeIndex(szName, &index);
  616. if (FAILED(hr))
  617. return hr;
  618. if (cSizes == MAX_SIZES)
  619. return MakeError32(E_FAIL); // too many sizes specified
  620. iSizes[cSizes++] = index;
  621. if (scan.EndOfLine())
  622. break;
  623. if (! scan.GetChar(L','))
  624. return MakeError32(E_FAIL); // names must be comma separated
  625. }
  626. //---- now form all combos of specified colors & sizes ----
  627. for (int c=0; c < cColors; c++) // for each color
  628. {
  629. int color = iColors[c];
  630. for (int s=0; s < cSizes; s++) // for each size
  631. {
  632. int size = iSizes[s];
  633. Combos[size][color] = (SHORT)iFileNum;
  634. //---- update our max's ----
  635. if (size > g_iMaxSize)
  636. g_iMaxSize = size;
  637. if (color > g_iMaxColor)
  638. g_iMaxColor = color;
  639. }
  640. }
  641. return S_OK;
  642. }
  643. //---------------------------------------------------------------------------
  644. void WriteProperty(CSimpleArray<CWideString> &csa, LPCWSTR pszSection, LPCWSTR pszPropName,
  645. LPCWSTR pszValue)
  646. {
  647. WCHAR buff[MAX_PATH*2];
  648. wsprintf(buff, L"%s@[%s]%s=%s", g_szBaseIniName, pszSection, pszPropName, pszValue);
  649. csa.Add(CWideString(buff));
  650. }
  651. //---------------------------------------------------------------------------
  652. BOOL FnCallBack(enum THEMECALLBACK tcbType, LPCWSTR pszName, LPCWSTR pszName2,
  653. LPCWSTR pszName3, int iIndex, LPARAM lParam)
  654. {
  655. HRESULT hr = S_OK;
  656. int nDefaultDepth = 15;
  657. switch (tcbType)
  658. {
  659. case TCB_FILENAME:
  660. WCHAR szFullName[_MAX_PATH+1];
  661. hr = AddPathIfNeeded(pszName, g_szInputDir, szFullName, ARRAYSIZE(szFullName));
  662. if (FAILED(hr))
  663. {
  664. SET_LAST_ERROR(hr);
  665. return FALSE;
  666. }
  667. if ((iIndex == TMT_IMAGEFILE) || (iIndex == TMT_GLYPHIMAGEFILE) || (iIndex == TMT_STOCKIMAGEFILE))
  668. hr = OutputResourceLine(szFullName, (FILE *)lParam, PACK_IMAGEFILE);
  669. else if ((iIndex >= TMT_IMAGEFILE1) && (iIndex <= TMT_IMAGEFILE5))
  670. hr = OutputResourceLine(szFullName, (FILE *)lParam, PACK_IMAGEFILE);
  671. #if 0 // not yet implemented
  672. else if (iIndex == TMT_NTLFILE)
  673. hr = OutputResourceLine(szFullName, (FILE *)lParam, PACK_NTLFILE);
  674. #endif
  675. else
  676. hr = MakeError32(E_FAIL); // unexpected type
  677. if (FAILED(hr))
  678. {
  679. SET_LAST_ERROR(hr);
  680. return FALSE;
  681. }
  682. break;
  683. case TCB_FONT:
  684. WriteProperty(PropValuePairs, pszName2, pszName3, pszName);
  685. break;
  686. case TCB_MIRRORIMAGE:
  687. {
  688. LPCWSTR p;
  689. if (lParam)
  690. p = L"1";
  691. else
  692. p = L"0";
  693. WriteProperty(PropValuePairs, pszName2, pszName3, p);
  694. }
  695. break;
  696. case TCB_LOCALIZABLE_RECT:
  697. {
  698. WCHAR szBuff[100];
  699. RECT *prc = (RECT *)lParam;
  700. wsprintf(szBuff, L"%d, %d, %d, %d", prc->left, prc->top, prc->right, prc->bottom);
  701. WriteProperty(PropValuePairs, pszName2, pszName3, szBuff);
  702. }
  703. break;
  704. case TCB_COLORSCHEME:
  705. ColorSchemes.Add(CWideString(pszName));
  706. ColorDisplays.Add(CWideString(pszName2));
  707. ColorToolTips.Add(CWideString(pszName3));
  708. break;
  709. case TCB_SIZENAME:
  710. SizeNames.Add(CWideString(pszName));
  711. SizeDisplays.Add(CWideString(pszName2));
  712. SizeToolTips.Add(CWideString(pszName3));
  713. break;
  714. case TCB_SUBSTTABLE:
  715. {
  716. int iTableIndex = GetSubstTableIndex(pszName);
  717. if (iTableIndex == -1) // Not found, add one
  718. {
  719. sSubstTable s;
  720. s.sName = pszName;
  721. s.iFirstIndex = -1;
  722. s.cItems = 0;
  723. SubstNames.Add(s);
  724. iTableIndex = SubstNames.GetSize() - 1;
  725. }
  726. if (0 == AsciiStrCmpI(pszName2, SUBST_TABLE_INCLUDE))
  727. {
  728. int iSecondTableIndex = GetSubstTableIndex(pszName3);
  729. if (iSecondTableIndex == -1)
  730. {
  731. SET_LAST_ERROR(MakeError32(ERROR_NOT_FOUND));
  732. return FALSE;
  733. }
  734. else
  735. {
  736. // Copy the symbols in the new table
  737. for (UINT iSymbol = SubstNames[iSecondTableIndex].iFirstIndex;
  738. iSymbol < SubstNames[iSecondTableIndex].iFirstIndex + SubstNames[iSecondTableIndex].cItems;
  739. iSymbol++)
  740. {
  741. if (SubstNames[iTableIndex].iFirstIndex == -1)
  742. {
  743. SubstNames[iTableIndex].iFirstIndex = SubstValues.GetSize();
  744. }
  745. SubstNames[iTableIndex].cItems++;
  746. SubstIds.Add(CWideString(SubstIds[iSymbol]));
  747. SubstValues.Add(CWideString(SubstValues[iSymbol]));
  748. }
  749. }
  750. }
  751. else if (pszName2 != NULL && pszName3 != NULL)
  752. {
  753. // If the table was pre-created, update it
  754. if (SubstNames[iTableIndex].iFirstIndex == -1)
  755. {
  756. SubstNames[iTableIndex].iFirstIndex = SubstValues.GetSize();
  757. }
  758. SubstNames[iTableIndex].cItems++;
  759. SubstIds.Add(CWideString(pszName2));
  760. SubstValues.Add(CWideString(pszName3));
  761. }
  762. break;
  763. }
  764. case TCB_NEEDSUBST:
  765. GetSubstValue(pszName, pszName2, (LPWSTR) pszName3);
  766. break;
  767. case TCB_CDFILENAME:
  768. WCHAR szResName[_MAX_PATH+1];
  769. MakeResName(pszName, szResName);
  770. ResFileNames.Add(CWideString(szResName));
  771. MinDepths.Add(nDefaultDepth);
  772. BaseResFileNames.Add(CWideString(pszName));
  773. OrigFileNames.Add(CWideString(pszName2));
  774. break;
  775. case TCB_CDFILECOMBO:
  776. MakeResName(pszName, szResName);
  777. hr = ApplyCombos(szResName, pszName2, pszName3);
  778. if (FAILED(hr))
  779. {
  780. SET_LAST_ERROR(hr);
  781. return FALSE;
  782. }
  783. break;
  784. case TCB_DOCPROPERTY:
  785. if ((iIndex < 0) || (iIndex >= ARRAYSIZE(DocProperties)))
  786. return FALSE;
  787. DocProperties[iIndex] = pszName;
  788. break;
  789. case TCB_MINCOLORDEPTH:
  790. MakeResName(pszName, szResName);
  791. int iRes;
  792. if (SUCCEEDED(GetFileIndex(szResName, &iRes)))
  793. {
  794. MinDepths[iRes] = iIndex;
  795. }
  796. break;
  797. }
  798. SET_LAST_ERROR(hr);
  799. return TRUE;
  800. }
  801. //---------------------------------------------------------------------------
  802. HRESULT OpenOutFile(FILE *&outfile, LPCWSTR pszRcName, LPCWSTR pszBaseName)
  803. {
  804. if (! outfile) // first time thru
  805. {
  806. //---- open out file ----
  807. outfile = _wfopen(pszRcName, L"wt");
  808. if (! outfile)
  809. {
  810. fwprintf(ConsoleFile, L"Error - cannot open file: %s\n", pszRcName);
  811. return MakeError32(E_FAIL);
  812. }
  813. OutputDashLine(outfile);
  814. fwprintf(outfile, L"// %s.rc - used to build the %s theme DLL\n", pszBaseName, pszBaseName);
  815. OutputDashLine(outfile);
  816. }
  817. return S_OK;
  818. }
  819. //---------------------------------------------------------------------------
  820. HRESULT ProcessContainerFile(LPCWSTR pszDir, LPCWSTR pszInputName, FILE *&outfile)
  821. {
  822. HRESULT hr;
  823. //---- output .ini filename as a resource ----
  824. WCHAR fullname[_MAX_PATH+1];
  825. wsprintf(fullname, L"%s\\%s", pszDir, pszInputName);
  826. if (! g_fQuietRun)
  827. fwprintf(ConsoleFile, L"processing container file: %s\n", fullname);
  828. hr = OutputResourceLine(fullname, outfile, PACK_INIFILE);
  829. if (FAILED(hr))
  830. {
  831. ReportError(hr, L"Error reading themes.ini file");
  832. goto exit;
  833. }
  834. OutputDashLine(outfile);
  835. int oldcnt = g_LineCount;
  836. //---- scan the themes.ini files for color, size, & file sections; write 'em to the .rc file ----
  837. DWORD flags = PTF_CONTAINER_PARSE | PTF_CALLBACK_COLORSECTION | PTF_CALLBACK_SIZESECTION
  838. | PTF_CALLBACK_FILESECTION | PTF_CALLBACK_DOCPROPERTIES | PTF_CALLBACK_SUBSTTABLE;
  839. WCHAR szErrMsg[4096];
  840. hr = _ParseThemeIniFile(fullname, flags, FnCallBack, (LPARAM)outfile);
  841. if (FAILED(hr))
  842. {
  843. ReportError(hr, L"Error parsing themes.ini file");
  844. goto exit;
  845. }
  846. if (g_LineCount > oldcnt)
  847. OutputDashLine(outfile);
  848. exit:
  849. return hr;
  850. }
  851. //---------------------------------------------------------------------------
  852. HRESULT ProcessClassDataFile(LPCWSTR pszFileName, FILE *&outfile, LPCWSTR pszResFileName, LPCWSTR pszInputDir)
  853. {
  854. HRESULT hr;
  855. WCHAR szFullName[MAX_PATH];
  856. WCHAR szTempName[MAX_PATH];
  857. LPWSTR pBS = NULL;
  858. hr = hr_lstrcpy(g_szCurrentClass, pszFileName, ARRAYSIZE(g_szCurrentClass)); // make avail to everybody
  859. if (SUCCEEDED(hr))
  860. {
  861. pBS = wcschr(g_szCurrentClass, L'\\');
  862. if (pBS)
  863. {
  864. *pBS = L'_';
  865. *(pBS + 1) = L'\0';
  866. }
  867. }
  868. if (pBS == NULL) // If there's no '\', don't use the class name
  869. {
  870. g_szCurrentClass[0] = 0;
  871. }
  872. hr = hr_lstrcpy(g_szInputDir, pszInputDir, ARRAYSIZE(g_szInputDir)); // make avail to everybody
  873. if (FAILED(hr))
  874. goto exit;
  875. hr = AddPathIfNeeded(pszFileName, pszInputDir, szFullName, ARRAYSIZE(szFullName));
  876. if (FAILED(hr))
  877. goto exit;
  878. //---- extract base ini name ----
  879. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szExt[_MAX_EXT];
  880. _wsplitpath(szFullName, szDrive, szDir, g_szBaseIniName, szExt);
  881. if (! g_fQuietRun)
  882. fwprintf(ConsoleFile, L"processing classdata file: %s\n", pszFileName);
  883. //---- Create a temporary INI file with the substituted values
  884. UINT cTablesCount = SubstNames.GetSize();
  885. for (UINT i = 0; i < cTablesCount; i++)
  886. {
  887. if (0 == AsciiStrCmpI(SubstNames[i].sName, pszResFileName))
  888. {
  889. // Section used in the string table
  890. wcscpy(g_szBaseIniName, SubstNames[i].sName);
  891. // Create the temp file
  892. DWORD len = lstrlen(g_szTempPath);
  893. if ((len) && (g_szTempPath[len-1] == '\\'))
  894. wsprintf(szTempName, L"%s$%s%s", g_szTempPath, pszResFileName, szExt);
  895. else
  896. wsprintf(szTempName, L"%s\\$%s%s", g_szTempPath, pszResFileName, szExt);
  897. if (lstrcmpi(szFullName, szTempName))
  898. {
  899. CopyFile(szFullName, szTempName, FALSE);
  900. SetFileAttributes(szTempName, FILE_ATTRIBUTE_NORMAL);
  901. wcscpy(szFullName, szTempName);
  902. }
  903. break;
  904. }
  905. }
  906. //---- output .ini filename as a resource ----
  907. hr = OutputResourceLine(szFullName, outfile, PACK_INIFILE);
  908. if (FAILED(hr))
  909. goto exit;
  910. OutputDashLine(outfile);
  911. int oldcnt;
  912. oldcnt = g_LineCount;
  913. //---- scan the classdata .ini file for valid filenames & fonts; write 'em to the .rc file ----
  914. WCHAR szErrMsg[4096];
  915. DWORD flags;
  916. flags = PTF_CLASSDATA_PARSE | PTF_CALLBACK_FILENAMES | PTF_CALLBACK_LOCALIZATIONS
  917. | PTF_CALLBACK_MINCOLORDEPTH;
  918. hr = _ParseThemeIniFile(szFullName, flags, FnCallBack, (LPARAM)outfile);
  919. if (FAILED(hr))
  920. {
  921. ReportError(hr, L"Error parsing classdata .ini file");
  922. goto exit;
  923. }
  924. if (g_LineCount > oldcnt)
  925. OutputDashLine(outfile);
  926. hr = S_OK;
  927. exit:
  928. return hr;
  929. }
  930. //---------------------------------------------------------------------------
  931. HRESULT ProcessClassDataFiles(FILE *&outfile, LPCWSTR pszInputDir)
  932. {
  933. int cNames = OrigFileNames.GetSize();
  934. for (int i=0; i < cNames; i++)
  935. {
  936. HRESULT hr = ProcessClassDataFile(OrigFileNames[i], outfile, BaseResFileNames[i], pszInputDir);
  937. if (FAILED(hr))
  938. return hr;
  939. }
  940. return S_OK;
  941. }
  942. //---------------------------------------------------------------------------
  943. HRESULT OutputStringTable(FILE *outfile, CWideString *ppszStrings, UINT cStrings, int iBaseNum,
  944. LPCWSTR pszTitle, BOOL fLocalizable=TRUE, BOOL fMinDepths=FALSE)
  945. {
  946. if (! cStrings)
  947. return S_OK;
  948. if (fLocalizable)
  949. {
  950. fwprintf(outfile, L"STRINGTABLE DISCARDABLE // %s\n", pszTitle);
  951. }
  952. else // custom resource type
  953. {
  954. fwprintf(outfile, L"1 %s DISCARDABLE\n", pszTitle);
  955. }
  956. fwprintf(outfile, L"BEGIN\n");
  957. for (UINT c=0; c < cStrings; c++)
  958. {
  959. LPCWSTR p = ppszStrings[c];
  960. if (! p)
  961. p = L"";
  962. if (fLocalizable)
  963. fwprintf(outfile, L" %d \t\"%s\"\n", iBaseNum, p);
  964. else
  965. {
  966. if (fMinDepths)
  967. {
  968. fwprintf(outfile, L" %d,\n", MinDepths[c]);
  969. }
  970. else
  971. {
  972. fwprintf(outfile, L" L\"%s\\0\",\n", p);
  973. }
  974. if (c == cStrings-1) // last entry
  975. {
  976. if (fMinDepths)
  977. {
  978. fwprintf(outfile, L" 0\n");
  979. }
  980. else
  981. {
  982. fwprintf(outfile, L" L\"\\0\",\n");
  983. }
  984. }
  985. }
  986. iBaseNum++;
  987. }
  988. fwprintf(outfile, L"END\n");
  989. OutputDashLine(outfile);
  990. return S_OK;
  991. }
  992. //---------------------------------------------------------------------------
  993. HRESULT OutputAllStringTables(FILE *outfile)
  994. {
  995. //---- output all non-localizable strings ----
  996. if (ColorSchemes.GetSize())
  997. {
  998. OutputStringTable(outfile, &ColorSchemes[0], ColorSchemes.GetSize(),
  999. 0, L"COLORNAMES", FALSE);
  1000. }
  1001. if (SizeNames.GetSize())
  1002. {
  1003. OutputStringTable(outfile, &SizeNames[0], SizeNames.GetSize(),
  1004. 0, L"SIZENAMES", FALSE);
  1005. }
  1006. if (ResFileNames.GetSize())
  1007. {
  1008. OutputStringTable(outfile, &ResFileNames[0], ResFileNames.GetSize(),
  1009. 0, L"FILERESNAMES", FALSE);
  1010. }
  1011. if (MinDepths.GetSize())
  1012. {
  1013. OutputStringTable(outfile, &ResFileNames[0], ResFileNames.GetSize(),
  1014. 0, L"MINDEPTH", FALSE, TRUE);
  1015. }
  1016. if (OrigFileNames.GetSize())
  1017. {
  1018. OutputStringTable(outfile, &OrigFileNames[0], OrigFileNames.GetSize(),
  1019. 0, L"ORIGFILENAMES", FALSE);
  1020. }
  1021. //---- output all localizable strings ----
  1022. if (ColorDisplays.GetSize())
  1023. {
  1024. OutputStringTable(outfile, &ColorDisplays[0], ColorDisplays.GetSize(),
  1025. RES_BASENUM_COLORDISPLAYS, L"Color Display Names");
  1026. }
  1027. if (ColorToolTips.GetSize())
  1028. {
  1029. OutputStringTable(outfile, &ColorToolTips[0], ColorToolTips.GetSize(),
  1030. RES_BASENUM_COLORTOOLTIPS, L"Color ToolTips");
  1031. }
  1032. if (SizeDisplays.GetSize())
  1033. {
  1034. OutputStringTable(outfile, &SizeDisplays[0], SizeDisplays.GetSize(),
  1035. RES_BASENUM_SIZEDISPLAYS, L"Size Display Names");
  1036. }
  1037. if (SizeToolTips.GetSize())
  1038. {
  1039. OutputStringTable(outfile, &SizeToolTips[0], SizeToolTips.GetSize(),
  1040. RES_BASENUM_SIZETOOLTIPS, L"Size ToolTips");
  1041. }
  1042. OutputStringTable(outfile, &DocProperties[0], ARRAYSIZE(DocProperties),
  1043. RES_BASENUM_DOCPROPERTIES, L"Doc PropValuePairs");
  1044. OutputStringTable(outfile, &PropValuePairs[0], PropValuePairs.GetSize(),
  1045. RES_BASENUM_PROPVALUEPAIRS, L"PropValuePairs");
  1046. return S_OK;
  1047. }
  1048. //---------------------------------------------------------------------------
  1049. BOOL WriteBitmapHeader(CSimpleFile &cfOut, BYTE *pBytes, DWORD dwBytes)
  1050. {
  1051. BOOL fOK = FALSE;
  1052. BYTE pbHdr1[] = {0x42, 0x4d};
  1053. BYTE pbHdr2[] = {0x0, 0x0, 0x0, 0x0};
  1054. int iFileLen;
  1055. //---- add bitmap hdr at front ----
  1056. HRESULT hr = cfOut.Write(pbHdr1, sizeof(pbHdr1));
  1057. if (FAILED(hr))
  1058. {
  1059. ReportError(hr, L"Cannot write to output file");
  1060. goto exit;
  1061. }
  1062. //---- add length of data ----
  1063. iFileLen = dwBytes + sizeof(BITMAPFILEHEADER);
  1064. hr = cfOut.Write(&iFileLen, sizeof(int));
  1065. if (FAILED(hr))
  1066. {
  1067. ReportError(hr, L"Cannot write to output file");
  1068. goto exit;
  1069. }
  1070. hr = cfOut.Write(pbHdr2, sizeof(pbHdr2));
  1071. if (FAILED(hr))
  1072. {
  1073. ReportError(hr, L"Cannot write to output file");
  1074. goto exit;
  1075. }
  1076. //---- offset to bits (who's idea was *this* field?) ----
  1077. int iOffset, iColorTableSize;
  1078. DWORD dwSize;
  1079. iOffset = sizeof(BITMAPFILEHEADER);
  1080. dwSize = *(DWORD *)pBytes;
  1081. iOffset += dwSize;
  1082. iColorTableSize = 0;
  1083. switch (dwSize)
  1084. {
  1085. case sizeof(BITMAPCOREHEADER):
  1086. BITMAPCOREHEADER *hdr1;
  1087. hdr1 = (BITMAPCOREHEADER *)pBytes;
  1088. if (hdr1->bcBitCount == 1)
  1089. iColorTableSize = 2*sizeof(RGBTRIPLE);
  1090. else if (hdr1->bcBitCount == 4)
  1091. iColorTableSize = 16*sizeof(RGBTRIPLE);
  1092. else if (hdr1->bcBitCount == 8)
  1093. iColorTableSize = 256*sizeof(RGBTRIPLE);
  1094. break;
  1095. case sizeof(BITMAPINFOHEADER):
  1096. case sizeof(BITMAPV4HEADER):
  1097. case sizeof(BITMAPV5HEADER):
  1098. BITMAPINFOHEADER *hdr2;
  1099. hdr2 = (BITMAPINFOHEADER *)pBytes;
  1100. if (hdr2->biClrUsed)
  1101. iColorTableSize = hdr2->biClrUsed*sizeof(RGBQUAD);
  1102. else
  1103. {
  1104. if (hdr2->biBitCount == 1)
  1105. iColorTableSize = 2*sizeof(RGBQUAD);
  1106. else if (hdr2->biBitCount == 4)
  1107. iColorTableSize = 16*sizeof(RGBQUAD);
  1108. else if (hdr2->biBitCount == 8)
  1109. iColorTableSize = 256*sizeof(RGBQUAD);
  1110. }
  1111. break;
  1112. }
  1113. iOffset += iColorTableSize;
  1114. hr = cfOut.Write(&iOffset, sizeof(int));
  1115. if (FAILED(hr))
  1116. {
  1117. ReportError(hr, L"Cannot write to output file");
  1118. goto exit;
  1119. }
  1120. fOK = TRUE;
  1121. exit:
  1122. return fOK;
  1123. }
  1124. //---------------------------------------------------------------------------
  1125. BOOL CALLBACK ResEnumerator(HMODULE hModule, LPCWSTR pszType, LPWSTR pszResName, LONG_PTR lParam)
  1126. {
  1127. HRESULT hr;
  1128. BOOL fAnsi = (BOOL)lParam;
  1129. BOOL fText = FALSE;
  1130. RESOURCE BYTE *pBytes = NULL;
  1131. CSimpleFile cfOut;
  1132. DWORD dwBytes;
  1133. if (pszType != RT_BITMAP)
  1134. fText = TRUE;
  1135. hr = GetPtrToResource(hModule, pszType, pszResName, (void **)&pBytes, &dwBytes);
  1136. if (FAILED(hr))
  1137. {
  1138. ReportError(hr, L"error reading file resources");
  1139. goto exit;
  1140. }
  1141. //---- convert name to filename ----
  1142. WCHAR szFileName[_MAX_PATH+1];
  1143. lstrcpy(szFileName, pszResName);
  1144. WCHAR *q;
  1145. q = wcsrchr(szFileName, '_');
  1146. if (q)
  1147. *q = '.';
  1148. if (! fText)
  1149. fAnsi = FALSE; // don't translate if binary data
  1150. hr = cfOut.Create(szFileName, fAnsi);
  1151. if (FAILED(hr))
  1152. {
  1153. ReportError(hr, L"Cannot create output file");
  1154. goto exit;
  1155. }
  1156. if (! fText)
  1157. {
  1158. if (! WriteBitmapHeader(cfOut, pBytes, dwBytes))
  1159. goto exit;
  1160. }
  1161. hr = cfOut.Write(pBytes, dwBytes);
  1162. if (FAILED(hr))
  1163. {
  1164. ReportError(hr, L"Cannot write to output file");
  1165. goto exit;
  1166. }
  1167. exit:
  1168. return (SUCCEEDED(hr));
  1169. }
  1170. //---------------------------------------------------------------------------
  1171. void WriteBitmap(LPWSTR pszFileName, BITMAPINFOHEADER* pbmi, DWORD* pdwData)
  1172. {
  1173. DWORD dwLen = pbmi->biWidth * pbmi->biHeight;
  1174. CSimpleFile cfOut;
  1175. cfOut.Create(pszFileName, FALSE);
  1176. BITMAPFILEHEADER bmfh = {0};
  1177. bmfh.bfType = 'MB';
  1178. bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (dwLen * sizeof(DWORD));
  1179. bmfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
  1180. cfOut.Write(&bmfh, sizeof(BITMAPFILEHEADER));
  1181. cfOut.Write(pbmi, sizeof(BITMAPINFOHEADER));
  1182. cfOut.Write(pdwData, dwLen * sizeof(DWORD));
  1183. }
  1184. HRESULT ColorShift(LPWSTR pszFileName, int cchFileName)
  1185. {
  1186. HDC hdc = GetDC(NULL);
  1187. if (hdc)
  1188. {
  1189. HBITMAP hbm = (HBITMAP)LoadImage(0, pszFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
  1190. if (hbm)
  1191. {
  1192. BITMAP bm;
  1193. GetObject(hbm, sizeof(bm), &bm);
  1194. DWORD dwLen = bm.bmWidth * bm.bmHeight;
  1195. DWORD* pPixelQuads = new DWORD[dwLen];
  1196. if (pPixelQuads)
  1197. {
  1198. BITMAPINFO bi = {0};
  1199. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1200. bi.bmiHeader.biWidth = bm.bmWidth;
  1201. bi.bmiHeader.biHeight = bm.bmHeight;
  1202. bi.bmiHeader.biPlanes = 1;
  1203. bi.bmiHeader.biBitCount = 32;
  1204. bi.bmiHeader.biCompression = BI_RGB;
  1205. if (GetDIBits(hdc, hbm, 0, bm.bmHeight, pPixelQuads, &bi, DIB_RGB_COLORS))
  1206. {
  1207. pszFileName[lstrlen(pszFileName) - 4] = 0;
  1208. WCHAR szFileNameR[MAX_PATH];
  1209. wsprintf(szFileNameR, L"%sR.bmp", pszFileName);
  1210. WCHAR szFileNameG[MAX_PATH];
  1211. wsprintf(szFileNameG, L"%sG.bmp", pszFileName);
  1212. WCHAR szFileNameB[MAX_PATH];
  1213. wsprintf(szFileNameB, L"%sB.bmp", pszFileName);
  1214. WriteBitmap(szFileNameB, &bi.bmiHeader, pPixelQuads);
  1215. DWORD *pdw = pPixelQuads;
  1216. for (DWORD i = 0; i < dwLen; i++)
  1217. {
  1218. COLORREF crTemp = *pdw;
  1219. if (crTemp != RGB(255, 0, 255))
  1220. {
  1221. crTemp = (crTemp & 0xff000000) | RGB(GetGValue(crTemp), GetBValue(crTemp), GetRValue(crTemp));
  1222. }
  1223. *pdw = crTemp;
  1224. pdw++;
  1225. }
  1226. WriteBitmap(szFileNameR, &bi.bmiHeader, pPixelQuads);
  1227. pdw = pPixelQuads;
  1228. for (DWORD i = 0; i < dwLen; i++)
  1229. {
  1230. COLORREF crTemp = *pdw;
  1231. if (crTemp != RGB(255, 0, 255))
  1232. {
  1233. crTemp = (crTemp & 0xff000000) | RGB(GetGValue(crTemp), GetBValue(crTemp), GetRValue(crTemp));
  1234. }
  1235. *pdw = crTemp;
  1236. pdw++;
  1237. }
  1238. WriteBitmap(szFileNameG, &bi.bmiHeader, pPixelQuads);
  1239. }
  1240. delete[] pPixelQuads;
  1241. }
  1242. DeleteObject(hbm);
  1243. }
  1244. ReleaseDC(NULL, hdc);
  1245. }
  1246. return S_OK;
  1247. }
  1248. //---------------------------------------------------------------------------
  1249. HRESULT UnpackTheme(LPCWSTR pszFileName, BOOL fAnsi)
  1250. {
  1251. HRESULT hr = S_OK;
  1252. //---- load the file as a resource only DLL ----
  1253. RESOURCE HINSTANCE hInst = LoadLibraryEx(pszFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1254. if (hInst)
  1255. {
  1256. //---- enum all bitmaps & write as files ----
  1257. if (! EnumResourceNames(hInst, RT_BITMAP, ResEnumerator, LPARAM(fAnsi)))
  1258. hr = GetLastError();
  1259. //---- enum all .ini files & write as files ----
  1260. if (! EnumResourceNames(hInst, L"TEXTFILE", ResEnumerator, LPARAM(fAnsi)))
  1261. hr = GetLastError();
  1262. //---- close the file ----
  1263. if (hInst)
  1264. FreeLibrary(hInst);
  1265. }
  1266. return hr;
  1267. }
  1268. //---------------------------------------------------------------------------
  1269. HRESULT PackTheme(LPCWSTR pszInputDir, LPWSTR pszOutputName, DWORD cchSize)
  1270. {
  1271. //---- is it a valid dir ----
  1272. DWORD dwMask = GetFileAttributes(pszInputDir);
  1273. if ((dwMask == 0xffffffff) || (! (dwMask & FILE_ATTRIBUTE_DIRECTORY)))
  1274. {
  1275. fwprintf(ConsoleFile, L"\nError - not a valid directory name: %s\n", pszInputDir);
  1276. return MakeError32(E_FAIL);
  1277. }
  1278. //---- build: szDllName ----
  1279. WCHAR szDllName[_MAX_PATH+1];
  1280. BOOL fOutputDir = FALSE;
  1281. if (! *pszOutputName) // not specified - build from pszInputDir
  1282. {
  1283. WCHAR szFullDir[_MAX_PATH+1];
  1284. WCHAR *pszBaseName;
  1285. DWORD val = GetFullPathName(pszInputDir, ARRAYSIZE(szFullDir), szFullDir, &pszBaseName);
  1286. if (! val)
  1287. return MakeErrorLast();
  1288. //---- make output dir same as input dir ----
  1289. wsprintf(szDllName, L"%s\\%s%s", pszInputDir, pszBaseName, THEMEDLL_EXT);
  1290. }
  1291. else // get full name of output file
  1292. {
  1293. DWORD val = GetFullPathName(pszOutputName, ARRAYSIZE(szDllName), szDllName, NULL);
  1294. if (! val)
  1295. return MakeErrorLast();
  1296. fOutputDir = TRUE; // don't remove temp files
  1297. }
  1298. // Give the caller the path so the file can be signed.
  1299. lstrcpyn(pszOutputName, szDllName, cchSize);
  1300. //--- delete the old target in case we have errors ----
  1301. DeleteFile(pszOutputName);
  1302. //---- build: g_szTempPath, szDllRoot, szRcName, and szResName ----
  1303. WCHAR szDllRoot[_MAX_PATH+1];
  1304. WCHAR szResName[_MAX_PATH+1];
  1305. WCHAR szRcName[_MAX_PATH+1];
  1306. WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
  1307. _wsplitpath(szDllName, szDrive, szDir, szBaseName, szExt);
  1308. _wmakepath(szDllRoot, L"", L"", szBaseName, szExt);
  1309. _wmakepath(szRcName, szDrive, szDir, szBaseName, L".rc");
  1310. _wmakepath(szResName, szDrive, szDir, szBaseName, L".res");
  1311. if (fOutputDir)
  1312. _wmakepath(g_szTempPath, szDrive, szDir, L"", L"");
  1313. else
  1314. lstrcpy(g_szTempPath, L".");
  1315. FILE *outfile = NULL;
  1316. OpenOutFile(outfile, szRcName, szBaseName);
  1317. ClearCombos();
  1318. //---- process the main container file ----
  1319. HRESULT hr = ProcessContainerFile(pszInputDir, CONTAINER_NAME, outfile);
  1320. if (FAILED(hr))
  1321. goto exit;
  1322. //---- process all classdata files that were defined in container file ----
  1323. hr = ProcessClassDataFiles(outfile, pszInputDir);
  1324. if (FAILED(hr))
  1325. goto exit;
  1326. //---- output all string tables ----
  1327. hr = OutputAllStringTables(outfile);
  1328. if (FAILED(hr))
  1329. goto exit;
  1330. hr = OutputCombos(outfile);
  1331. if (FAILED(hr))
  1332. goto exit;
  1333. hr = OutputVersionInfo(outfile, szDllRoot, szBaseName);
  1334. if (FAILED(hr))
  1335. goto exit;
  1336. fclose(outfile);
  1337. outfile = NULL;
  1338. hr = BuildThemeDll(szRcName, szResName, szDllName);
  1339. exit:
  1340. if (outfile)
  1341. fclose(outfile);
  1342. if (ConsoleFile != stdout)
  1343. fclose(ConsoleFile);
  1344. if (! g_fKeepTempFiles)
  1345. RemoveTempFiles(szRcName, szResName);
  1346. if (SUCCEEDED(hr))
  1347. {
  1348. if (! g_fQuietRun)
  1349. fwprintf(ConsoleFile, L"Created %s\n", szDllName);
  1350. return S_OK;
  1351. }
  1352. if (! g_fQuietRun)
  1353. fwprintf(ConsoleFile, L"Error occured - theme DLL not created\n");
  1354. return hr;
  1355. }
  1356. //---------------------------------------------------------------------------
  1357. void PrintUsage()
  1358. {
  1359. fwprintf(ConsoleFile, L"\nUsage: \n\n");
  1360. fwprintf(ConsoleFile, L" packthem [-o <output name> ] [-k] [-q] <dirname>\n");
  1361. fwprintf(ConsoleFile, L" -m specifies the (full path) name of the image file you want to color shift\n");
  1362. fwprintf(ConsoleFile, L" -o specifies the (full path) name of the output file\n");
  1363. fwprintf(ConsoleFile, L" -k specifies that temp. files should be kept (not deleted)\n");
  1364. fwprintf(ConsoleFile, L" -d do not sign the file when building it\n");
  1365. fwprintf(ConsoleFile, L" -q quite mode (don't print header and progress msgs)\n\n");
  1366. fwprintf(ConsoleFile, L" packthem -u [-a] <packed filename> \n");
  1367. fwprintf(ConsoleFile, L" -u unpacks the packed file into its separate files in current dir\n");
  1368. fwprintf(ConsoleFile, L" -a writes .ini files as ANSI (defaults to UNICODE)\n\n");
  1369. fwprintf(ConsoleFile, L" packthem -p [-q] <packed filename> \n");
  1370. fwprintf(ConsoleFile, L" -p Parses the localized packed file and reports errors\n\n");
  1371. fwprintf(ConsoleFile, L" packthem [-c] [-q] <packed filename> \n");
  1372. fwprintf(ConsoleFile, L" -c check the signature of the already created file\n\n");
  1373. fwprintf(ConsoleFile, L" packthem [-s] [-q] <packed filename> \n");
  1374. fwprintf(ConsoleFile, L" -s sign the already created file\n\n");
  1375. fwprintf(ConsoleFile, L" packthem [-g] [-q] <packed filename> \n");
  1376. fwprintf(ConsoleFile, L" -g generate public and private keys\n\n");
  1377. }
  1378. //---------------------------------------------------------------------------
  1379. enum eOperation
  1380. {
  1381. opPack = 1,
  1382. opUnPack,
  1383. opSign,
  1384. opCheckSignature,
  1385. opGenerateKeys,
  1386. opParse,
  1387. opColorShift
  1388. };
  1389. //---------------------------------------------------------------------------
  1390. extern "C" WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE previnst,
  1391. LPTSTR pszCmdLine, int nShowCmd)
  1392. {
  1393. //---- initialize globals from themeldr.lib ----
  1394. ThemeLibStartUp(FALSE);
  1395. //---- initialize our globals ----
  1396. HRESULT hr = S_OK;
  1397. int nWeek = -1;
  1398. UtilsStartUp();
  1399. LogStartUp();
  1400. WCHAR szOutputName[_MAX_PATH+1] = {0};
  1401. int retval = 1; // error, until prove otherwise
  1402. BOOL fAnsi = FALSE;
  1403. BOOL fSkipSigning = FALSE;
  1404. eOperation Operation = opPack;
  1405. LPCWSTR p = pszCmdLine;
  1406. szOutputName[0] = 0; // Much faster than ={0};
  1407. //---- default to console until something else is specified ----
  1408. if (! ConsoleFile)
  1409. {
  1410. ConsoleFile = stdout;
  1411. }
  1412. while ((*p == '-') || (*p == '/'))
  1413. {
  1414. p++;
  1415. WCHAR sw = *p;
  1416. if (isupper(sw))
  1417. sw = (WCHAR)tolower(sw);
  1418. if (sw == 'e')
  1419. {
  1420. ConsoleFile = _wfopen(L"packthem.err", L"wt");
  1421. g_fQuietRun = TRUE;
  1422. p++;
  1423. }
  1424. else if (sw == 'o')
  1425. {
  1426. WCHAR *q = szOutputName;
  1427. p++; // skip over switch
  1428. while (iswspace(*p))
  1429. p++;
  1430. while ((*p) && (! iswspace(*p)))
  1431. *q++ = *p++;
  1432. *q = 0; // terminate the output name
  1433. }
  1434. else if (sw == 'k')
  1435. {
  1436. g_fKeepTempFiles = TRUE;
  1437. p++;
  1438. }
  1439. else if (sw == 'q')
  1440. {
  1441. g_fQuietRun = TRUE;
  1442. p++;
  1443. }
  1444. else if (sw == 'm')
  1445. {
  1446. Operation = opColorShift;
  1447. WCHAR *q = szOutputName;
  1448. p++; // skip over switch
  1449. while (iswspace(*p))
  1450. p++;
  1451. while ((*p) && (! iswspace(*p)))
  1452. *q++ = *p++;
  1453. *q = 0; // terminate the output name
  1454. }
  1455. else if (sw == 'u')
  1456. {
  1457. Operation = opUnPack;
  1458. p++;
  1459. }
  1460. else if (sw == 'd')
  1461. {
  1462. fSkipSigning = TRUE;
  1463. p++;
  1464. }
  1465. else if (sw == 'c')
  1466. {
  1467. Operation = opCheckSignature;
  1468. p++;
  1469. }
  1470. else if (sw == 'g')
  1471. {
  1472. Operation = opGenerateKeys;
  1473. p++;
  1474. }
  1475. else if (sw == 's')
  1476. {
  1477. Operation = opSign;
  1478. p++;
  1479. }
  1480. else if (sw == 'a')
  1481. {
  1482. fAnsi = TRUE;
  1483. p++;
  1484. }
  1485. else if (sw == 'w')
  1486. {
  1487. fAnsi = TRUE;
  1488. p++;
  1489. LARGE_INTEGER uli;
  1490. WCHAR szWeek[3];
  1491. szWeek[0] = p[0];
  1492. szWeek[1] = p[1];
  1493. szWeek[2] = 0;
  1494. if (StrToInt64ExInternalW(szWeek, 0, &(uli.QuadPart)) &&
  1495. (uli.QuadPart > 0))
  1496. {
  1497. nWeek = (int)uli.LowPart;
  1498. }
  1499. while ((L' ' != p[0]) && (0 != p[0]))
  1500. {
  1501. p++;
  1502. }
  1503. }
  1504. else if (sw == 'p')
  1505. {
  1506. Operation = opParse;
  1507. p++;
  1508. }
  1509. else if (sw == '?')
  1510. {
  1511. PrintUsage();
  1512. retval = 0;
  1513. goto exit;
  1514. }
  1515. else
  1516. {
  1517. fwprintf(ConsoleFile, L"Error - unrecognized switch: %s\n", p);
  1518. goto exit;
  1519. }
  1520. while (iswspace(*p))
  1521. p++;
  1522. }
  1523. LPCWSTR pszInputDir;
  1524. pszInputDir = p;
  1525. if (! g_fQuietRun)
  1526. {
  1527. fwprintf(ConsoleFile, L"Microsoft (R) Theme Packager (Version %d)\n", PACKTHEM_VERSION);
  1528. fwprintf(ConsoleFile, L"Copyright (C) Microsoft Corp 2000. All rights reserved.\n");
  1529. }
  1530. //---- any cmdline arg specified? ----
  1531. if (Operation != opColorShift)
  1532. {
  1533. if ((! pszInputDir) || (! *pszInputDir))
  1534. {
  1535. PrintUsage();
  1536. goto exit;
  1537. }
  1538. }
  1539. switch (Operation)
  1540. {
  1541. case opPack:
  1542. hr = PackTheme(pszInputDir, szOutputName, ARRAYSIZE(szOutputName));
  1543. if (SUCCEEDED(hr) && !fSkipSigning)
  1544. {
  1545. hr = SignTheme(szOutputName, nWeek);
  1546. if (!g_fQuietRun)
  1547. {
  1548. if (SUCCEEDED(hr))
  1549. {
  1550. wprintf(L"Creating the signature succeeded\n");
  1551. }
  1552. else
  1553. {
  1554. wprintf(L"The signature failed to be created. hr=%#08lx\n", hr);
  1555. }
  1556. }
  1557. }
  1558. break;
  1559. case opUnPack:
  1560. hr = UnpackTheme(pszInputDir, fAnsi);
  1561. break;
  1562. case opSign:
  1563. // We don't sign it again if the signature is already valid.
  1564. if (FAILED(CheckThemeFileSignature(pszInputDir)))
  1565. {
  1566. // Needs signing.
  1567. hr = SignTheme(pszInputDir, nWeek);
  1568. if (!g_fQuietRun)
  1569. {
  1570. if (SUCCEEDED(hr))
  1571. {
  1572. wprintf(L"Creating the signature succeeded\n");
  1573. }
  1574. else
  1575. {
  1576. wprintf(L"The signature failed to be created. hr=%#08lx\n", hr);
  1577. }
  1578. }
  1579. }
  1580. else
  1581. {
  1582. if (!g_fQuietRun)
  1583. {
  1584. wprintf(L"The file was already signed and the signature is still valid.");
  1585. }
  1586. }
  1587. break;
  1588. case opCheckSignature:
  1589. hr = CheckThemeFileSignature(pszInputDir);
  1590. if (!g_fQuietRun)
  1591. {
  1592. if (SUCCEEDED(hr))
  1593. {
  1594. wprintf(L"The signature is valid\n");
  1595. }
  1596. else
  1597. {
  1598. wprintf(L"The signature is not valid. hr=%#08lx\n", hr);
  1599. }
  1600. }
  1601. break;
  1602. case opGenerateKeys:
  1603. hr = GenerateKeys(pszInputDir);
  1604. break;
  1605. case opParse:
  1606. hr = ParseTheme(pszInputDir);
  1607. if (FAILED(hr))
  1608. {
  1609. ReportError(hr, L"Error during parsing");
  1610. goto exit;
  1611. } else
  1612. {
  1613. wprintf(L"No errors parsing theme file\n");
  1614. }
  1615. break;
  1616. case opColorShift:
  1617. hr = ColorShift(szOutputName, ARRAYSIZE(szOutputName));
  1618. break;
  1619. default:
  1620. if (FAILED(hr))
  1621. {
  1622. hr = E_FAIL;
  1623. goto exit;
  1624. }
  1625. break;
  1626. };
  1627. retval = 0; // all OK
  1628. exit:
  1629. UtilsShutDown();
  1630. LogShutDown();
  1631. return retval;
  1632. }
  1633. //---------------------------------------------------------------------------
  1634. HRESULT LoadClassDataIni(HINSTANCE hInst, LPCWSTR pszColorName,
  1635. LPCWSTR pszSizeName, LPWSTR pszFoundIniName, DWORD dwMaxIniNameChars, LPWSTR *ppIniData)
  1636. {
  1637. COLORSIZECOMBOS *combos;
  1638. HRESULT hr = FindComboData(hInst, &combos);
  1639. if (FAILED(hr))
  1640. return hr;
  1641. int iSizeIndex = 0;
  1642. int iColorIndex = 0;
  1643. if ((pszColorName) && (* pszColorName))
  1644. {
  1645. hr = GetColorSchemeIndex(hInst, pszColorName, &iColorIndex);
  1646. if (FAILED(hr))
  1647. return hr;
  1648. }
  1649. if ((pszSizeName) && (* pszSizeName))
  1650. {
  1651. hr = GetSizeIndex(hInst, pszSizeName, &iSizeIndex);
  1652. if (FAILED(hr))
  1653. return hr;
  1654. }
  1655. int filenum = COMBOENTRY(combos, iColorIndex, iSizeIndex);
  1656. if (filenum == -1)
  1657. return MakeError32(ERROR_NOT_FOUND);
  1658. //---- locate resname for classdata file "filenum" ----
  1659. hr = GetResString(hInst, L"FILERESNAMES", filenum, pszFoundIniName, dwMaxIniNameChars);
  1660. if (SUCCEEDED(hr))
  1661. {
  1662. hr = AllocateTextResource(hInst, pszFoundIniName, ppIniData);
  1663. }
  1664. return hr;
  1665. }
  1666. //---------------------------------------------------------------------------
  1667. // Parse the theme to detect localization errors
  1668. HRESULT ParseTheme(LPCWSTR pszThemeName)
  1669. {
  1670. // Dummy callback class needed by the parser
  1671. class CParserCallBack: public IParserCallBack
  1672. {
  1673. HRESULT AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName,
  1674. int iPartNum, int iStateNum, int iIndex, int iLen) { return S_OK; };
  1675. HRESULT AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen) { return S_OK; };
  1676. int GetNextDataIndex() { return 0; };
  1677. };
  1678. CParserCallBack *pParserCallBack = NULL;
  1679. CThemeParser *pParser = NULL;
  1680. HRESULT hr;
  1681. HINSTANCE hInst = NULL;
  1682. WCHAR *pDataIni = NULL;
  1683. WCHAR szClassDataName[_MAX_PATH+1];
  1684. //---- load the Color Scheme from "themes.ini" ----
  1685. hr = LoadThemeLibrary(pszThemeName, &hInst);
  1686. if (FAILED(hr))
  1687. goto exit;
  1688. pParser = new CThemeParser(FALSE);
  1689. if (! pParser)
  1690. {
  1691. hr = MakeError32(E_OUTOFMEMORY);
  1692. goto exit;
  1693. }
  1694. pParserCallBack = new CParserCallBack;
  1695. if (!pParserCallBack)
  1696. {
  1697. hr = MakeError32(E_OUTOFMEMORY);
  1698. goto exit;
  1699. }
  1700. THEMENAMEINFO tniColors;
  1701. THEMENAMEINFO tniSizes;
  1702. for (DWORD c = 0; ; c++)
  1703. {
  1704. if (FAILED(_EnumThemeColors(hInst, pszThemeName, NULL, c, &tniColors, FALSE)))
  1705. break;
  1706. for (DWORD s = 0 ; ; s++)
  1707. {
  1708. if (FAILED(_EnumThemeSizes(hInst, pszThemeName, tniColors.szName, s, &tniSizes, FALSE)))
  1709. break;
  1710. //---- load the classdata file resource into memory ----
  1711. hr = LoadClassDataIni(hInst, tniColors.szName, tniSizes.szName, szClassDataName, ARRAYSIZE(szClassDataName), &pDataIni);
  1712. if (FAILED(hr))
  1713. goto exit;
  1714. //---- parse & build binary theme ----
  1715. hr = pParser->ParseThemeBuffer(pDataIni, szClassDataName, NULL, hInst,
  1716. pParserCallBack, FnCallBack, NULL, PTF_CLASSDATA_PARSE);
  1717. if (FAILED(hr))
  1718. goto exit;
  1719. if (pDataIni)
  1720. {
  1721. delete [] pDataIni;
  1722. pDataIni = NULL;
  1723. }
  1724. }
  1725. }
  1726. exit:
  1727. if (hInst)
  1728. FreeLibrary(hInst);
  1729. if (pDataIni)
  1730. delete [] pDataIni;
  1731. if (pParser)
  1732. delete pParser;
  1733. if (pParserCallBack)
  1734. delete pParserCallBack;
  1735. return hr;
  1736. }