//////////////////////////////////////////////////////////////////////////////////// // // File: shimdbc.cpp // // History: 19-Nov-99 markder Created. // 1-Feb-00 markder Revised to read/write to ShimDB. // 1-Apr-00 vadimb Revised to work with apphelp entries // 13-Dec-00 markder Version 2 // 13-Dec-00 vadimb Version 2.00.10 MSI support // 03-Dec-01 vadimb Version 2.01.13 Fix Memory patch write routine // 15-Feb-01 markder/vadimb 2.01.14 Fix Install section format for migdb // 07-Feb-01 vadimb Version 2.01.15 MSI support (nested DATA) // 21-Feb-01 vadimb Version 2.01.16 16-bit module name attribute, // fix 16-bit description // 06-Mar-01 markder Version 2.02.11 MSI filter support // 12-Mar-01 vadimb Version 2.03.00 Migration support, part deux // 28-Mar-01 markder Version 2.04.00 Driver DB support, NtCompat support // 29-Mar-01 vadimb Version 2.04.11 Driver DB indexing // 11-Apr-01 dmunsil Version 2.04.12 Driver DB support, NtCompat support // 12-Apr-01 vadimb Version 2.04.13 MSI shimming support // 18-Apr-01 vadimb Version 2.04.15 MSI dynamic shim bugfix // 15-Jan-02 jdoherty Version 2.04.59 Add ID to additional tags. // 19-Mar-02 kinshu Version 2.04.63 Bug# 529272 // 22-Mar-02 markder Version 2.05.00 Multi-language database support // 22-Apr-02 rparsons Version 2.05.01 Fix regression in patch write routine // 07-Apr-02 maonis Version 2.05.02 Adding 2 new OS_SKU tags to recognize // TabletPC and eHome // 31-May-02 vadimb Version 2.05.04 Fix msi package indexing // 22-May-02 vadimb Version 2.05.05 Add OS_SKU to msi package entries // 25-Jul-02 maonis Version 2.05.06 Fixed a postbuild break in lab02 // 19-Jul-02 maonis Version 2.05.07 Fusion dev forgot to update the // version when she checked in changelist #27985 // (lab01_fusion). // 17-Sep-02 maonis Version 2.05.08 One .chm on all platforms // 15-Jan-03 robkenny Version 2.05.09 Added new OS_SKU SBS. // 16-Jan-03 maonis Version 2.05.10 Allow attribute PARAMETER1 in APPHELP // and fixed the bug where AppcompatRedirImport.xml is // ANSI - should be unicode. // // Desc: This file contains the entry point and main functions // of the Shim database compiler. // //////////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "resource.h" #include "typeinfo.h" #include "registry.h" #include "ntcompat.h" #include "chm.h" #include "mig.h" #include "make.h" #include "stats.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////////////////////////// // Global variables //////////////////////////////////////////////////////////////////////////////////// #ifdef USE_CWIN CWinApp theApp; // Needed for MFC #endif // USE_CWIN BOOL g_bQuiet = FALSE; // Quiet mode TCHAR g_szVersion[] = _T("v2.05.10"); // Version string BOOL g_bStrict = FALSE; // Strict checking CStringArray g_rgErrors; // Error message stack //////////////////////////////////////////////////////////////////////////////////// // Forward declarations of functions //////////////////////////////////////////////////////////////////////////////////// void PrintHelp(); //////////////////////////////////////////////////////////////////////////////////// // // Func: main // // Desc: Entry point. // extern "C" int __cdecl _tmain(int argc, TCHAR* argv[]) { int nRetCode = 1; int i; DOUBLE flOSVersion = 0.0; SdbDatabase* pDatabase = new SdbDatabase(); CString csOutputFile; CString csOutputDir; CString csInputDir; CString csTemp; CString csMigDBFile; CString csMakefile; SdbMakefile Makefile; SdbInputFile* pInputFile = NULL; SdbInputFile* pRefFile = NULL; SdbOutputFile* pOutputFile = NULL; SdbOutputFile* pOtherFile = NULL; BOOL bCreateHTMLHelpFiles = FALSE; BOOL bCreateRegistryFiles = FALSE; BOOL bAddExeStubs = FALSE; BOOL bCreateMigDBFiles = FALSE; BOOL bUseNameInAppHelpURL = FALSE; LONG nPrintStatistics = 0; // // Initialize MFC and print and error on failure // if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { PrintError(_T("Fatal Error: MFC initialization failed\n")); goto eh; } // // Print banner // if (!g_bQuiet) { Print(_T("\nMicrosoft Application Compatibility Database Compiler %s\n"), g_szVersion); Print(_T("Copyright (C) Microsoft Corp 2000-2002. All rights reserved.\n\n")); } if (argc < 2) { PrintHelp(); return 0; } // // Initialize COM // if (FAILED(CoInitialize(NULL))) { PrintError(_T("Could not initialize COM to get the MSXML object.\n")); goto eh; } // // Create default files (populated by command switches) // pInputFile = new SdbInputFile(); pRefFile = new SdbInputFile(); pOutputFile = new SdbOutputFile(); // // Determine compile mode // pOutputFile->m_dwFilter = GetFilter(argv[1]); // // Parse command line // for (i = 2; i < argc; i++) { if (argv[i][0] == _T('-') || argv[i][0] == _T('/')) { switch (argv[i][1]) { case '?': PrintHelp(); return 0; case 'a': case 'A': if (argv[i][2] == _T('n') || argv[i][2] == _T('N')) { bUseNameInAppHelpURL = TRUE; } if (i < argc - 1) { pRefFile->m_csName = MakeFullPath(argv[++i]); Makefile.m_rgInputFiles.Add(pRefFile); } else { PrintError(_T("Error -- not enough parameters.\n")); goto eh; } break; case 'f': case 'F': if (i < argc - 1) { csTemp = argv[++i]; } else { PrintError(_T("Error -- not enough parameters.\n")); goto eh; } if (csTemp.Right(1) != _T("\\")) { csTemp += _T("\\"); } pOutputFile->m_mapParameters.SetAt( _T("INCLUDE FILES"), csTemp ); break; case 'h': case 'H': bCreateHTMLHelpFiles = TRUE; break; case 'l': case 'L': Makefile.m_csLangID = argv[++i]; Makefile.m_csLangID.MakeUpper(); break; case 'm': case 'M': bCreateMigDBFiles = TRUE; break; case 'o': case 'O': if (argv[i][2] == _T('v') || argv[i][2] == _T('V')) { Makefile.m_flOSVersion = _tcstod(argv[++i], NULL); } if (argv[i][2] == _T('p') || argv[i][2] == _T('P')) { Makefile.m_dwOSPlatform = GetOSPlatform(argv[++i]); } break; case 'q': case 'Q': g_bQuiet = TRUE; break; case 'r': case 'R': bCreateRegistryFiles = TRUE; if (argv[i][2] == _T('s') || argv[i][2] == _T('S')) { bAddExeStubs = TRUE; } break; case 'k': case 'K': if (i < argc - 1) { Makefile.AddHistoryKeywords(argv[++i]); } else { PrintError(_T("Error -- not enough parameters.\n")); goto eh; } break; case 's': case 'S': g_bStrict = TRUE; break; case 'v': case 'V': nPrintStatistics = 1; if (argv[i][2] == _T('s') || argv[i][2] == _T('S')) { nPrintStatistics = 2; } break; case 'x': case 'X': if (i < argc - 1) { csMakefile = MakeFullPath(argv[++i]); if (!Makefile.ReadMakefile(csMakefile)) { PrintErrorStack(); goto eh; } } else { PrintError(_T("Error -- not enough parameters.\n")); goto eh; } break; } } else { // // The last entry is the output file. // if (pInputFile->m_csName.IsEmpty()) { pInputFile->m_csName = MakeFullPath(argv[i]); } else if (pOutputFile->m_csName.IsEmpty()) { pOutputFile->m_csName = MakeFullPath(argv[i]); } else { PrintError(_T("Too many parameters.\n")); goto eh; } } } // // Add default lang map entry // SdbLangMap* pNewMap = new SdbLangMap(); pNewMap->m_csName = _T("---"); pNewMap->m_dwCodePage = 1252; pNewMap->m_lcid = 0x409; Makefile.m_rgLangMaps.Add(pNewMap); // // Determine input/output directory // for (i = pInputFile->m_csName.GetLength() - 1; i >= 0; i--) { if (pInputFile->m_csName.GetAt(i) == _T('\\')) { csInputDir = pInputFile->m_csName.Left(i + 1); break; } } for (i = pOutputFile->m_csName.GetLength() - 1; i >= 0; i--) { if (pOutputFile->m_csName.GetAt(i) == _T('\\')) { csOutputDir = pOutputFile->m_csName.Left(i + 1); break; } } // // Strip .SDB from output file to allow easy extension concatenation // csTemp = pOutputFile->m_csName.Right(4); if (0 == csTemp.CompareNoCase(_T(".sdb"))) { csOutputFile = pOutputFile->m_csName.Left( pOutputFile->m_csName.GetLength() - 4); } // // Add additional output files if necessary // if (bCreateHTMLHelpFiles) { pOtherFile = new SdbOutputFile(); Makefile.m_rgOutputFiles.Add(pOtherFile); pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_HTMLHELP; pOtherFile->m_csName = csOutputDir + _T("apps.chm"); if (bUseNameInAppHelpURL) { pOtherFile->m_mapParameters.SetAt(_T("USE NAME IN APPHELP URL"), _T("TRUE")); } pOtherFile->m_mapParameters.SetAt(_T("HTMLHELP TEMPLATE"), _T("WindowsXP")); } if (bCreateMigDBFiles) { // // INX file // if (pOutputFile->m_dwFilter == SDB_FILTER_FIX) { pOtherFile = new SdbOutputFile(); Makefile.m_rgOutputFiles.Add(pOtherFile); pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_MIGDB_INX; pOtherFile->m_csName = csOutputDir + _T("MigApp.inx"); } if (pOutputFile->m_dwFilter == SDB_FILTER_APPHELP) { // // TXT file // pOtherFile = new SdbOutputFile(); Makefile.m_rgOutputFiles.Add(pOtherFile); pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_MIGDB_TXT; pOtherFile->m_csName = csOutputDir + _T("MigApp.txt"); } } if (bCreateRegistryFiles) { pOtherFile = new SdbOutputFile(); Makefile.m_rgOutputFiles.Add(pOtherFile); pOtherFile->m_OutputType = SDB_OUTPUT_TYPE_WIN2K_REGISTRY; pOtherFile->m_csName = csOutputFile; if (bAddExeStubs) { pOtherFile->m_mapParameters.SetAt(_T("ADD EXE STUBS"), _T("TRUE")); } } // // If default input/output files weren't used, delete them // if (pInputFile->m_csName.IsEmpty()) { delete pInputFile; } else { Makefile.m_rgInputFiles.Add(pInputFile); } if (pOutputFile->m_csName.IsEmpty()) { delete pOutputFile; } else { Makefile.m_rgOutputFiles.Add(pOutputFile); } pInputFile = NULL; pOutputFile = NULL; // // Check for at least one input and one output file // if (Makefile.m_rgInputFiles.GetSize() == 0) { PrintError(_T("No input file(s) specified.\n")); goto eh; } if (Makefile.m_rgOutputFiles.GetSize() == 0) { PrintError(_T("No output file(s) specified.\n")); goto eh; } pDatabase->m_pCurrentMakefile = &Makefile; // // Ensure that there is a valid LangMap specified // if (Makefile.GetLangMap(Makefile.m_csLangID) == NULL) { PrintError(_T("No LANG_MAP available for \"%s\".\n"), Makefile.m_csLangID); goto eh; } // // Read input file(s) // for (i = 0; i < Makefile.m_rgInputFiles.GetSize(); i++) { pInputFile = (SdbInputFile *) Makefile.m_rgInputFiles[i]; Print(_T(" Reading XML file - %s"), pInputFile->m_csName); pDatabase->m_pCurrentInputFile = pInputFile; if (!ReadDatabase(pInputFile, pDatabase)) { PrintErrorStack(); goto eh; } Print(_T("%s\n"), pInputFile->m_bSourceUpdated ? _T(" - updated") : _T("") ); pDatabase->m_pCurrentInputFile = NULL; } Print(_T("\n")); // // Propagate filters // pDatabase->PropagateFilter(SDB_FILTER_DEFAULT); // // Write output file(s) // for (i = 0; i < Makefile.m_rgOutputFiles.GetSize(); i++) { pOutputFile = (SdbOutputFile *) Makefile.m_rgOutputFiles[i]; Print(_T("%27s - %s\n"), pOutputFile->GetFriendlyNameForType(), pOutputFile->m_csName); pDatabase->m_pCurrentOutputFile = pOutputFile; g_dwCurrentWriteFilter = pOutputFile->m_dwFilter; g_dtCurrentWriteRevisionCutoff = pOutputFile->m_dtRevisionCutoff; switch (pOutputFile->m_OutputType) { case SDB_OUTPUT_TYPE_SDB: if (!WriteDatabase(pOutputFile, pDatabase)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_HTMLHELP: if (!ChmWriteProject(pOutputFile, pDatabase)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_MIGDB_TXT: if (!WriteMigDBFile(NULL, pDatabase, pDatabase, pOutputFile->m_csName)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_MIGDB_INX: if (!WriteMigDBFile(pDatabase, pDatabase, NULL, pOutputFile->m_csName)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_WIN2K_REGISTRY: csTemp.Empty(); pOutputFile->m_mapParameters.Lookup(_T("ADD EXE STUBS"), csTemp); if (!WriteRegistryFiles(pDatabase, pOutputFile->m_csName + _T(".reg"), pOutputFile->m_csName + _T(".inx"), csTemp == _T("TRUE"))) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_REDIR_MAP: csTemp.Empty(); pOutputFile->m_mapParameters.Lookup(_T("TEMPLATE"), csTemp); if (csTemp.IsEmpty()) { PrintError (_T("REDIR_MAP output type requires TEMPLATE parameter\n")); goto eh; } if (!WriteRedirMapFile(pOutputFile->m_csName, csTemp, pDatabase)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_NTCOMPAT_INF: if (!NtCompatWriteInfAdditions(pOutputFile, pDatabase)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_NTCOMPAT_MESSAGE_INF: if (!NtCompatWriteMessageInf(pOutputFile, pDatabase)) { PrintErrorStack(); goto eh; } break; case SDB_OUTPUT_TYPE_APPHELP_REPORT: if (!WriteAppHelpReport(pOutputFile, pDatabase)) { PrintErrorStack(); goto eh; } break; } pDatabase->m_pCurrentOutputFile = NULL; } // // Indicate success and print statistics // nRetCode = 0; Print(_T("\nCompilation successful.\n\n")); Print(_T(" Executables: %d\n"), pDatabase->m_rgExes.GetSize() + pDatabase->m_rgWildcardExes.GetSize()); Print(_T(" Shims: %d\n"), pDatabase->m_Library.m_rgShims.GetSize()); Print(_T(" Patches: %d\n"), pDatabase->m_Library.m_rgPatches.GetSize()); Print(_T(" Files: %d\n"), pDatabase->m_Library.m_rgFiles.GetSize()); Print(_T(" Layers: %d\n\n"), pDatabase->m_Library.m_rgLayers.GetSize()); Print(_T(" AppHelp Instances: %d\n"), pDatabase->m_rgAppHelps.GetSize()); Print(_T(" Localized Vendors: %d\n"), pDatabase->m_rgContactInfo.GetSize()); Print(_T(" Templates: %d\n"), pDatabase->m_rgMessageTemplates.GetSize()); Print(_T("\n")); // // Print statistics if requested // if (nPrintStatistics > 0) { DumpVerboseStats(pDatabase, nPrintStatistics == 2); } eh: if (pDatabase) { delete pDatabase; } CoUninitialize(); return nRetCode; } //////////////////////////////////////////////////////////////////////////////////// // // Func: PrintHelp // // Desc: Prints the tool's help information. // void PrintHelp() { Print(_T(" Usage:\n\n")); Print(_T(" ShimDBC [mode] [command switches] [input file] [output file]\n\n")); Print(_T(" Modes:\n\n")); Print(_T(" Fix Compiles a Fix database (e.g., sysmain.sdb).\n\n")); Print(_T(" AppHelp Compiles an AppHelp database (e.g., apphelp.sdb).\n\n")); Print(_T(" MSI Compiles an MSI database (e.g., msimain.sdb).\n\n")); Print(_T(" Driver Compiles a Driver database (e.g., drvmain.sdb).\n\n")); Print(_T(" Command switches:\n\n")); Print(_T(" -a Specifies the reference XML for the AppHelp database\n")); Print(_T(" This is usually the fix database (AppHelp mode only)\n\n")); Print(_T(" -h Creates HTMLHelp files in the output file's directory\n")); Print(_T(" used to create .CHM files. (AppHelp mode only)\n\n")); Print(_T(" -f Include FILE binaries in database is\n")); Print(_T(" directory to grab binaries from. (Fix mode only)\n\n")); Print(_T(" -k Specifies a keyword to filter on.\n\n")); Print(_T(" -m Writes out Migration support files\n\n")); Print(_T(" -ov Specifies what OS version to compile for.\n\n")); Print(_T(" -op Specifies what OS platform to compile for.\n\n")); Print(_T(" -l Specifies the language to compile for.\n\n")); Print(_T(" -q Quiet mode.\n\n")); Print(_T(" -r[s] Creates Win2k-style registry files for use in\n")); Print(_T(" migration or Win2k update packages. If -rs is used,\n")); Print(_T(" then shimming stubs are added. (Fix mode only)\n\n")); Print(_T(" -s Strict compile, additional checking is performed.\n\n")); Print(_T(" -v[s] Verbose statistics. -vs indicates summary form.\n\n")); Print(_T(" -x Use the makefile specified.\n\n")); } extern "C" BOOL ShimdbcExecute( LPCWSTR lpszCmdLine ) { LPWSTR* argv; int argc = 0; argv = CommandLineToArgvW(lpszCmdLine, &argc); return 1 - _tmain(argc, argv); }