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.

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