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.

736 lines
23 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. xmlchk.cpp
  5. Abstract:
  6. Use msxml.dll to see if an .xml file conforms to a schema.
  7. Author:
  8. Ted Padua (TedP)
  9. Revision History:
  10. Jay Krell (JayKrell) April 2001 partial cleanup
  11. many leaks added in attempt to stop it from crashing
  12. crash doesn't repro consistently, but there's always a few
  13. in a world build
  14. June 2001 let it run on Win9x and Win2000
  15. --*/
  16. #include "stdinc.h"
  17. #include "helpers.h"
  18. #define XMLCHK_FLAG_SILENT (0x00000001)
  19. ULONG g_nrunFlags = 0; //global run flag - determines if should run in silent mode = 0x01
  20. IClassFactory* g_XmlDomClassFactory;
  21. IClassFactory* g_XmlSchemaCacheClassFactory;
  22. __declspec(thread) long line = __LINE__;
  23. __declspec(thread) ULONG lastError;
  24. #if defined(_WIN64)
  25. #define IsAtLeastXp() (TRUE)
  26. #define g_IsNt (TRUE)
  27. #else
  28. DWORD g_Version;
  29. BOOL g_IsNt;
  30. #define IsAtLeastXp() (g_IsNt && g_Version >= 0x0501)
  31. #endif
  32. // Globals indicating what we're currently doing.
  33. // L"" is different than the default constructed, because it can be derefed
  34. ::ATL::CComBSTR szwcharSchemaTmp = L"";
  35. ::ATL::CComBSTR szwcharManTmp = L"";
  36. bool g_fInBuildProcess = false;
  37. // string to put in front of all error messages so that BUILD can find them.
  38. const char ErrMsgPrefix[] = "NMAKE : U1234: 'FUSION_MANIFEST_VALIDATOR' ";
  39. void ConvertNewlinesToSpaces(char* s)
  40. {
  41. while (*s)
  42. {
  43. if (isspace(*s))
  44. *s = ' ';
  45. s += 1;
  46. }
  47. }
  48. void Error(PCSTR szPrintFormatString, ...)
  49. {
  50. char StartBuffer[256];
  51. char *buffer = StartBuffer;
  52. int iAvailable = 256;
  53. if (g_fInBuildProcess)
  54. return;
  55. while (buffer)
  56. {
  57. va_list args;
  58. int iUsed;
  59. va_start(args, szPrintFormatString);
  60. buffer[iAvailable - 1] = buffer[iAvailable - 2] = '\0';
  61. iUsed = _vsnprintf(buffer, iAvailable, szPrintFormatString, args);
  62. va_end(args);
  63. //
  64. // Used all the characters, or we stomped the canary?
  65. //
  66. if ((iUsed >= iAvailable) || (buffer[iAvailable - 1] != '\0'))
  67. {
  68. if (buffer != StartBuffer)
  69. {
  70. delete [] buffer;
  71. }
  72. iAvailable *= 2;
  73. buffer = new char[iAvailable];
  74. continue;
  75. }
  76. else
  77. {
  78. buffer[iUsed] = '\0';
  79. break;
  80. }
  81. }
  82. if (buffer)
  83. {
  84. ConvertNewlinesToSpaces(buffer);
  85. }
  86. printf("%s line=%ld, %s\n", ErrMsgPrefix, line, buffer);
  87. if (buffer && (buffer != StartBuffer))
  88. delete [] buffer;
  89. }
  90. void PrintOutMode(PCSTR szPrintFormatString, ...)
  91. {
  92. if (g_fInBuildProcess)
  93. return;
  94. if ((g_nrunFlags & XMLCHK_FLAG_SILENT) == 0)
  95. {
  96. va_list args;
  97. va_start(args, szPrintFormatString);
  98. vprintf(szPrintFormatString, args);
  99. va_end(args);
  100. }
  101. }
  102. void PrintErrorDuringBuildProcess(IXMLDOMParseError* pError)
  103. {
  104. HRESULT hr = S_OK;
  105. ::ATL::CComBSTR bstrError;
  106. long lErrorCode = 0;
  107. long lErrorLine = 0;
  108. if (FAILED(hr = pError->get_errorCode(&lErrorCode)))
  109. goto FailedGettingDetails;
  110. if (FAILED(hr = pError->get_line(&lErrorLine)))
  111. goto FailedGettingDetails;
  112. if (FAILED(hr = pError->get_reason(&bstrError)))
  113. goto FailedGettingDetails;
  114. //
  115. // Now print in a way that build is likely to pick up
  116. //
  117. printf(
  118. "%s : %ls(%ld) - %ls (Error 0x%08lx)\r\n",
  119. ErrMsgPrefix,
  120. static_cast<PCWSTR>(szwcharManTmp),
  121. lErrorLine,
  122. static_cast<PCWSTR>(bstrError),
  123. lErrorCode);
  124. return;
  125. FailedGettingDetails:
  126. printf("%s : %ls had an error, but the error data was unavailable (Error 0x%08lx).\r\n",
  127. ErrMsgPrefix,
  128. static_cast<PCWSTR>(szwcharManTmp),
  129. hr);
  130. return;
  131. }
  132. void PrintError(IXMLDOMParseError *pError)
  133. {
  134. ::ATL::CComBSTR bstrError;
  135. ::ATL::CComBSTR bstrURL;
  136. ::ATL::CComBSTR bstrText;
  137. long errCode = 0;
  138. long errLine = 0;
  139. long errPos = 0;
  140. HRESULT hr = S_OK;
  141. long line = __LINE__;
  142. try
  143. {
  144. line = __LINE__;
  145. hr = pError->get_reason(&bstrError);
  146. if (FAILED(hr))
  147. throw hr;
  148. line = __LINE__;
  149. hr = pError->get_url(&bstrURL);
  150. if (FAILED(hr))
  151. throw hr;
  152. line = __LINE__;
  153. hr = pError->get_errorCode(&errCode);
  154. if (FAILED(hr))
  155. throw hr;
  156. line = __LINE__;
  157. hr = pError->get_srcText(&bstrText);
  158. if (FAILED(hr))
  159. throw hr;
  160. line = __LINE__;
  161. hr = pError->get_line(&errLine);
  162. if (FAILED(hr))
  163. throw hr;
  164. line = __LINE__;
  165. hr = pError->get_linepos(&errPos);
  166. if (FAILED(hr))
  167. throw hr;
  168. line = __LINE__;
  169. PrintOutMode("\nError Info:\n");
  170. if (bstrError != NULL)
  171. PrintOutMode("\tDescription: %ls\n", static_cast<PCWSTR>(bstrError));
  172. if (bstrURL != NULL)
  173. PrintOutMode("\tURL: %ls\n", static_cast<PCWSTR>(bstrURL));
  174. //if (errCode > 0)
  175. PrintOutMode("\tCode=%X", errCode);
  176. if (errLine > 0)
  177. PrintOutMode(" on Line:%ld, ", errLine);
  178. if (errPos > 0)
  179. PrintOutMode("\tPos:%ld\n", errPos);
  180. line = __LINE__;
  181. if (errLine > 0 && bstrText != NULL)
  182. {
  183. PrintOutMode("\tLine %ld: ", errLine);
  184. long lLen = ::SysStringLen(bstrText);
  185. for (int i = 0; i < lLen; i++)
  186. {
  187. if (bstrText[i] == '\t')
  188. PrintOutMode(" ");
  189. else
  190. PrintOutMode("%lc", bstrText[i]);
  191. }
  192. PrintOutMode("\n");
  193. if (errPos > 0 || lLen > 0)
  194. {
  195. PrintOutMode("\tPos %ld: ", errPos);
  196. for (int i = 1; i < errPos; i++)
  197. {
  198. PrintOutMode("-");
  199. }
  200. PrintOutMode("^\n");
  201. }
  202. }
  203. line = __LINE__;
  204. }
  205. catch(HRESULT hr2)
  206. {
  207. Error("Failed getting error #1 information hr=%lx, line=%ld\n", static_cast<unsigned long>(hr2), line);
  208. }
  209. }
  210. //tedp
  211. // Load an msxml version. If we don't get v3, we fall to v2, then to v1. v1 is pretty darn useless,
  212. // however, so it'd be nice if we didn't have to.
  213. bool
  214. InitializeMSXML3()
  215. {
  216. static HMODULE hMsXml3 = NULL;
  217. typedef HRESULT (__stdcall * PFN_DLL_GET_CLASS_OBJECT)(REFCLSID, REFIID, LPVOID*);
  218. PFN_DLL_GET_CLASS_OBJECT pfnGetClassObject = NULL;
  219. ::ATL::CComPtr<IClassFactory> pFactory;
  220. HRESULT hr = S_OK;
  221. ::ATL::CComPtr<IClassFactory> pSchemaCacheFactory;
  222. line = __LINE__;
  223. if (hMsXml3 == NULL)
  224. {
  225. hMsXml3 = LoadLibrary(TEXT("msxml3.dll"));
  226. if (hMsXml3 == NULL)
  227. {
  228. line = __LINE__;
  229. if (IsAtLeastXp())
  230. PrintOutMode("Unable to load msxml3, trying msxml2\n");
  231. line = __LINE__;
  232. if (IsAtLeastXp())
  233. hMsXml3 = LoadLibrary(TEXT("msxml2.dll"));
  234. line = __LINE__;
  235. if (hMsXml3 == NULL)
  236. {
  237. line = __LINE__;
  238. if (IsAtLeastXp())
  239. PrintOutMode("Unable to load msxml2\n");
  240. line = __LINE__;
  241. }
  242. }
  243. }
  244. line = __LINE__;
  245. if (hMsXml3 == NULL)
  246. {
  247. if (IsAtLeastXp())
  248. Error("LoadLibrary(msxml) lastError=%lu\n", GetLastError());
  249. return false;
  250. }
  251. line = __LINE__;
  252. pfnGetClassObject = reinterpret_cast<PFN_DLL_GET_CLASS_OBJECT>(GetProcAddress(hMsXml3, "DllGetClassObject"));
  253. if (!pfnGetClassObject)
  254. {
  255. line = __LINE__;
  256. Error("GetProcAddress(msxml, DllGetClassObject) lastError=%lu\n", GetLastError());
  257. return false;
  258. }
  259. line = __LINE__;
  260. hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument30), __uuidof(pFactory), (void**)&pFactory);
  261. if (FAILED(hr))
  262. {
  263. PrintOutMode("Can't load version 3.0, trying 2.6\n");
  264. hr = pfnGetClassObject(__uuidof(MSXML2::DOMDocument26), __uuidof(pFactory), (void**)&pFactory);
  265. if (FAILED(hr))
  266. {
  267. PrintOutMode("Can't load version 2.6\n");
  268. }
  269. }
  270. pFactory->LockServer(TRUE); // possibly the right fix for the crash
  271. static_cast<IUnknown*>(pFactory)->AddRef(); // jaykrell hack to try to avoid crash
  272. static_cast<IUnknown*>(pFactory)->AddRef(); // jaykrell hack to try to avoid crash
  273. line = __LINE__;
  274. if (FAILED(hr))
  275. {
  276. Error("msxml.DllGetClassObject(DOMDocument) hr=%lx\n", hr);
  277. return false;
  278. }
  279. g_XmlDomClassFactory = pFactory;
  280. hr = pfnGetClassObject(__uuidof(MSXML2::XMLSchemaCache30), __uuidof(pFactory), (void**)&pSchemaCacheFactory);
  281. if (FAILED(hr))
  282. {
  283. PrintOutMode("Can't load SchemaCache version 3.0, trying 2.6\n");
  284. hr = pfnGetClassObject(__uuidof(MSXML2::XMLSchemaCache26), __uuidof(pFactory), (void**)&pSchemaCacheFactory);
  285. if (FAILED(hr))
  286. {
  287. PrintOutMode("Can't load SchemaCache version 2.6\n");
  288. }
  289. }
  290. pSchemaCacheFactory->LockServer(TRUE); // possibly the right fix for the crash
  291. static_cast<IUnknown*>(pSchemaCacheFactory)->AddRef(); // jaykrell hack to try to avoid crash
  292. static_cast<IUnknown*>(pSchemaCacheFactory)->AddRef(); // jaykrell hack to try to avoid crash
  293. if (FAILED(hr))
  294. {
  295. Error("msxml.DllGetClassObject(SchemaCache) hr=%lx\n", hr);
  296. return false;
  297. }
  298. g_XmlSchemaCacheClassFactory = pSchemaCacheFactory;
  299. return true;
  300. }
  301. BOOL
  302. Validating(
  303. PCWSTR SourceManName,
  304. PCWSTR SchemaName
  305. )
  306. {
  307. HRESULT hr = S_OK;
  308. BOOL bResult = FALSE;
  309. short sResult = FALSE;
  310. VARIANT_BOOL vb = VARIANT_FALSE;
  311. ::ATL::CComPtr<IXMLDOMParseError> pParseError;
  312. ::ATL::CComPtr<IXMLDOMParseError> pParseError2;
  313. ::ATL::CComPtr<IXMLDOMDocument> document;
  314. ::ATL::CComPtr<MSXML2::IXMLDOMDocument2> spXMLDOMDoc2;
  315. ::ATL::CComPtr<MSXML2::IXMLDOMSchemaCollection> spIXMLDOMSchemaCollection;
  316. try
  317. {
  318. hr = g_XmlDomClassFactory->CreateInstance(NULL, __uuidof(document), (void**)&document);
  319. if (FAILED(hr))
  320. {
  321. Error("msxml.CreateInstance(document) hr=%lx\n", hr);
  322. throw hr;
  323. }
  324. if (document != NULL)
  325. {
  326. static_cast<IUnknown*>(document)->AddRef(); // jaykrell hack to try to avoid crash
  327. static_cast<IUnknown*>(document)->AddRef(); // jaykrell hack to try to avoid crash
  328. }
  329. //
  330. // If they're willing to deal with bad XML, then so be it.
  331. //
  332. // First pass - validating the manifest itself alone
  333. PrintOutMode("Validating the manifest as XML file...\n");
  334. hr = document->put_async(VARIANT_FALSE);
  335. if (FAILED(hr))
  336. throw hr;
  337. hr = document->put_validateOnParse(VARIANT_FALSE);
  338. if (FAILED(hr))
  339. throw hr;
  340. hr = document->put_resolveExternals(VARIANT_FALSE);
  341. if (FAILED(hr))
  342. throw hr;
  343. line = __LINE__;
  344. CFileStreamBase* fsbase = new CFileStreamBase; // jaykrell leak out of paranoia
  345. fsbase->AddRef(); // jaykrell leak out of paranoia
  346. fsbase->AddRef(); // jaykrell leak out of paranoia
  347. fsbase->AddRef(); // jaykrell leak out of paranoia
  348. ::ATL::CComPtr<IStream> istream = fsbase;
  349. if (!fsbase->OpenForRead(SourceManName))
  350. {
  351. lastError = GetLastError();
  352. hr = HRESULT_FROM_WIN32(lastError);
  353. Error("OpenForRead(%ls) lastError=%lu\n", SourceManName, lastError);
  354. throw hr;
  355. }
  356. hr = document->load(::ATL::CComVariant(istream), &vb);
  357. if (FAILED(hr) || vb == VARIANT_FALSE)
  358. {
  359. if (vb == VARIANT_FALSE)
  360. PrintOutMode("Well Formed XML Validation: FAILED\n");
  361. {
  362. HRESULT loc_hr = document->get_parseError(&pParseError);
  363. if (pParseError != NULL)
  364. {
  365. static_cast<IUnknown*>(pParseError)->AddRef(); // jaykrell hack to try to avoid crash
  366. static_cast<IUnknown*>(pParseError)->AddRef(); // jaykrell hack to try to avoid crash
  367. }
  368. if (g_fInBuildProcess)
  369. PrintErrorDuringBuildProcess(pParseError);
  370. else
  371. PrintError(pParseError);
  372. }
  373. throw hr;
  374. }
  375. else
  376. PrintOutMode("Well Formed XML Validation: Passed\n");
  377. // Second pass - validating manifest against schema
  378. PrintOutMode("\nNow validating manifest against XML Schema file...\n");
  379. // CreateInstance creates you an instance of the object you requested above, and puts
  380. // the pointer in the out param. Think of this like CoCreateInstance, but knowing who
  381. // is going
  382. hr = g_XmlDomClassFactory->CreateInstance(NULL, __uuidof(spXMLDOMDoc2), (void**)&spXMLDOMDoc2);
  383. if (FAILED(hr))
  384. {
  385. PrintOutMode("Failed creating IXMLDOMDoc2...\n");
  386. throw hr;
  387. }
  388. static_cast<IUnknown*>(spXMLDOMDoc2)->AddRef(); // jaykrell hack to try to avoid crash
  389. static_cast<IUnknown*>(spXMLDOMDoc2)->AddRef(); // jaykrell hack to try to avoid crash
  390. hr = spXMLDOMDoc2->put_async(VARIANT_FALSE);
  391. if (FAILED(hr))
  392. throw hr;
  393. hr = spXMLDOMDoc2->put_validateOnParse(VARIANT_TRUE); //changed - was FALSE
  394. if (FAILED(hr))
  395. throw hr;
  396. hr = spXMLDOMDoc2->put_resolveExternals(VARIANT_FALSE);
  397. if (FAILED(hr))
  398. throw hr;
  399. hr = g_XmlSchemaCacheClassFactory->CreateInstance(NULL, __uuidof(spIXMLDOMSchemaCollection), (void**)&spIXMLDOMSchemaCollection);
  400. if (FAILED(hr))
  401. {
  402. PrintOutMode("Failed creating IXMLDOMSchemaCollection...\n");
  403. throw hr;
  404. }
  405. static_cast<IUnknown*>(spIXMLDOMSchemaCollection)->AddRef(); // jaykrell hack to try to avoid crash
  406. static_cast<IUnknown*>(spIXMLDOMSchemaCollection)->AddRef(); // jaykrell hack to try to avoid crash
  407. if ((FAILED(hr) || !spIXMLDOMSchemaCollection))
  408. throw hr;
  409. hr = spIXMLDOMSchemaCollection->add(
  410. ::ATL::CComBSTR(L"urn:schemas-microsoft-com:asm.v1"),
  411. ::ATL::CComVariant(SchemaName));
  412. if(FAILED(hr))
  413. {
  414. PrintOutMode("BAD SCHEMA file.\n");
  415. throw hr;
  416. }
  417. static_cast<IUnknown*>(spIXMLDOMSchemaCollection)->AddRef(); // jaykrell hack to try to avoid crash
  418. static_cast<IUnknown*>(spIXMLDOMSchemaCollection)->AddRef(); // jaykrell hack to try to avoid crash
  419. // ownership of the idispatch/variant-by-value is not clear
  420. ::ATL::CComVariant varValue(::ATL::CComQIPtr<IDispatch>(spIXMLDOMSchemaCollection).Detach());
  421. hr = spXMLDOMDoc2->putref_schemas(varValue);
  422. // The document will load only if a valid schema is
  423. // attached to the xml file.
  424. // jaykrell leak here because ownership isn't clear
  425. hr = spXMLDOMDoc2->load(::ATL::CComVariant(::ATL::CComBSTR(SourceManName).Copy()), &sResult);
  426. if (FAILED(hr) || sResult == VARIANT_FALSE)
  427. {
  428. PrintOutMode("Manifest Schema Validation: FAILED\n");
  429. if (sResult == VARIANT_FALSE)
  430. {
  431. HRESULT loc_hr = spXMLDOMDoc2->get_parseError(&pParseError2);
  432. if (pParseError2 != NULL)
  433. {
  434. static_cast<IUnknown*>(pParseError2)->AddRef(); // jaykrell hack to try to avoid crash
  435. static_cast<IUnknown*>(pParseError2)->AddRef(); // jaykrell hack to try to avoid crash
  436. }
  437. if (g_fInBuildProcess)
  438. PrintErrorDuringBuildProcess(pParseError2);
  439. else
  440. PrintError(pParseError2);
  441. bResult = FALSE;
  442. }
  443. else
  444. {
  445. throw hr;
  446. }
  447. }
  448. else
  449. {
  450. PrintOutMode("Manifest Schema Validation: Passed\n");
  451. bResult = TRUE;
  452. }
  453. }
  454. catch(HRESULT hr)
  455. {
  456. bResult = FALSE;
  457. if (E_NOINTERFACE == hr)
  458. {
  459. Error("*** Error *** No such interface supported! \n");
  460. }
  461. else
  462. {
  463. ::ATL::CComPtr<IErrorInfo> pErrorInfo;
  464. HRESULT loc_hr = GetErrorInfo(0, &pErrorInfo);
  465. if (pErrorInfo != NULL)
  466. {
  467. static_cast<IUnknown*>(pErrorInfo)->AddRef(); // jaykrell hack to try to avoid crash
  468. static_cast<IUnknown*>(pErrorInfo)->AddRef(); // jaykrell hack to try to avoid crash
  469. }
  470. if ((S_OK == loc_hr) && pErrorInfo != NULL)
  471. {
  472. ::ATL::CComQIPtr<IXMLError> pXmlError(pErrorInfo);
  473. XML_ERROR xError;
  474. ::ATL::CComBSTR errSource;
  475. ::ATL::CComBSTR errDescr;
  476. pErrorInfo->GetDescription(&errDescr);
  477. pErrorInfo->GetSource(&errSource);
  478. Error("*** ERROR *** generated by %ls\n", static_cast<PCWSTR>(errSource));
  479. Error("*** ERROR *** description: %ls\n", static_cast<PCWSTR>(errDescr));
  480. if (pXmlError)
  481. {
  482. pXmlError->GetErrorInfo(&xError);
  483. Error("*** ERROR *** document line %d, text '%.*ls'\n", xError._nLine, xError._pchBuf, xError._cchBuf);
  484. }
  485. }
  486. else
  487. {
  488. if (hr == CO_E_CLASSSTRING)
  489. {
  490. Error("*** Error *** hr returned: CO_E_CLASSSTRING, value %x\n", hr);
  491. Error(" msg: The registered CLSID for the ProgID is invalid.\n");
  492. }
  493. else
  494. {
  495. Error("*** Error *** Cannot obtain additional error info hr=%lx!\n", static_cast<unsigned long>(hr));
  496. }
  497. }
  498. }
  499. }
  500. return bResult;
  501. }
  502. BOOL IsValidCommandLineArgs(int argc, wchar_t** argv, ::ATL::CComBSTR& szwcharSchemaTmp, ::ATL::CComBSTR& szwcharManTmp)
  503. {
  504. // check commandline args a little
  505. int nOnlyAllowFirstTimeReadFlag = 0; //Manifest = 0x01 Schema = 0x02 Quiet = 0x04
  506. if((4 >= argc) && (3 <= argc))
  507. {
  508. //now check actual values
  509. for (int i = 1; i < argc; i++)
  510. {
  511. if (argv[i][0] == L'/')
  512. {
  513. switch (argv[i][1])
  514. {
  515. case L'?': return FALSE; break;
  516. case L'q': case L'Q':
  517. if(0x04 & nOnlyAllowFirstTimeReadFlag)
  518. return FALSE;
  519. else
  520. g_nrunFlags |= XMLCHK_FLAG_SILENT;
  521. nOnlyAllowFirstTimeReadFlag = 0x04;
  522. break;
  523. case L'm': case L'M':
  524. if (argv[i][2] == L':')
  525. {
  526. if(0x01 & nOnlyAllowFirstTimeReadFlag)
  527. return FALSE;
  528. else
  529. szwcharManTmp = &argv[i][3];
  530. nOnlyAllowFirstTimeReadFlag = 0x01;
  531. break;
  532. }
  533. else
  534. {
  535. return FALSE;
  536. }
  537. case L's': case L'S':
  538. if (argv[i][2] == L':')
  539. {
  540. if(0x02 & nOnlyAllowFirstTimeReadFlag)
  541. return FALSE;
  542. else
  543. szwcharSchemaTmp = &argv[i][3];
  544. nOnlyAllowFirstTimeReadFlag = 0x02;
  545. break;
  546. }
  547. else
  548. {
  549. return FALSE;
  550. }
  551. case L'B': case L'b':
  552. g_fInBuildProcess = true;
  553. break;
  554. default:
  555. return FALSE;
  556. }
  557. }
  558. else
  559. return FALSE;
  560. }
  561. if ((0 == szwcharSchemaTmp[0]) ||
  562. (0 == szwcharManTmp[0]))
  563. {
  564. return FALSE;
  565. }
  566. return TRUE;
  567. }
  568. else
  569. {
  570. return FALSE;
  571. }
  572. }
  573. void PrintUsage()
  574. {
  575. printf("\n");
  576. printf("Validates Fusion Win32 Manifest files using a schema.");
  577. printf("\n");
  578. printf("Usage:");
  579. printf(" FusionManifestValidator /S:[drive:][path]schema_filename /M:[drive:][path]xml_manifest_filename [/Q]\n\n");
  580. printf(" /S: Specify schema filename used to validate manifest\n");
  581. printf(" /M: Specify manifest filename to validate\n");
  582. printf(" /Q Quiet mode - suppresses output to console\n");
  583. printf(" \n");
  584. printf(" The tool without /Q displays details of first encountered error\n");
  585. printf(" (if errors are present in manifest), and displays Pass or Fail\n");
  586. printf(" of the validation result. The application returns 0 for Pass,\n");
  587. printf(" 1 for Fail, and returns 2 for bad command line argument.\n");
  588. }
  589. int __cdecl wmain(int argc, wchar_t** argv)
  590. {
  591. int iValidationResult = 0;
  592. #if !defined(_WIN64)
  593. g_Version = GetVersion();
  594. g_IsNt = ((g_Version & 0x80000000) == 0);
  595. g_Version = ((g_Version >> 8) & 0xFF) | ((g_Version & 0xFF) << 8);
  596. //printf("%x\n", g_Version);
  597. #endif
  598. // Start COM
  599. CoInitialize(NULL);
  600. if (!IsValidCommandLineArgs(argc, argv, szwcharSchemaTmp, szwcharManTmp))
  601. {
  602. PrintUsage();
  603. iValidationResult = 2; //return error value 2 for CommandLine Arg error
  604. }
  605. else
  606. {
  607. PrintOutMode("Schema is: %ls\n", static_cast<PCWSTR>(szwcharSchemaTmp));
  608. PrintOutMode("Manifest is: %ls\n\n", static_cast<PCWSTR>(szwcharManTmp));
  609. if (InitializeMSXML3())
  610. {
  611. BOOL bResult = Validating(szwcharManTmp, szwcharSchemaTmp);
  612. if (bResult)
  613. PrintOutMode("\nOverall Validation PASSED.\n");
  614. else
  615. {
  616. Error("Overall Validation FAILED, CommandLine=%ls.\n", GetCommandLineW());
  617. iValidationResult = 1; //return error value 1 for Validation routine error
  618. }
  619. }
  620. else
  621. {
  622. //
  623. // If running on less than Windows XP, just claim success.
  624. //
  625. if (IsAtLeastXp())
  626. {
  627. Error("Unable to load MSXML3\n");
  628. iValidationResult = 3;
  629. }
  630. else
  631. PrintOutMode("\nMsXml3 not always available downlevel, just claim overall Validation PASSED.\n");
  632. }
  633. }
  634. // Stop COM
  635. CoUninitialize();
  636. // TerminateProcess(GetCurrentProcess(), iValidationResult);
  637. return iValidationResult;
  638. }