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.

443 lines
13 KiB

  1. // manifestmanlger.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdinc.h"
  4. #include "atlbase.h"
  5. IXMLDOMDocument *g_pCurrentDocument;
  6. BOOL g_bIgnoreMalformedXML = FALSE;
  7. #define MAX_OPERATIONS (20)
  8. extern const string ASM_NAMESPACE_URI ("urn:schemas-microsoft-com:asm.v1");
  9. char MicrosoftCopyrightLogo[] = "Microsoft (R) Side-By-Side Manifest Tool 1.0.0.0\nCopyright (C) Microsoft Corporation 2000-2001. All Rights Reserved.\n\n";
  10. bool g_RazzleBuildTime = false;
  11. //
  12. // Global flags used in processing
  13. //
  14. string g_BinplaceLogFile;
  15. string g_CdfOutputPath;
  16. ATL::CComPtr<IClassFactory> g_XmlDomClassFactory;
  17. bool g_SuppressBanner = false;
  18. #define XMLDOMSOURCE_FILE (1)
  19. #define XMLDOMSOURCE_STRING (2)
  20. #define MAX_ARGUMENTS (500)
  21. #define MAX_ARGUMENT_LENGTH (8192)
  22. bool
  23. InitializeMSXML3()
  24. {
  25. static HMODULE hMsXml3 = NULL;
  26. ATL::CComPtr<IClassFactory> pFactory;
  27. HRESULT hr;
  28. typedef HRESULT (__stdcall * PFN_DLL_GET_CLASS_OBJECT)(REFCLSID, REFIID, LPVOID*);
  29. PFN_DLL_GET_CLASS_OBJECT pfnGetClassObject = NULL;
  30. if (hMsXml3 == NULL)
  31. {
  32. hMsXml3 = LoadLibraryA("msxml3.dll");
  33. if (hMsXml3 == NULL)
  34. {
  35. cerr << "Unable to load msxml3, trying msxml2" << endl;
  36. hMsXml3 = LoadLibraryA("msxml2.dll");
  37. if (hMsXml3 == NULL)
  38. {
  39. cerr << "Unable to load msxml2, trying msxml" << endl;
  40. hMsXml3 = LoadLibraryA("msxml.dll");
  41. }
  42. }
  43. }
  44. if (hMsXml3 == NULL) {
  45. cerr << "Very Bad Things - no msxml exists on this machine?" << endl;
  46. return false;
  47. }
  48. pfnGetClassObject = (PFN_DLL_GET_CLASS_OBJECT)GetProcAddress(hMsXml3, "DllGetClassObject");
  49. if (!pfnGetClassObject)
  50. {
  51. return false;
  52. }
  53. hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument30), __uuidof(pFactory), (void**)&pFactory);
  54. if (FAILED(hr))
  55. {
  56. cerr << "Can't load version 3.0, trying 2.6" << endl;
  57. hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument26), __uuidof(pFactory), (void**)&pFactory);
  58. if (FAILED(hr))
  59. {
  60. cerr << "Can't load version 2.6, trying 1.0" << endl;
  61. // from msxml.h, not msxml2.h
  62. // hr = pfnGetClassObject(__uuidof(DOMDocument), __uuidof(pFactory), (void**)&pFactory);
  63. if (FAILED(hr))
  64. {
  65. cerr << "Poked: no XML v1.0" << endl;
  66. }
  67. }
  68. }
  69. if (FAILED(hr))
  70. {
  71. return false;
  72. }
  73. g_XmlDomClassFactory = pFactory;
  74. return true;
  75. }
  76. HRESULT
  77. ConstructXMLDOMObject(
  78. string SourceName,
  79. ATL::CComPtr<IXMLDOMDocument> &document
  80. )
  81. {
  82. HRESULT hr = S_OK;
  83. VARIANT_BOOL vb;
  84. hr = g_XmlDomClassFactory->CreateInstance(NULL, __uuidof(document), (void**)&document);
  85. if (FAILED(hr))
  86. {
  87. return hr;
  88. }
  89. //
  90. // If they're willing to deal with bad XML, then so be it.
  91. //
  92. if (FAILED(hr = document->put_validateOnParse(VARIANT_FALSE)))
  93. {
  94. stringstream ss;
  95. ss << "MSXMLDOM Refuses to be let the wool be pulled over its eyes!";
  96. ReportError(ErrorSpew, ss);
  97. }
  98. hr = document->put_preserveWhiteSpace(VARIANT_TRUE);
  99. hr = document->put_resolveExternals(VARIANT_FALSE);
  100. CFileStreamBase *fsbase = new CFileStreamBase; // LEAK out of paranoia
  101. ATL::CComPtr<IStream> istream = fsbase;
  102. if (!fsbase->OpenForRead(SourceName))
  103. {
  104. stringstream ss;
  105. ss << "Failed opening " << SourceName.c_str() << " for read.";
  106. ReportError(ErrorFatal, ss);
  107. return E_FAIL;
  108. }
  109. hr = document->load(_variant_t(istream), &vb);
  110. if (vb != VARIANT_TRUE)
  111. {
  112. ATL::CComPtr<IXMLDOMParseError> perror;
  113. hr = document->get_parseError(&perror);
  114. long ecode, filepos, linenumber, linepos;
  115. BSTR reason, src;
  116. perror->get_errorCode(&ecode);
  117. perror->get_filepos(&filepos);
  118. perror->get_line(&linenumber);
  119. perror->get_linepos(&linepos);
  120. perror->get_reason(&reason);
  121. perror->get_srcText(&src);
  122. stringstream ss;
  123. ss << "Error: " << hex << ecode << dec << " " << (char*)_bstr_t(reason)
  124. << " at position " << filepos << ", line " << linenumber << " column " << linepos << endl
  125. << " the text was: " << endl << (char*)_bstr_t(src) << endl;
  126. ReportError(ErrorFatal, ss);
  127. hr = E_FAIL;
  128. }
  129. fsbase->Close();
  130. return hr;
  131. }
  132. void dispUsage()
  133. {
  134. const char HelpMessage[] =
  135. "Modes of operation:\n"
  136. " -hashupdate Update hashes of member files\n"
  137. " -makecdfs Generate CDF files to make catalogs\n"
  138. " -verbose Disply piles of debugging information\n"
  139. "\n"
  140. "Modifiers:\n"
  141. " -manifest <foo.man> The name of the manifest to work with\n"
  142. "\n"
  143. "Normal usage:"
  144. " mt.exe -hashupdate -makecdfs -manifest foo.man\n"
  145. "\n";
  146. cout << HelpMessage;
  147. }
  148. BOOL
  149. ProcessParameters(
  150. const vector<wstring> &params,
  151. bool &bUpdateHashes,
  152. bool &bCreateCatalogs,
  153. bool &bVerbosity,
  154. pair<bool, CPostbuildProcessListEntry> &bCmdLineSingleItem
  155. )
  156. {
  157. std::vector<wstring>::const_iterator ci;
  158. bUpdateHashes = bCreateCatalogs = bVerbosity = false;
  159. for (ci = params.begin(); ci != params.end(); ci++)
  160. {
  161. if (*ci == wstring(L"-?"))
  162. {
  163. dispUsage();
  164. exit(1);
  165. }
  166. bUpdateHashes |= (*ci == wstring(L"-hashupdate"));
  167. bCreateCatalogs |= (*ci == wstring(L"-makecdfs"));
  168. bVerbosity |= (*ci == wstring(L"-verbose"));
  169. if (*ci == wstring(L"-binplacelog"))
  170. {
  171. g_BinplaceLogFile = SwitchStringRep(*++ci);
  172. }
  173. else if (*ci == wstring(L"-razzle"))
  174. {
  175. g_RazzleBuildTime = true;
  176. }
  177. else if (*ci == wstring(L"-cdfpath"))
  178. {
  179. std::vector<wstring>::const_iterator cinext = ci + 1;
  180. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  181. {
  182. stringstream ss;
  183. ss << "-cdfpath needs a path name";
  184. ReportError( ErrorFatal, ss );
  185. return FALSE;
  186. }
  187. g_CdfOutputPath = SwitchStringRep(*++ci);
  188. }
  189. else if (*ci == wstring(L"-asmsroot"))
  190. {
  191. std::vector<wstring>::const_iterator cinext = ci + 1;
  192. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  193. {
  194. stringstream ss;
  195. ss << "-asmsroot needs a path name";
  196. ReportError( ErrorFatal, ss );
  197. return FALSE;
  198. }
  199. g_AsmsBuildRootPath = SwitchStringRep(*++ci);
  200. }
  201. else if (*ci == wstring(L"-manifest"))
  202. {
  203. std::vector<wstring>::const_iterator cinext = ci + 1;
  204. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  205. {
  206. stringstream ss;
  207. ss << "-manifest needs a file name";
  208. ReportError( ErrorFatal, ss );
  209. return FALSE;
  210. }
  211. bCmdLineSingleItem.first = true;
  212. CHAR ch[MAX_PATH];
  213. GetCurrentDirectoryA(MAX_PATH, ch);
  214. bCmdLineSingleItem.first = true;
  215. bCmdLineSingleItem.second.setManifestLocation(string(ch), SwitchStringRep(*++ci));
  216. }
  217. else if (*ci == wstring(L"-version"))
  218. {
  219. std::vector<wstring>::const_iterator cinext = ci + 1;
  220. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  221. {
  222. stringstream ss;
  223. ss << "-version needs a version string";
  224. ReportError( ErrorFatal, ss );
  225. return FALSE;
  226. }
  227. bCmdLineSingleItem.first = true;
  228. bCmdLineSingleItem.second.version = SwitchStringRep(*++ci);
  229. }
  230. else if (*ci == wstring(L"-language"))
  231. {
  232. std::vector<wstring>::const_iterator cinext = ci + 1;
  233. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  234. {
  235. stringstream ss;
  236. ss << "-language needs a culture name string";
  237. ReportError( ErrorFatal, ss );
  238. return FALSE;
  239. }
  240. bCmdLineSingleItem.first = true;
  241. bCmdLineSingleItem.second.language = JustifyPath(SwitchStringRep(*++ci));
  242. }
  243. else if (*ci == wstring(L"-name"))
  244. {
  245. std::vector<wstring>::const_iterator cinext = ci + 1;
  246. if ( ( cinext == params.end() ) || ( (*cinext).at(0) == L'-' ) )
  247. {
  248. stringstream ss;
  249. ss << "-name needs an assembly name string";
  250. ReportError( ErrorFatal, ss );
  251. return FALSE;
  252. }
  253. bCmdLineSingleItem.first = true;
  254. bCmdLineSingleItem.second.name = SwitchStringRep(*++ci);
  255. }
  256. }
  257. return TRUE;
  258. }
  259. int __cdecl wmain(int argc, WCHAR* argv[])
  260. {
  261. using namespace std;
  262. bool bUpdateHashes = true;
  263. bool bGenerateCatalogs = true;
  264. vector<wstring> params;
  265. HRESULT hr;
  266. pair<bool, CPostbuildProcessListEntry> hasInlinedManifest;
  267. for (int i = 0; i < argc; i++) {
  268. wstring here = argv[i];
  269. if ( here == wstring(L"-nologo"))
  270. g_SuppressBanner = true;
  271. else
  272. params.push_back(here);
  273. }
  274. if ( !g_SuppressBanner )
  275. {
  276. cout << MicrosoftCopyrightLogo;
  277. }
  278. if (!ProcessParameters(params, bUpdateHashes, bGenerateCatalogs, g_bDisplaySpew, hasInlinedManifest))
  279. return 1;
  280. //
  281. // Start COM
  282. //
  283. if (FAILED(hr = ::CoInitialize(NULL)))
  284. {
  285. stringstream ss;
  286. ss << "Unable to start com, error " << hex << hr;
  287. ReportError(ErrorFatal, ss);
  288. return 1;
  289. }
  290. if (!InitializeMSXML3())
  291. {
  292. return 2;
  293. }
  294. if (hasInlinedManifest.first)
  295. {
  296. PostbuildEntries.push_back(hasInlinedManifest.second);
  297. goto StartProcessing;
  298. }
  299. //
  300. // Populate the processing list, but only if we're really in a Razzle
  301. // environment
  302. //
  303. if ( g_RazzleBuildTime )
  304. {
  305. // string chName = convertWCharToAnsi(argv[1]);
  306. ifstream BinplaceLog;
  307. BinplaceLog.open(g_BinplaceLogFile.c_str());
  308. if (!BinplaceLog.is_open()) {
  309. cerr << "Failed opening '" << g_BinplaceLogFile << "' as the binplace log?" << endl;
  310. cerr << "Ensure that the path passed by '-binplacelog' is valid." << endl;
  311. return 1;
  312. }
  313. while (!BinplaceLog.eof())
  314. {
  315. string sourceLine;
  316. wstring wSourceLine;
  317. CPostbuildProcessListEntry item;
  318. StringStringMap ValuePairs;
  319. getline(BinplaceLog, sourceLine);
  320. wSourceLine = SwitchStringRep(sourceLine);
  321. ValuePairs = MapFromDefLine(wSourceLine);
  322. if (!ValuePairs.size())
  323. continue;
  324. item.name = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_NAME"]);
  325. item.version = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_VERSION"]);
  326. item.language = SwitchStringRep(ValuePairs[L"SXS_ASSEMBLY_LANGUAGE"]);
  327. item.setManifestLocation(g_AsmsBuildRootPath, SwitchStringRep(ValuePairs[L"SXS_MANIFEST"]));
  328. if (item.getManifestFullPath().find("asms\\") == -1) {
  329. stringstream ss;
  330. ss << "Skipping manifested item " << item << " because it's not under asms.";
  331. ReportError(ErrorSpew, ss);
  332. } else {
  333. PostbuildEntries.push_back(item);
  334. }
  335. }
  336. std::sort(PostbuildEntries.begin(), PostbuildEntries.end());
  337. PostbuildEntries.resize(std::unique(PostbuildEntries.begin(), PostbuildEntries.end()) - PostbuildEntries.begin());
  338. }
  339. else if ( !hasInlinedManifest.first )
  340. {
  341. //
  342. // No -razzle and no -manifest? Whoops...
  343. //
  344. dispUsage();
  345. return 1;
  346. }
  347. StartProcessing:
  348. if ( !bUpdateHashes && !bGenerateCatalogs )
  349. {
  350. cout << "Nothing to do!" << endl;
  351. dispUsage();
  352. return 1;
  353. }
  354. for (vector<CPostbuildProcessListEntry>::const_iterator cursor = PostbuildEntries.begin(); cursor != PostbuildEntries.end(); cursor++)
  355. {
  356. //
  357. // First, mash the hashes around.
  358. //
  359. if (bUpdateHashes)
  360. UpdateManifestHashes(*cursor);
  361. //
  362. // Second, generate catalogs
  363. //
  364. if (bGenerateCatalogs)
  365. GenerateCatalogContents(*cursor);
  366. }
  367. hr = S_OK;
  368. return (hr == S_OK) ? 0 : 1;
  369. }
  370. CPostbuildItemVector PostbuildEntries;