Leaked source code of windows server 2003
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.

653 lines
22 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: shimdbc.cpp
  4. //
  5. // History: 19-Nov-99 markder Created.
  6. // 1-Feb-00 markder Revised to read/write to ShimDB.
  7. // 1-Apr-00 vadimb Revised to work with apphelp entries
  8. // 13-Dec-00 markder Version 2
  9. // 13-Dec-00 vadimb Version 2.00.10 MSI support
  10. // 03-Dec-01 vadimb Version 2.01.13 Fix Memory patch write routine
  11. // 15-Feb-01 markder/vadimb 2.01.14 Fix Install section format for migdb
  12. // 07-Feb-01 vadimb Version 2.01.15 MSI support (nested DATA)
  13. // 21-Feb-01 vadimb Version 2.01.16 16-bit module name attribute,
  14. // fix 16-bit description
  15. // 06-Mar-01 markder Version 2.02.11 MSI filter support
  16. // 12-Mar-01 vadimb Version 2.03.00 Migration support, part deux
  17. // 28-Mar-01 markder Version 2.04.00 Driver DB support, NtCompat support
  18. // 29-Mar-01 vadimb Version 2.04.11 Driver DB indexing
  19. // 11-Apr-01 dmunsil Version 2.04.12 Driver DB support, NtCompat support
  20. // 12-Apr-01 vadimb Version 2.04.13 MSI shimming support
  21. // 18-Apr-01 vadimb Version 2.04.15 MSI dynamic shim bugfix
  22. // 15-Jan-02 jdoherty Version 2.04.59 Add ID to additional tags.
  23. // 19-Mar-02 kinshu Version 2.04.63 Bug# 529272
  24. // 22-Mar-02 markder Version 2.05.00 Multi-language database support
  25. // 22-Apr-02 rparsons Version 2.05.01 Fix regression in patch write routine
  26. // 07-Apr-02 maonis Version 2.05.02 Adding 2 new OS_SKU tags to recognize
  27. // TabletPC and eHome
  28. // 31-May-02 vadimb Version 2.05.04 Fix msi package indexing
  29. // 22-May-02 vadimb Version 2.05.05 Add OS_SKU to msi package entries
  30. // 25-Jul-02 maonis Version 2.05.06 Fixed a postbuild break in lab02
  31. // 19-Jul-02 maonis Version 2.05.07 Fusion dev forgot to update the
  32. // version when she checked in changelist #27985
  33. // (lab01_fusion).
  34. // 17-Sep-02 maonis Version 2.05.08 One .chm on all platforms
  35. // 15-Jan-03 robkenny Version 2.05.09 Added new OS_SKU SBS.
  36. // 16-Jan-03 maonis Version 2.05.10 Allow attribute PARAMETER1 in APPHELP
  37. // and fixed the bug where AppcompatRedirImport.xml is
  38. // ANSI - should be unicode.
  39. //
  40. // Desc: This file contains the entry point and main functions
  41. // of the Shim database compiler.
  42. //
  43. ////////////////////////////////////////////////////////////////////////////////////
  44. #include "stdafx.h"
  45. #include "resource.h"
  46. #include "typeinfo.h"
  47. #include "registry.h"
  48. #include "ntcompat.h"
  49. #include "chm.h"
  50. #include "mig.h"
  51. #include "make.h"
  52. #include "stats.h"
  53. #ifdef _DEBUG
  54. #define new DEBUG_NEW
  55. #undef THIS_FILE
  56. static char THIS_FILE[] = __FILE__;
  57. #endif
  58. ////////////////////////////////////////////////////////////////////////////////////
  59. // Global variables
  60. ////////////////////////////////////////////////////////////////////////////////////
  61. #ifdef USE_CWIN
  62. CWinApp theApp; // Needed for MFC
  63. #endif // USE_CWIN
  64. BOOL g_bQuiet = FALSE; // Quiet mode
  65. TCHAR g_szVersion[] = _T("v2.05.10"); // Version string
  66. BOOL g_bStrict = FALSE; // Strict checking
  67. CStringArray g_rgErrors; // Error message stack
  68. ////////////////////////////////////////////////////////////////////////////////////
  69. // Forward declarations of functions
  70. ////////////////////////////////////////////////////////////////////////////////////
  71. void PrintHelp();
  72. ////////////////////////////////////////////////////////////////////////////////////
  73. //
  74. // Func: main
  75. //
  76. // Desc: Entry point.
  77. //
  78. extern "C" int __cdecl _tmain(int argc, TCHAR* argv[])
  79. {
  80. int nRetCode = 1;
  81. int i;
  82. DOUBLE flOSVersion = 0.0;
  83. SdbDatabase* pDatabase = new SdbDatabase();
  84. CString csOutputFile;
  85. CString csOutputDir;
  86. CString csInputDir;
  87. CString csTemp;
  88. CString csMigDBFile;
  89. CString csMakefile;
  90. SdbMakefile Makefile;
  91. SdbInputFile* pInputFile = NULL;
  92. SdbInputFile* pRefFile = NULL;
  93. SdbOutputFile* pOutputFile = NULL;
  94. SdbOutputFile* pOtherFile = NULL;
  95. BOOL bCreateHTMLHelpFiles = FALSE;
  96. BOOL bCreateRegistryFiles = FALSE;
  97. BOOL bAddExeStubs = FALSE;
  98. BOOL bCreateMigDBFiles = FALSE;
  99. BOOL bUseNameInAppHelpURL = FALSE;
  100. LONG nPrintStatistics = 0;
  101. //
  102. // Initialize MFC and print and error on failure
  103. //
  104. if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) {
  105. PrintError(_T("Fatal Error: MFC initialization failed\n"));
  106. goto eh;
  107. }
  108. //
  109. // Print banner
  110. //
  111. if (!g_bQuiet) {
  112. Print(_T("\nMicrosoft Application Compatibility Database Compiler %s\n"), g_szVersion);
  113. Print(_T("Copyright (C) Microsoft Corp 2000-2002. All rights reserved.\n\n"));
  114. }
  115. if (argc < 2) {
  116. PrintHelp();
  117. return 0;
  118. }
  119. //
  120. // Initialize COM
  121. //
  122. if (FAILED(CoInitialize(NULL))) {
  123. PrintError(_T("Could not initialize COM to get the MSXML object.\n"));
  124. goto eh;
  125. }
  126. //
  127. // Create default files (populated by command switches)
  128. //
  129. pInputFile = new SdbInputFile();
  130. pRefFile = new SdbInputFile();
  131. pOutputFile = new SdbOutputFile();
  132. //
  133. // Determine compile mode
  134. //
  135. pOutputFile->m_dwFilter = GetFilter(argv[1]);
  136. //
  137. // Parse command line
  138. //
  139. for (i = 2; i < argc; i++) {
  140. if (argv[i][0] == _T('-') || argv[i][0] == _T('/')) {
  141. switch (argv[i][1]) {
  142. case '?':
  143. PrintHelp();
  144. return 0;
  145. case 'a':
  146. case 'A':
  147. if (argv[i][2] == _T('n') ||
  148. argv[i][2] == _T('N')) {
  149. bUseNameInAppHelpURL = TRUE;
  150. }
  151. if (i < argc - 1) {
  152. pRefFile->m_csName = MakeFullPath(argv[++i]);
  153. Makefile.m_rgInputFiles.Add(pRefFile);
  154. } else {
  155. PrintError(_T("Error -- not enough parameters.\n"));
  156. goto eh;
  157. }
  158. break;
  159. case 'f':
  160. case 'F':
  161. if (i < argc - 1) {
  162. csTemp = argv[++i];
  163. } else {
  164. PrintError(_T("Error -- not enough parameters.\n"));
  165. goto eh;
  166. }
  167. if (csTemp.Right(1) != _T("\\")) {
  168. csTemp += _T("\\");
  169. }
  170. pOutputFile->m_mapParameters.SetAt(
  171. _T("INCLUDE FILES"), csTemp );
  172. break;
  173. case 'h':
  174. case 'H':
  175. bCreateHTMLHelpFiles = TRUE;
  176. break;
  177. case 'l':
  178. case 'L':
  179. Makefile.m_csLangID = argv[++i];
  180. Makefile.m_csLangID.MakeUpper();
  181. break;
  182. case 'm':
  183. case 'M':
  184. bCreateMigDBFiles = TRUE;
  185. break;
  186. case 'o':
  187. case 'O':
  188. if (argv[i][2] == _T('v') ||
  189. argv[i][2] == _T('V')) {
  190. Makefile.m_flOSVersion = _tcstod(argv[++i], NULL);
  191. }
  192. if (argv[i][2] == _T('p') ||
  193. argv[i][2] == _T('P')) {
  194. Makefile.m_dwOSPlatform = GetOSPlatform(argv[++i]);
  195. }
  196. break;
  197. case 'q':
  198. case 'Q':
  199. g_bQuiet = TRUE;
  200. break;
  201. case 'r':
  202. case 'R':
  203. bCreateRegistryFiles = TRUE;
  204. if (argv[i][2] == _T('s') ||
  205. argv[i][2] == _T('S')) {
  206. bAddExeStubs = TRUE;
  207. }
  208. break;
  209. case 'k':
  210. case 'K':
  211. if (i < argc - 1) {
  212. Makefile.AddHistoryKeywords(argv[++i]);
  213. } else {
  214. PrintError(_T("Error -- not enough parameters.\n"));
  215. goto eh;
  216. }
  217. break;
  218. case 's':
  219. case 'S':
  220. g_bStrict = TRUE;
  221. break;
  222. case 'v':
  223. case 'V':
  224. nPrintStatistics = 1;
  225. if (argv[i][2] == _T('s') ||
  226. argv[i][2] == _T('S')) {
  227. nPrintStatistics = 2;
  228. }
  229. break;
  230. case 'x':
  231. case 'X':
  232. if (i < argc - 1) {
  233. csMakefile = MakeFullPath(argv[++i]);
  234. if (!Makefile.ReadMakefile(csMakefile)) {
  235. PrintErrorStack();
  236. goto eh;
  237. }
  238. } else {
  239. PrintError(_T("Error -- not enough parameters.\n"));
  240. goto eh;
  241. }
  242. break;
  243. }
  244. } else {
  245. //
  246. // The last entry is the output file.
  247. //
  248. if (pInputFile->m_csName.IsEmpty()) {
  249. pInputFile->m_csName = MakeFullPath(argv[i]);
  250. } else if (pOutputFile->m_csName.IsEmpty()) {
  251. pOutputFile->m_csName = MakeFullPath(argv[i]);
  252. } else {
  253. PrintError(_T("Too many parameters.\n"));
  254. goto eh;
  255. }
  256. }
  257. }
  258. //
  259. // Add default lang map entry
  260. //
  261. SdbLangMap* pNewMap = new SdbLangMap();
  262. pNewMap->m_csName = _T("---");
  263. pNewMap->m_dwCodePage = 1252;
  264. pNewMap->m_lcid = 0x409;
  265. Makefile.m_rgLangMaps.Add(pNewMap);
  266. //
  267. // Determine input/output directory
  268. //
  269. for (i = pInputFile->m_csName.GetLength() - 1; i >= 0; i--) {
  270. if (pInputFile->m_csName.GetAt(i) == _T('\\')) {
  271. csInputDir = pInputFile->m_csName.Left(i + 1);
  272. break;
  273. }
  274. }
  275. for (i = pOutputFile->m_csName.GetLength() - 1; i >= 0; i--) {
  276. if (pOutputFile->m_csName.GetAt(i) == _T('\\')) {
  277. csOutputDir = pOutputFile->m_csName.Left(i + 1);
  278. break;
  279. }
  280. }
  281. //
  282. // Strip .SDB from output file to allow easy extension concatenation
  283. //
  284. csTemp = pOutputFile->m_csName.Right(4);
  285. if (0 == csTemp.CompareNoCase(_T(".sdb"))) {
  286. csOutputFile = pOutputFile->m_csName.Left(
  287. pOutputFile->m_csName.GetLength() - 4);
  288. }
  289. //
  290. // Add additional output files if necessary
  291. //
  292. if (bCreateHTMLHelpFiles) {
  293. pOtherFile = new SdbOutputFile();
  294. Makefile.m_rgOutputFiles.Add(pOtherFile);
  295. pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_HTMLHELP;
  296. pOtherFile->m_csName = csOutputDir + _T("apps.chm");
  297. if (bUseNameInAppHelpURL) {
  298. pOtherFile->m_mapParameters.SetAt(_T("USE NAME IN APPHELP URL"), _T("TRUE"));
  299. }
  300. pOtherFile->m_mapParameters.SetAt(_T("HTMLHELP TEMPLATE"), _T("WindowsXP"));
  301. }
  302. if (bCreateMigDBFiles) {
  303. //
  304. // INX file
  305. //
  306. if (pOutputFile->m_dwFilter == SDB_FILTER_FIX) {
  307. pOtherFile = new SdbOutputFile();
  308. Makefile.m_rgOutputFiles.Add(pOtherFile);
  309. pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_MIGDB_INX;
  310. pOtherFile->m_csName = csOutputDir + _T("MigApp.inx");
  311. }
  312. if (pOutputFile->m_dwFilter == SDB_FILTER_APPHELP) {
  313. //
  314. // TXT file
  315. //
  316. pOtherFile = new SdbOutputFile();
  317. Makefile.m_rgOutputFiles.Add(pOtherFile);
  318. pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_MIGDB_TXT;
  319. pOtherFile->m_csName = csOutputDir + _T("MigApp.txt");
  320. }
  321. }
  322. if (bCreateRegistryFiles) {
  323. pOtherFile = new SdbOutputFile();
  324. Makefile.m_rgOutputFiles.Add(pOtherFile);
  325. pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_WIN2K_REGISTRY;
  326. pOtherFile->m_csName = csOutputFile;
  327. if (bAddExeStubs) {
  328. pOtherFile->m_mapParameters.SetAt(_T("ADD EXE STUBS"), _T("TRUE"));
  329. }
  330. }
  331. //
  332. // If default input/output files weren't used, delete them
  333. //
  334. if (pInputFile->m_csName.IsEmpty()) {
  335. delete pInputFile;
  336. } else {
  337. Makefile.m_rgInputFiles.Add(pInputFile);
  338. }
  339. if (pOutputFile->m_csName.IsEmpty()) {
  340. delete pOutputFile;
  341. } else {
  342. Makefile.m_rgOutputFiles.Add(pOutputFile);
  343. }
  344. pInputFile = NULL;
  345. pOutputFile = NULL;
  346. //
  347. // Check for at least one input and one output file
  348. //
  349. if (Makefile.m_rgInputFiles.GetSize() == 0) {
  350. PrintError(_T("No input file(s) specified.\n"));
  351. goto eh;
  352. }
  353. if (Makefile.m_rgOutputFiles.GetSize() == 0) {
  354. PrintError(_T("No output file(s) specified.\n"));
  355. goto eh;
  356. }
  357. pDatabase->m_pCurrentMakefile = &Makefile;
  358. //
  359. // Ensure that there is a valid LangMap specified
  360. //
  361. if (Makefile.GetLangMap(Makefile.m_csLangID) == NULL) {
  362. PrintError(_T("No LANG_MAP available for \"%s\".\n"), Makefile.m_csLangID);
  363. goto eh;
  364. }
  365. //
  366. // Read input file(s)
  367. //
  368. for (i = 0; i < Makefile.m_rgInputFiles.GetSize(); i++) {
  369. pInputFile = (SdbInputFile *) Makefile.m_rgInputFiles[i];
  370. Print(_T(" Reading XML file - %s"), pInputFile->m_csName);
  371. pDatabase->m_pCurrentInputFile = pInputFile;
  372. if (!ReadDatabase(pInputFile, pDatabase)) {
  373. PrintErrorStack();
  374. goto eh;
  375. }
  376. Print(_T("%s\n"), pInputFile->m_bSourceUpdated ? _T(" - updated") : _T("") );
  377. pDatabase->m_pCurrentInputFile = NULL;
  378. }
  379. Print(_T("\n"));
  380. //
  381. // Propagate filters
  382. //
  383. pDatabase->PropagateFilter(SDB_FILTER_DEFAULT);
  384. //
  385. // Write output file(s)
  386. //
  387. for (i = 0; i < Makefile.m_rgOutputFiles.GetSize(); i++) {
  388. pOutputFile = (SdbOutputFile *) Makefile.m_rgOutputFiles[i];
  389. Print(_T("%27s - %s\n"),
  390. pOutputFile->GetFriendlyNameForType(),
  391. pOutputFile->m_csName);
  392. pDatabase->m_pCurrentOutputFile = pOutputFile;
  393. g_dwCurrentWriteFilter = pOutputFile->m_dwFilter;
  394. g_dtCurrentWriteRevisionCutoff = pOutputFile->m_dtRevisionCutoff;
  395. switch (pOutputFile->m_OutputType) {
  396. case SDB_OUTPUT_TYPE_SDB:
  397. if (!WriteDatabase(pOutputFile, pDatabase)) {
  398. PrintErrorStack();
  399. goto eh;
  400. }
  401. break;
  402. case SDB_OUTPUT_TYPE_HTMLHELP:
  403. if (!ChmWriteProject(pOutputFile,
  404. pDatabase)) {
  405. PrintErrorStack();
  406. goto eh;
  407. }
  408. break;
  409. case SDB_OUTPUT_TYPE_MIGDB_TXT:
  410. if (!WriteMigDBFile(NULL,
  411. pDatabase,
  412. pDatabase,
  413. pOutputFile->m_csName)) {
  414. PrintErrorStack();
  415. goto eh;
  416. }
  417. break;
  418. case SDB_OUTPUT_TYPE_MIGDB_INX:
  419. if (!WriteMigDBFile(pDatabase,
  420. pDatabase,
  421. NULL,
  422. pOutputFile->m_csName)) {
  423. PrintErrorStack();
  424. goto eh;
  425. }
  426. break;
  427. case SDB_OUTPUT_TYPE_WIN2K_REGISTRY:
  428. csTemp.Empty();
  429. pOutputFile->m_mapParameters.Lookup(_T("ADD EXE STUBS"), csTemp);
  430. if (!WriteRegistryFiles(pDatabase,
  431. pOutputFile->m_csName + _T(".reg"),
  432. pOutputFile->m_csName + _T(".inx"),
  433. csTemp == _T("TRUE"))) {
  434. PrintErrorStack();
  435. goto eh;
  436. }
  437. break;
  438. case SDB_OUTPUT_TYPE_REDIR_MAP:
  439. csTemp.Empty();
  440. pOutputFile->m_mapParameters.Lookup(_T("TEMPLATE"), csTemp);
  441. if (csTemp.IsEmpty()) {
  442. PrintError (_T("REDIR_MAP output type requires TEMPLATE parameter\n"));
  443. goto eh;
  444. }
  445. if (!WriteRedirMapFile(pOutputFile->m_csName, csTemp, pDatabase)) {
  446. PrintErrorStack();
  447. goto eh;
  448. }
  449. break;
  450. case SDB_OUTPUT_TYPE_NTCOMPAT_INF:
  451. if (!NtCompatWriteInfAdditions(pOutputFile, pDatabase)) {
  452. PrintErrorStack();
  453. goto eh;
  454. }
  455. break;
  456. case SDB_OUTPUT_TYPE_NTCOMPAT_MESSAGE_INF:
  457. if (!NtCompatWriteMessageInf(pOutputFile, pDatabase)) {
  458. PrintErrorStack();
  459. goto eh;
  460. }
  461. break;
  462. case SDB_OUTPUT_TYPE_APPHELP_REPORT:
  463. if (!WriteAppHelpReport(pOutputFile, pDatabase)) {
  464. PrintErrorStack();
  465. goto eh;
  466. }
  467. break;
  468. }
  469. pDatabase->m_pCurrentOutputFile = NULL;
  470. }
  471. //
  472. // Indicate success and print statistics
  473. //
  474. nRetCode = 0;
  475. Print(_T("\nCompilation successful.\n\n"));
  476. Print(_T(" Executables: %d\n"), pDatabase->m_rgExes.GetSize() +
  477. pDatabase->m_rgWildcardExes.GetSize());
  478. Print(_T(" Shims: %d\n"), pDatabase->m_Library.m_rgShims.GetSize());
  479. Print(_T(" Patches: %d\n"), pDatabase->m_Library.m_rgPatches.GetSize());
  480. Print(_T(" Files: %d\n"), pDatabase->m_Library.m_rgFiles.GetSize());
  481. Print(_T(" Layers: %d\n\n"), pDatabase->m_Library.m_rgLayers.GetSize());
  482. Print(_T(" AppHelp Instances: %d\n"), pDatabase->m_rgAppHelps.GetSize());
  483. Print(_T(" Localized Vendors: %d\n"), pDatabase->m_rgContactInfo.GetSize());
  484. Print(_T(" Templates: %d\n"), pDatabase->m_rgMessageTemplates.GetSize());
  485. Print(_T("\n"));
  486. //
  487. // Print statistics if requested
  488. //
  489. if (nPrintStatistics > 0) {
  490. DumpVerboseStats(pDatabase, nPrintStatistics == 2);
  491. }
  492. eh:
  493. if (pDatabase) {
  494. delete pDatabase;
  495. }
  496. CoUninitialize();
  497. return nRetCode;
  498. }
  499. ////////////////////////////////////////////////////////////////////////////////////
  500. //
  501. // Func: PrintHelp
  502. //
  503. // Desc: Prints the tool's help information.
  504. //
  505. void PrintHelp()
  506. {
  507. Print(_T(" Usage:\n\n"));
  508. Print(_T(" ShimDBC [mode] [command switches] [input file] [output file]\n\n"));
  509. Print(_T(" Modes:\n\n"));
  510. Print(_T(" Fix Compiles a Fix database (e.g., sysmain.sdb).\n\n"));
  511. Print(_T(" AppHelp Compiles an AppHelp database (e.g., apphelp.sdb).\n\n"));
  512. Print(_T(" MSI Compiles an MSI database (e.g., msimain.sdb).\n\n"));
  513. Print(_T(" Driver Compiles a Driver database (e.g., drvmain.sdb).\n\n"));
  514. Print(_T(" Command switches:\n\n"));
  515. Print(_T(" -a <file path> Specifies the reference XML for the AppHelp database\n"));
  516. Print(_T(" This is usually the fix database (AppHelp mode only)\n\n"));
  517. Print(_T(" -h Creates HTMLHelp files in the output file's directory\n"));
  518. Print(_T(" used to create .CHM files. (AppHelp mode only)\n\n"));
  519. Print(_T(" -f <file path> Include FILE binaries in database <file path> is\n"));
  520. Print(_T(" directory to grab binaries from. (Fix mode only)\n\n"));
  521. Print(_T(" -k <keyword> Specifies a <HISTORY> keyword to filter on.\n\n"));
  522. Print(_T(" -m Writes out Migration support files\n\n"));
  523. Print(_T(" -ov <version> Specifies what OS version to compile for.\n\n"));
  524. Print(_T(" -op <platform> Specifies what OS platform to compile for.\n\n"));
  525. Print(_T(" -l <language> Specifies the language to compile for.\n\n"));
  526. Print(_T(" -q Quiet mode.\n\n"));
  527. Print(_T(" -r[s] Creates Win2k-style registry files for use in\n"));
  528. Print(_T(" migration or Win2k update packages. If -rs is used,\n"));
  529. Print(_T(" then shimming stubs are added. (Fix mode only)\n\n"));
  530. Print(_T(" -s Strict compile, additional checking is performed.\n\n"));
  531. Print(_T(" -v[s] Verbose statistics. -vs indicates summary form.\n\n"));
  532. Print(_T(" -x <file path> Use the makefile specified.\n\n"));
  533. }
  534. extern "C" BOOL
  535. ShimdbcExecute(
  536. LPCWSTR lpszCmdLine
  537. )
  538. {
  539. LPWSTR* argv;
  540. int argc = 0;
  541. argv = CommandLineToArgvW(lpszCmdLine, &argc);
  542. return 1 - _tmain(argc, argv);
  543. }