// manifestmanlger.cpp : Defines the entry point for the console application. // #include "stdinc.h" #include "atlbase.h" IXMLDOMDocument *g_pCurrentDocument; BOOL g_bIgnoreMalformedXML = FALSE; #define MAX_OPERATIONS (20) extern const string ASM_NAMESPACE_URI ("urn:schemas-microsoft-com:asm.v1"); char MicrosoftCopyrightLogo[] = "Microsoft (R) Side-By-Side Manifest Tool 1.0.0.0\nCopyright (C) Microsoft Corporation 2000-2001. All Rights Reserved.\n\n"; bool g_RazzleBuildTime = false; // // Global flags used in processing // string g_BinplaceLogFile; string g_CdfOutputPath; ATL::CComPtr g_XmlDomClassFactory; bool g_SuppressBanner = false; #define XMLDOMSOURCE_FILE (1) #define XMLDOMSOURCE_STRING (2) #define MAX_ARGUMENTS (500) #define MAX_ARGUMENT_LENGTH (8192) bool InitializeMSXML3() { static HMODULE hMsXml3 = NULL; ATL::CComPtr pFactory; HRESULT hr; typedef HRESULT (__stdcall * PFN_DLL_GET_CLASS_OBJECT)(REFCLSID, REFIID, LPVOID*); PFN_DLL_GET_CLASS_OBJECT pfnGetClassObject = NULL; if (hMsXml3 == NULL) { hMsXml3 = LoadLibraryA("msxml3.dll"); if (hMsXml3 == NULL) { cerr << "Unable to load msxml3, trying msxml2" << endl; hMsXml3 = LoadLibraryA("msxml2.dll"); if (hMsXml3 == NULL) { cerr << "Unable to load msxml2, trying msxml" << endl; hMsXml3 = LoadLibraryA("msxml.dll"); } } } if (hMsXml3 == NULL) { cerr << "Very Bad Things - no msxml exists on this machine?" << endl; return false; } pfnGetClassObject = (PFN_DLL_GET_CLASS_OBJECT)GetProcAddress(hMsXml3, "DllGetClassObject"); if (!pfnGetClassObject) { return false; } hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument30), __uuidof(pFactory), (void**)&pFactory); if (FAILED(hr)) { cerr << "Can't load version 3.0, trying 2.6" << endl; hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument26), __uuidof(pFactory), (void**)&pFactory); if (FAILED(hr)) { cerr << "Can't load version 2.6, trying 1.0" << endl; // from msxml.h, not msxml2.h // hr = pfnGetClassObject(__uuidof(DOMDocument), __uuidof(pFactory), (void**)&pFactory); if (FAILED(hr)) { cerr << "Poked: no XML v1.0" << endl; } } } if (FAILED(hr)) { return false; } g_XmlDomClassFactory = pFactory; return true; } HRESULT ConstructXMLDOMObject( string SourceName, ATL::CComPtr &document ) { HRESULT hr = S_OK; VARIANT_BOOL vb; hr = g_XmlDomClassFactory->CreateInstance(NULL, __uuidof(document), (void**)&document); if (FAILED(hr)) { return hr; } // // If they're willing to deal with bad XML, then so be it. // if (FAILED(hr = document->put_validateOnParse(VARIANT_FALSE))) { stringstream ss; ss << "MSXMLDOM Refuses to be let the wool be pulled over its eyes!"; ReportError(ErrorSpew, ss); } hr = document->put_preserveWhiteSpace(VARIANT_TRUE); hr = document->put_resolveExternals(VARIANT_FALSE); CFileStreamBase *fsbase = new CFileStreamBase; // LEAK out of paranoia ATL::CComPtr istream = fsbase; if (!fsbase->OpenForRead(SourceName)) { stringstream ss; ss << "Failed opening " << SourceName.c_str() << " for read."; ReportError(ErrorFatal, ss); return E_FAIL; } hr = document->load(_variant_t(istream), &vb); if (vb != VARIANT_TRUE) { ATL::CComPtr perror; hr = document->get_parseError(&perror); long ecode, filepos, linenumber, linepos; BSTR reason, src; perror->get_errorCode(&ecode); perror->get_filepos(&filepos); perror->get_line(&linenumber); perror->get_linepos(&linepos); perror->get_reason(&reason); perror->get_srcText(&src); stringstream ss; ss << "Error: " << hex << ecode << dec << " " << (char*)_bstr_t(reason) << " at position " << filepos << ", line " << linenumber << " column " << linepos << endl << " the text was: " << endl << (char*)_bstr_t(src) << endl; ReportError(ErrorFatal, ss); hr = E_FAIL; } fsbase->Close(); return hr; } void dispUsage() { const char HelpMessage[] = "Modes of operation:\n" " -hashupdate Update hashes of member files\n" " -makecdfs Generate CDF files to make catalogs\n" " -verbose Disply piles of debugging information\n" "\n" "Modifiers:\n" " -manifest The name of the manifest to work with\n" "\n" "Normal usage:" " mt.exe -hashupdate -makecdfs -manifest foo.man\n" "\n"; cout << HelpMessage; } BOOL ProcessParameters( const vector ¶ms, bool &bUpdateHashes, bool &bCreateCatalogs, bool &bVerbosity, pair &bCmdLineSingleItem ) { std::vector::const_iterator ci; bUpdateHashes = bCreateCatalogs = bVerbosity = false; for (ci = params.begin(); ci != params.end(); ci++) { if (*ci == wstring(L"-?")) { dispUsage(); exit(1); } bUpdateHashes |= (*ci == wstring(L"-hashupdate")); bCreateCatalogs |= (*ci == wstring(L"-makecdfs")); bVerbosity |= (*ci == wstring(L"-verbose")); if (*ci == wstring(L"-binplacelog")) { g_BinplaceLogFile = SwitchStringRep(*++ci); } else if (*ci == wstring(L"-razzle")) { g_RazzleBuildTime = true; } else if (*ci == wstring(L"-cdfpath")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-cdfpath needs a path name"; ReportError( ErrorFatal, ss ); return FALSE; } g_CdfOutputPath = SwitchStringRep(*++ci); } else if (*ci == wstring(L"-asmsroot")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-asmsroot needs a path name"; ReportError( ErrorFatal, ss ); return FALSE; } g_AsmsBuildRootPath = SwitchStringRep(*++ci); } else if (*ci == wstring(L"-manifest")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-manifest needs a file name"; ReportError( ErrorFatal, ss ); return FALSE; } bCmdLineSingleItem.first = true; CHAR ch[MAX_PATH]; GetCurrentDirectoryA(MAX_PATH, ch); bCmdLineSingleItem.first = true; bCmdLineSingleItem.second.setManifestLocation(string(ch), SwitchStringRep(*++ci)); } else if (*ci == wstring(L"-version")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-version needs a version string"; ReportError( ErrorFatal, ss ); return FALSE; } bCmdLineSingleItem.first = true; bCmdLineSingleItem.second.version = SwitchStringRep(*++ci); } else if (*ci == wstring(L"-language")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-language needs a culture name string"; ReportError( ErrorFatal, ss ); return FALSE; } bCmdLineSingleItem.first = true; bCmdLineSingleItem.second.language = JustifyPath(SwitchStringRep(*++ci)); } else if (*ci == wstring(L"-name")) { std::vector::const_iterator cinext = ci + 1; if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) ) { stringstream ss; ss << "-name needs an assembly name string"; ReportError( ErrorFatal, ss ); return FALSE; } bCmdLineSingleItem.first = true; bCmdLineSingleItem.second.name = SwitchStringRep(*++ci); } } return TRUE; } int __cdecl wmain(int argc, WCHAR* argv[]) { using namespace std; bool bUpdateHashes = true; bool bGenerateCatalogs = true; vector params; HRESULT hr; pair hasInlinedManifest; for (int i = 0; i < argc; i++) { wstring here = argv[i]; if ( here == wstring(L"-nologo")) g_SuppressBanner = true; else params.push_back(here); } if ( !g_SuppressBanner ) { cout << MicrosoftCopyrightLogo; } if (!ProcessParameters(params, bUpdateHashes, bGenerateCatalogs, g_bDisplaySpew, hasInlinedManifest)) return 1; // // Start COM // if (FAILED(hr = ::CoInitialize(NULL))) { stringstream ss; ss << "Unable to start com, error " << hex << hr; ReportError(ErrorFatal, ss); return 1; } if (!InitializeMSXML3()) { return 2; } if (hasInlinedManifest.first) { PostbuildEntries.push_back(hasInlinedManifest.second); goto StartProcessing; } // // Populate the processing list, but only if we're really in a Razzle // environment // if ( g_RazzleBuildTime ) { // string chName = convertWCharToAnsi(argv[1]); ifstream BinplaceLog; BinplaceLog.open(g_BinplaceLogFile.c_str()); if (!BinplaceLog.is_open()) { cerr << "Failed opening '" << g_BinplaceLogFile << "' as the binplace log?" << endl; cerr << "Ensure that the path passed by '-binplacelog' is valid." << endl; return 1; } while (!BinplaceLog.eof()) { string sourceLine; wstring wSourceLine; CPostbuildProcessListEntry item; StringStringMap ValuePairs; getline(BinplaceLog, sourceLine); wSourceLine = SwitchStringRep(sourceLine); ValuePairs = MapFromDefLine(wSourceLine); if (!ValuePairs.size()) continue; item.name = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_NAME"]); item.version = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_VERSION"]); item.language = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_LANGUAGE"]); item.setManifestLocation(g_AsmsBuildRootPath, SwitchStringRep(ValuePairs[L"SXS_MANIFEST"])); if (item.getManifestFullPath().find("asms\\") == -1) { stringstream ss; ss << "Skipping manifested item " << item << " because it's not under asms."; ReportError(ErrorSpew, ss); } else { PostbuildEntries.push_back(item); } } std::sort(PostbuildEntries.begin(), PostbuildEntries.end()); PostbuildEntries.resize(std::unique(PostbuildEntries.begin(), PostbuildEntries.end()) - PostbuildEntries.begin()); } else if ( !hasInlinedManifest.first ) { // // No -razzle and no -manifest? Whoops... // dispUsage(); return 1; } StartProcessing: if ( !bUpdateHashes && !bGenerateCatalogs ) { cout << "Nothing to do!" << endl; dispUsage(); return 1; } for (vector::const_iterator cursor = PostbuildEntries.begin(); cursor != PostbuildEntries.end(); cursor++) { // // First, mash the hashes around. // if (bUpdateHashes) UpdateManifestHashes(*cursor); // // Second, generate catalogs // if (bGenerateCatalogs) GenerateCatalogContents(*cursor); } hr = S_OK; return (hr == S_OK) ? 0 : 1; } CPostbuildItemVector PostbuildEntries;