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.

2047 lines
60 KiB

  1. #include "stdinc.h"
  2. #include "stdio.h"
  3. #include "objbase.h"
  4. #include "prettyformat.h"
  5. #include "user32detours.h"
  6. #define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
  7. //
  8. // Options:
  9. //
  10. // -manifest <filename> - Uses filename as the output/input manifest
  11. // -useexisting - Assumes filename is already there, and that
  12. // it potentially contains some data already
  13. // that should be updated/appended to
  14. // -rebuildexisting - Manifest exists, but remove everything except
  15. // the file name and hash information (if present)
  16. // -checkregistry - Indicates that the registry should be searched
  17. // for other file entries in 'manifest'
  18. // -dlls [dll [[dll] ...]] - List of DLLs (patterns) that should go into the manifest
  19. // if not already present
  20. // -tlb <typelibname> - Type library to pull extra data out of
  21. //
  22. #define STR_NOLOGO L"-nologo"
  23. #define MS_LOGO L"Microsoft (R) Manifest Builder version 1.0.0.0\r\nCopyright (c) Microsoft Corporation 2001. All rights reserved.\r\n\r\n"
  24. #define STR_FILE_TAG_NAME L"file"
  25. #define STR_ASSEMBLY_MANIFEST_NAMESPACE L"urn:schemas-microsoft-com:asm.v1"
  26. #define STR_FILESEARCH_PATTERN L"/asmns:assembly/asmns:file"
  27. #define STR_COMCLASS_TAG L"comClass"
  28. #define STR_COMCLASS_CLSID L"clsid"
  29. #define STR_COMCLASS_TLBID L"tlbid"
  30. #define STR_COMCLASS_PROGID L"progid"
  31. #define STR_COMCLASS_THREADING L"threadingModel"
  32. #define STR_COMCLASS_DESC L"description"
  33. #define STR_ASM_NS L"asmns"
  34. #define SELECTION_NAMESPACES (L"xmlns:" STR_ASM_NS L"='" STR_ASSEMBLY_MANIFEST_NAMESPACE L"'")
  35. #define STR_MS_COMMENT_COPYRIGHT L"Copyright (C) Microsoft Corp. All Rights Reserved"
  36. class __declspec(uuid("00020424-0000-0000-C000-000000000046")) CPSOAInterface;
  37. class IMetaDataFileElement
  38. {
  39. public:
  40. virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptElement) = 0;
  41. };
  42. class CComClassInformation : public IMetaDataFileElement
  43. {
  44. public:
  45. CLSID m_ObjectIdent;
  46. CLSID m_TlbIdent;
  47. CString m_Description;
  48. CString m_Name;
  49. CString m_DllName;
  50. CString m_ThreadingModel;
  51. CString m_VersionIndependentProgId;
  52. CSimpleList<CString> m_ProgIdListing;
  53. CComClassInformation() {
  54. ZeroMemory(&m_ObjectIdent, sizeof(m_ObjectIdent));
  55. ZeroMemory(&m_TlbIdent, sizeof(m_TlbIdent));
  56. }
  57. virtual bool AddProgId(const CString& ProgId)
  58. {
  59. for (SIZE_T i = 0; i < m_ProgIdListing.Size(); i++) {
  60. if (m_ProgIdListing[i] == ProgId)
  61. return true;
  62. }
  63. m_ProgIdListing.Append(ProgId);
  64. return true;
  65. }
  66. virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptClsidElement)
  67. {
  68. HRESULT hr;
  69. hr = ptClsidElement->setAttribute(
  70. CString(L"clsid"),
  71. _variant_t(StringFromCLSID(m_ObjectIdent)));
  72. if (FAILED(hr))
  73. return false;
  74. if (m_TlbIdent != GUID_NULL)
  75. {
  76. hr = ptClsidElement->setAttribute(
  77. CString(L"tlbid"),
  78. _variant_t(StringFromCLSID(m_TlbIdent)));
  79. if (FAILED(hr))
  80. return false;
  81. }
  82. hr = ptClsidElement->setAttribute(CString(L"description"), _variant_t(m_Description));
  83. if (m_ThreadingModel.length() != 0)
  84. {
  85. hr = ptClsidElement->setAttribute(CString(L"threadingModel"), _variant_t(m_ThreadingModel));
  86. if (FAILED(hr))
  87. return false;
  88. }
  89. if (m_VersionIndependentProgId.length() != 0)
  90. {
  91. hr = ptClsidElement->setAttribute(CString(L"progid"), _variant_t(m_VersionIndependentProgId));
  92. if (FAILED(hr))
  93. return false;
  94. }
  95. for (SIZE_T pi = 0; pi < m_ProgIdListing.Size(); pi++)
  96. {
  97. CSmartPointer<IXMLDOMNode> ptCreatedNode;
  98. CSmartPointer<IXMLDOMDocument> ptDocument;
  99. VARIANT vt;
  100. vt.vt = VT_INT;
  101. vt.intVal = NODE_ELEMENT;
  102. if (FAILED(hr = ptClsidElement->get_ownerDocument(&ptDocument)))
  103. return false;
  104. if (FAILED(ptDocument->createNode(
  105. vt,
  106. _bstr_t(L"progid"),
  107. _bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
  108. &ptCreatedNode)))
  109. return false;
  110. if (FAILED(ptCreatedNode->put_text(m_ProgIdListing[pi])))
  111. return false;
  112. if (FAILED(ptClsidElement->appendChild(ptCreatedNode, NULL)))
  113. return false;
  114. }
  115. return hr == S_OK;
  116. }
  117. };
  118. class CTlbInformation : public IMetaDataFileElement
  119. {
  120. public:
  121. GUID m_Ident;
  122. DWORD m_Version[2];
  123. DWORD m_dwFlags;
  124. CString m_HelpDirectory;
  125. CString m_ResourceIdent;
  126. CString m_SourceFile;
  127. CTlbInformation() {
  128. m_dwFlags = m_Version[0] = m_Version[1] = 0;
  129. ZeroMemory(&m_Ident, sizeof(m_Ident));
  130. }
  131. virtual bool
  132. CompleteElement(CSmartPointer<IXMLDOMElement> ptTlbElement)
  133. {
  134. if (FAILED(ptTlbElement->setAttribute(
  135. _bstr_t(L"tlbid"),
  136. _variant_t(StringFromCLSID(this->m_Ident)))))
  137. return false;
  138. if (m_ResourceIdent.length() != 0)
  139. {
  140. if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"resourceid"), _variant_t(m_ResourceIdent))))
  141. return false;
  142. }
  143. if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"version"), _variant_t(FormatVersion(m_Version[0], m_Version[1])))))
  144. return false;
  145. if (FAILED(ptTlbElement->setAttribute(_bstr_t(L"helpdir"), _variant_t(m_HelpDirectory))))
  146. return false;
  147. return true;
  148. }
  149. };
  150. //
  151. // This is the assembly!comInterfaceProxyStub element member.
  152. //
  153. class CComInterfaceProxyStub : public IMetaDataFileElement
  154. {
  155. public:
  156. IID m_InterfaceId;
  157. GUID m_TlbId;
  158. CLSID m_StubClsid;
  159. CString m_Name;
  160. int m_iMethods;
  161. CComInterfaceProxyStub() {
  162. ZeroMemory(&m_InterfaceId, sizeof(m_InterfaceId));
  163. ZeroMemory(&m_TlbId, sizeof(m_TlbId));
  164. ZeroMemory(&m_StubClsid, sizeof(m_StubClsid));
  165. m_iMethods = 0;
  166. }
  167. virtual bool
  168. CompleteElement(CSmartPointer<IXMLDOMElement> ptProxyStub)
  169. {
  170. if (m_InterfaceId != GUID_NULL)
  171. if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"iid"), _variant_t(StringFromCLSID(m_InterfaceId)))))
  172. return false;
  173. if (m_TlbId != GUID_NULL)
  174. if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"tlbid"), _variant_t(StringFromCLSID(m_TlbId)))))
  175. return false;
  176. if (m_Name.length() != 0)
  177. if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"name"), _variant_t(m_Name))))
  178. return false;
  179. if (m_iMethods)
  180. if (FAILED((ptProxyStub->setAttribute(_bstr_t(L"numMethods"), _variant_t((LONGLONG)m_iMethods)))))
  181. return false;
  182. if (m_StubClsid != GUID_NULL)
  183. if (FAILED(ptProxyStub->setAttribute(_bstr_t(L"proxyStubClsid32"), _variant_t(StringFromCLSID(m_StubClsid)))))
  184. return false;
  185. return true;
  186. // Punting on base interface
  187. }
  188. };
  189. class CInterfaceInformation
  190. {
  191. public:
  192. bool m_fUsed;
  193. IID m_InterfaceIID;
  194. CString m_Name;
  195. CInterfaceInformation() : m_fUsed(false) { }
  196. };
  197. class CWindowClass : IMetaDataFileElement
  198. {
  199. public:
  200. CString m_WindowClass;
  201. CString m_SourceDll;
  202. virtual bool CompleteElement(CSmartPointer<IXMLDOMElement> ptWindowClassElement)
  203. {
  204. return SUCCEEDED(ptWindowClassElement->put_text(this->m_WindowClass));
  205. }
  206. };
  207. class CDllInformation
  208. {
  209. public:
  210. CString m_DllName;
  211. CSimpleList<CComInterfaceProxyStub*> m_IfaceProxies;
  212. CSimpleList<CInterfaceInformation*> m_pInterfaces;
  213. HRESULT PopulateFileElement(CSmartPointer<IXMLDOMElement> ptElement);
  214. };
  215. class CManBuilder
  216. {
  217. public:
  218. CManBuilder();
  219. ~CManBuilder() { }
  220. bool Initialize(SIZE_T argc, WCHAR** argv);
  221. bool Run();
  222. protected:
  223. CComClassInformation* FindClassInfoForClsid(CLSID id);
  224. enum {
  225. HK_REDIR_HKLM,
  226. HK_REDIR_HKCU,
  227. HK_REDIR_HKCR,
  228. HK_REDIR_HKCC,
  229. HK_REDIR_HKU,
  230. HK_REDIR_HKPD,
  231. HK_REDIR_BASE_KEY,
  232. HK_REDIR_COUNT
  233. };
  234. enum ErrorLevel {
  235. ePlProgress = 0x01,
  236. ePlWarning = 0x02,
  237. ePlError = 0x04,
  238. ePlSpew = 0x08
  239. };
  240. ErrorLevel m_plPrintLevel;
  241. bool m_fAddCopyrightData;
  242. bool DispUsage();
  243. bool Display(ErrorLevel pl, PCWSTR Format, ...);
  244. bool ProcessDllEntry(CSmartPointer<IXMLDOMElement> ptFileTargetElement);
  245. bool FindFileDataFor(
  246. const CString& FileName,
  247. CSmartPointer<IXMLDOMElement> ptDocumentRoot,
  248. CSmartPointer<IXMLDOMElement> &ptFileNode,
  249. bool fAddIfNotPresent = false);
  250. CString m_ManifestFilename;
  251. CString m_TlbBaseName;
  252. CString m_strRegistryRootKey;
  253. CSimpleList<CString> m_Parameters;
  254. CSimpleList<CString> m_IdentityBlob;
  255. CSimpleList<CString> m_InputDllListing;
  256. CSimpleList<CComClassInformation*> m_ComClassData;
  257. CSimpleList<CTlbInformation*> m_TlbInfo;
  258. CSimpleList<CInterfaceInformation> m_FoundInterfaces;
  259. CSimpleList<CComInterfaceProxyStub*> m_ExternalProxies;
  260. CSimpleList<CWindowClass*> m_WindowClasses;
  261. bool m_fUseRegistryData, m_fTestCreation;
  262. CSimpleMap<CString, CDllInformation> m_DllInformation;
  263. bool ConstructEmptyAssemblyManifest(CSmartPointer<IXMLDOMDocument2> ptDocument);
  264. void PrintXML(CSmartPointer<IDispatch> ptUnk);
  265. void DisplayErrorInfo(CSmartPointer<ISupportErrorInfo> iErrorInfo);
  266. bool UpdateManifestWithData(CSmartPointer<IXMLDOMDocument> ptDocument);
  267. bool RegServerDll(CString ptFileElement);
  268. bool GatherRegistryData();
  269. bool EasyGetRegValue(HKEY hkRoot, PCWSTR pcwszSubKeyName, PCWSTR pcwszValueName, CString &OutValue, bool &fFound);
  270. void DisplayParams();
  271. bool FindWindowClasses();
  272. //
  273. // Look up what DLL owns this clsid
  274. //
  275. CString FindOwningClsid(CString& clsid);
  276. bool AddInterface(CDllInformation &dll, CSmartPointer<ITypeInfo> ptTypeInfo);
  277. };
  278. CComClassInformation*
  279. CManBuilder::FindClassInfoForClsid(CLSID id)
  280. {
  281. for (SIZE_T c = 0; c < this->m_ComClassData.Size(); c++)
  282. {
  283. if (m_ComClassData[c]->m_ObjectIdent == id)
  284. return m_ComClassData[c];
  285. }
  286. return NULL;
  287. }
  288. bool
  289. CManBuilder::FindWindowClasses()
  290. {
  291. HMODULE hmUser32 = NULL;
  292. UINT uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  293. if (GetModuleHandleW(L"user32.dll") == 0)
  294. {
  295. hmUser32 = LoadLibraryW(L"user32.dll");
  296. }
  297. //
  298. // For this DLL, run through all its objects and see
  299. // if they can be activated..
  300. //
  301. for (SIZE_T c = 0; c < m_InputDllListing.Size(); c++)
  302. {
  303. /*
  304. // no need to do this again, all entries in the list has already been registered.
  305. //
  306. CString &dll = m_InputDllListing[c];
  307. HMODULE hmThisDll = NULL;
  308. hmThisDll = LoadLibraryW(dll);
  309. if (hmThisDll == NULL)
  310. {
  311. Display(ePlProgress, L"Unable to loadlibrary %ls - can't sniff window classes.\r\n",
  312. static_cast<PCWSTR>(dll));
  313. }
  314. else
  315. {
  316. FreeLibrary(hmThisDll);
  317. }
  318. */
  319. CSimpleList<CString> Classes;
  320. User32Trampolines::GetRedirectedStrings(Classes);
  321. User32Trampolines::ClearRedirections();
  322. for (SIZE_T i = 0; i < Classes.Size(); i++)
  323. {
  324. CWindowClass *pClass = new CWindowClass;
  325. PCWSTR pcwsz = wcsrchr(m_InputDllListing[c], L'\\');
  326. if (pcwsz)
  327. pClass->m_SourceDll = pcwsz + wcsspn(pcwsz, L"\\//");
  328. else
  329. pClass->m_SourceDll = m_InputDllListing[c];
  330. pClass->m_WindowClass = Classes[i];
  331. this->m_WindowClasses.Append(pClass);
  332. }
  333. }
  334. if (hmUser32) FreeLibrary(hmUser32);
  335. SetErrorMode(uiErrorMode);
  336. return true;
  337. }
  338. bool
  339. CManBuilder::EasyGetRegValue(
  340. HKEY hkRoot,
  341. PCWSTR pcwszSubKeyName,
  342. PCWSTR pcwszValueName,
  343. CString &OutValue,
  344. bool &fFound
  345. )
  346. {
  347. OutValue = L"";
  348. HKEY hkSubKey = NULL;
  349. bool fProblems = false;
  350. ULONG ulError;
  351. fFound = false;
  352. if (0 == (ulError = RegOpenKeyW(hkRoot, pcwszSubKeyName, &hkSubKey)))
  353. {
  354. PBYTE pbData = NULL;
  355. DWORD cbdwData = 0;
  356. DWORD dwType;
  357. while (true)
  358. {
  359. DWORD dwErr = RegQueryValueExW(hkSubKey, pcwszValueName, NULL, &dwType, pbData, &cbdwData);
  360. if ((dwErr == ERROR_SUCCESS) && (pbData != NULL))
  361. {
  362. OutValue = (PWSTR)pbData;
  363. fFound = true;
  364. break;
  365. }
  366. else if ((dwErr == ERROR_MORE_DATA) || ((dwErr == ERROR_SUCCESS) && (pbData == NULL)))
  367. {
  368. if (pbData)
  369. {
  370. delete[] pbData;
  371. }
  372. pbData = new BYTE[cbdwData+1];
  373. continue;
  374. }
  375. else if ((dwErr == ERROR_FILE_NOT_FOUND) || (dwErr == ERROR_PATH_NOT_FOUND))
  376. {
  377. break;
  378. }
  379. else
  380. {
  381. fProblems = true;
  382. break;
  383. }
  384. }
  385. if (pbData)
  386. {
  387. delete[] pbData;
  388. pbData = NULL;
  389. }
  390. RegCloseKey(hkSubKey);
  391. }
  392. return !fProblems;
  393. }
  394. bool
  395. CManBuilder::GatherRegistryData()
  396. {
  397. CSimpleList<CString> FoundFiles;
  398. //
  399. // Look at HKEY_CLASSES_ROOT\CLSID - it contains the list of clsids that we should
  400. // be adding to the manifest.
  401. //
  402. CString PathBuilder;
  403. WCHAR wchKeyName[MAX_PATH];
  404. DWORD dwIndex = 0;
  405. ULONG ulError;
  406. DWORD cbDataLength;
  407. HKEY hkIterationKey;
  408. ulError = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_ENUMERATE_SUB_KEYS, &hkIterationKey);
  409. while (ulError == ERROR_SUCCESS)
  410. {
  411. HKEY hkThisClass = NULL;
  412. CString WorkerValue;
  413. bool fPresent, fOk, fCreatedInfo = false;
  414. CComClassInformation *pThisClass;
  415. CLSID FoundClsid;
  416. ulError = RegEnumKeyExW(hkIterationKey, dwIndex++, wchKeyName, &(cbDataLength = sizeof(wchKeyName)), NULL, NULL, NULL, NULL);
  417. if (ulError != ERROR_SUCCESS)
  418. break;
  419. //
  420. // Conversion to a clsid failed? Hmm, but continue.
  421. //
  422. if (FAILED(CLSIDFromString(wchKeyName, &FoundClsid)))
  423. continue;
  424. //
  425. // Find the existing class data to match up with. Otherwise, create a new
  426. // entity and add it to the list.
  427. //
  428. pThisClass = FindClassInfoForClsid(FoundClsid);
  429. if (pThisClass == NULL) {
  430. pThisClass = new CComClassInformation();
  431. pThisClass->m_ObjectIdent = FoundClsid;
  432. fCreatedInfo = true;
  433. }
  434. //
  435. // Description of the class
  436. //
  437. fOk = EasyGetRegValue(hkIterationKey, wchKeyName, NULL, WorkerValue, fPresent);
  438. if (fOk && fPresent)
  439. {
  440. pThisClass->m_Description = WorkerValue;
  441. }
  442. //
  443. // Now that we've got this subkey, let's go open it and do a little inspection on it.
  444. //
  445. ulError = RegOpenKeyExW(hkIterationKey, wchKeyName, 0, KEY_READ, &hkThisClass);
  446. if (ulError == ERROR_SUCCESS)
  447. {
  448. //
  449. // Get the version-independent prog id for this class
  450. //
  451. fOk = EasyGetRegValue(hkThisClass, L"VersionIndependentProgID", NULL, WorkerValue, fPresent);
  452. if (fOk && fPresent)
  453. {
  454. pThisClass->m_VersionIndependentProgId = WorkerValue;
  455. }
  456. //
  457. // Get the non-independent one
  458. //
  459. fOk = EasyGetRegValue(hkThisClass, L"ProgID", NULL, WorkerValue, fPresent);
  460. if (fOk && fPresent)
  461. {
  462. pThisClass->AddProgId(WorkerValue);
  463. }
  464. //
  465. // Get ourselves a threading model
  466. //
  467. fOk = EasyGetRegValue(hkThisClass, L"InprocServer32", L"ThreadingModel", WorkerValue, fPresent);
  468. if (fOk && fPresent)
  469. {
  470. pThisClass->m_ThreadingModel = WorkerValue;
  471. }
  472. //
  473. // And find the class's registered inproc server
  474. //
  475. fOk = EasyGetRegValue(hkThisClass, L"InprocServer32", NULL, WorkerValue, fPresent);
  476. if (fOk && fPresent)
  477. {
  478. //
  479. // Fix up this path - we need just the file name bit, we don't care about the
  480. // remainder of the path.
  481. //
  482. PWSTR pwszLastSlash = wcsrchr(WorkerValue, L'\\');
  483. if (pwszLastSlash == NULL)
  484. pwszLastSlash = wcsrchr(WorkerValue, L'/');
  485. pThisClass->m_DllName = (pwszLastSlash ? pwszLastSlash + 1 : WorkerValue);
  486. }
  487. RegCloseKey(hkThisClass);
  488. hkThisClass = NULL;
  489. }
  490. //
  491. // Found something in the registry that wasn't a creatable class, really..
  492. //
  493. if (fCreatedInfo) {
  494. if (pThisClass->m_DllName.length() != 0)
  495. m_ComClassData.Append(pThisClass);
  496. else
  497. delete pThisClass;
  498. }
  499. }
  500. RegCloseKey(hkIterationKey);
  501. #if 0
  502. while (true)
  503. {
  504. DWORD cbKeyNameLength = sizeof(wchKeyName);
  505. ULONG ulError;
  506. CString Found_Clsid, ProgId;
  507. ulError = RegEnumKeyExW(User32Trampolines::RemapRegKey(HKEY_CLASSES_ROOT), dwIndex++, wchKeyName, &cbKeyNameLength, 0, 0, 0, 0);
  508. if (ulError == ERROR_SUCCESS)
  509. {
  510. //
  511. // Examine this key. Form up the path to it as {keyname}\Clsid. We know that this
  512. // is a version-independent key if {keyname}\curver is present. (The version-dependent
  513. // value should go in the comclsid's <comClass> tag, while the independent goes under
  514. // the <comClass> as a child node.
  515. //
  516. // Not if it's one of the well-known values, though.
  517. //
  518. if ((lstrcmpiW(wchKeyName, L"CLSID") == 0) ||
  519. (lstrcmpiW(wchKeyName, L"Interface") == 0) ||
  520. (lstrcmpiW(wchKeyName, L"TypeLib") == 0))
  521. continue;
  522. CString ProgIdPath = wchKeyName + CString(L"\\Clsid");
  523. CString ClsidFound;
  524. bool fFound = false;
  525. CComClassInformation *pCInfo = NULL;
  526. EasyGetRegValue(User32Trampolines::RemapRegKey(HKEY_CLASSES_ROOT), ProgIdPath, NULL, ClsidFound, fFound);
  527. if (fFound)
  528. {
  529. CLSID id;
  530. CLSIDFromString(ClsidFound, &id);
  531. if ((pCInfo = FindClassInfoForClsid(id)) != NULL)
  532. {
  533. pCInfo->m_ProgIdListing.Append(CString(wchKeyName));
  534. }
  535. }
  536. }
  537. else
  538. {
  539. if (ulError != ERROR_NO_MORE_ITEMS)
  540. Display(ePlError, L"Error 0x%08lx (%l) enumerating redirected HKEY_CLASSES_ROOT.\r\n",
  541. ulError, ulError);
  542. break;
  543. }
  544. }
  545. #endif
  546. //
  547. // And let's go look at all the interfaces that were in the tlb
  548. //
  549. this->m_DllInformation.GetKeys(FoundFiles);
  550. for (SIZE_T c = 0; c < FoundFiles.Size(); c++)
  551. {
  552. CDllInformation &minfo = this->m_DllInformation[FoundFiles[c]];
  553. for (SIZE_T f = 0; f < minfo.m_pInterfaces.Size(); f++)
  554. {
  555. CInterfaceInformation* pInfo = minfo.m_pInterfaces[f];
  556. CComClassInformation* pComClass = NULL;
  557. //
  558. // Already found this one a home?
  559. //
  560. if (pInfo->m_fUsed) continue;
  561. Display(ePlSpew, L"Looking for pstub %ls (%ls)\r\n",
  562. static_cast<PCWSTR>(StringFromCLSID(pInfo->m_InterfaceIID)),
  563. static_cast<PCWSTR>(pInfo->m_Name));
  564. //
  565. // First check. Is there a COM class with this IID?
  566. //
  567. if ((pComClass = this->FindClassInfoForClsid(pInfo->m_InterfaceIID)) != NULL)
  568. {
  569. //
  570. // Great. Add an entry for the proxy stub interface to the file tag containing
  571. // the clsid.
  572. //
  573. pInfo->m_fUsed = true;
  574. CComInterfaceProxyStub *pstub = new CComInterfaceProxyStub;
  575. pstub->m_InterfaceId = pInfo->m_InterfaceIID;
  576. pstub->m_StubClsid = pComClass->m_ObjectIdent;
  577. pstub->m_Name = pComClass->m_Name;
  578. pstub->m_TlbId = pComClass->m_TlbIdent;
  579. Display(ePlSpew, L"- Matched to COM class %ls (IID matches guid)\r\n",
  580. static_cast<PCWSTR>(pstub->m_Name));
  581. minfo.m_IfaceProxies.Append(pstub);
  582. }
  583. //
  584. // Otherwise, look in the registry and try to map back to a proxy stub
  585. // clsid.
  586. //
  587. else
  588. {
  589. CString RegPath = L"Interface\\" + StringFromCLSID(pInfo->m_InterfaceIID);
  590. CString FoundClsid;
  591. CString FoundTlbIdent;
  592. bool fFoundClsid, fFoundTlbIdent;
  593. this->EasyGetRegValue(HKEY_CLASSES_ROOT, RegPath + L"\\ProxyStubClsid32", NULL, FoundClsid, fFoundClsid);
  594. this->EasyGetRegValue(HKEY_CLASSES_ROOT, RegPath + L"\\TypeLib", NULL, FoundTlbIdent, fFoundTlbIdent);
  595. if (fFoundClsid)
  596. {
  597. CLSID clsid;
  598. CLSIDFromString(FoundClsid, &clsid);
  599. //
  600. // Now go look and see if we own this clsid.
  601. //
  602. if ((pComClass = FindClassInfoForClsid(clsid)) != NULL)
  603. {
  604. pInfo->m_fUsed = true;
  605. CComInterfaceProxyStub *pStub = new CComInterfaceProxyStub;
  606. pStub->m_InterfaceId = pInfo->m_InterfaceIID;
  607. pStub->m_StubClsid = pComClass->m_ObjectIdent;
  608. pStub->m_Name = pComClass->m_Name;
  609. pStub->m_TlbId = pComClass->m_TlbIdent;
  610. m_DllInformation[pComClass->m_DllName].m_IfaceProxies.Append(pStub);
  611. }
  612. else if (clsid == __uuidof(CPSOAInterface))
  613. {
  614. CComInterfaceProxyStub *pStub = new CComInterfaceProxyStub;
  615. SIZE_T c = 0;
  616. pStub->m_InterfaceId = pInfo->m_InterfaceIID;
  617. pStub->m_StubClsid = __uuidof(CPSOAInterface);
  618. pStub->m_Name = L"Oleaut32 PSOAInterface";
  619. pStub->m_iMethods = 0;
  620. if (fFoundTlbIdent)
  621. CLSIDFromString(FoundTlbIdent, &pStub->m_TlbId);
  622. // This sucks, but it's necessary.
  623. for (c = 0; c < this->m_ExternalProxies.Size(); c++)
  624. {
  625. if (this->m_ExternalProxies[c]->m_InterfaceId == pInfo->m_InterfaceIID)
  626. break;
  627. }
  628. if (c == this->m_ExternalProxies.Size())
  629. {
  630. this->m_ExternalProxies.Append(pStub);
  631. pStub = NULL;
  632. }
  633. if (pStub != NULL)
  634. {
  635. delete pStub;
  636. pStub = NULL;
  637. }
  638. }
  639. }
  640. }
  641. }
  642. }
  643. return true;
  644. }
  645. void
  646. CManBuilder::DisplayErrorInfo(
  647. CSmartPointer<ISupportErrorInfo> iErrorInfo
  648. )
  649. {
  650. if (iErrorInfo == NULL)
  651. {
  652. Display(ePlError, L"No more error information available.\n");
  653. }
  654. else
  655. {
  656. CSmartPointer<IErrorInfo> iInfo;
  657. BSTR bst;
  658. GetErrorInfo(0, &iInfo);
  659. if ((iInfo != NULL) && SUCCEEDED(iInfo->GetDescription(&bst)))
  660. {
  661. Display(ePlError, L"Error: %ls\r\n", static_cast<PCWSTR>(bst));
  662. if (bst)
  663. {
  664. SysFreeString(bst);
  665. bst = NULL;
  666. }
  667. }
  668. }
  669. }
  670. void
  671. CManBuilder::PrintXML(
  672. CSmartPointer<IDispatch> ptDispatch
  673. )
  674. {
  675. if (0)
  676. {
  677. CSmartPointer<IXMLDOMDocument2> ptDoc;
  678. if ((ptDoc = ptDispatch) != NULL)
  679. PrettyFormatXmlDocument(ptDoc);
  680. }
  681. OLECHAR *wchGetXML = L"xml";
  682. DISPID dispid;
  683. if (ptDispatch != NULL)
  684. {
  685. _variant_t vresult;
  686. HRESULT hr;
  687. DISPPARAMS dp = { NULL, NULL, 0, 0 };
  688. EXCEPINFO ei = { 0 };
  689. if (FAILED(ptDispatch->GetIDsOfNames(
  690. IID_NULL,
  691. &wchGetXML,
  692. 1,
  693. LOCALE_SYSTEM_DEFAULT,
  694. &dispid))) return;
  695. hr = ptDispatch->Invoke(
  696. dispid,
  697. IID_NULL,
  698. LOCALE_SYSTEM_DEFAULT,
  699. DISPATCH_PROPERTYGET,
  700. &dp,
  701. &vresult,
  702. &ei,
  703. NULL);
  704. if (SUCCEEDED(hr))
  705. {
  706. Display(
  707. ePlSpew,
  708. L"XML:\r\n%ls\r\n",
  709. static_cast<PCWSTR>((_bstr_t)vresult));
  710. }
  711. }
  712. }
  713. bool
  714. SplitIdentityItem(
  715. const PCWSTR pcwszIdentityString,
  716. CString& ValueName,
  717. CString& ValueValue
  718. )
  719. {
  720. ValueName = ValueValue = L"";
  721. PWSTR pwszClone = new WCHAR[lstrlenW(pcwszIdentityString) + 1];
  722. PWSTR pwszEquals, pwszValue;
  723. wcscpy(pwszClone, pcwszIdentityString);
  724. pwszEquals = wcschr(pwszClone, L'=');
  725. pwszValue = CharNextW(pwszEquals);
  726. if (pwszEquals == NULL) return false;
  727. *pwszEquals = UNICODE_NULL;
  728. ValueName = pwszClone;
  729. ValueValue = pwszValue;
  730. return true;
  731. }
  732. bool
  733. CManBuilder::ConstructEmptyAssemblyManifest(
  734. CSmartPointer<IXMLDOMDocument2> ptDocument
  735. )
  736. {
  737. //
  738. // Remove /everything/ from the document.
  739. //
  740. CSmartPointer<IXMLDOMProcessingInstruction> Processing;
  741. CSmartPointer<IXMLDOMNode> AssemblyRootNode;
  742. CSmartPointer<IXMLDOMElement> AssemblyRootElement;
  743. VARIANT vt;
  744. HRESULT hr;
  745. // Create a processing instruction - <?xml version="1.0"?>
  746. hr = ptDocument->createProcessingInstruction(
  747. _bstr_t(L"xml"),
  748. _bstr_t(L"version='1.0' encoding='UTF-8' standalone='yes'"),
  749. &Processing);
  750. if (FAILED(hr))
  751. return false;
  752. // And add it
  753. if (FAILED(ptDocument->appendChild(Processing, NULL)))
  754. return false;
  755. //
  756. // If we're supposed to be injecting the MS copyright, do so
  757. //
  758. if (m_fAddCopyrightData)
  759. {
  760. CSmartPointer<IXMLDOMComment> CopyrightComment;
  761. hr = ptDocument->createComment(STR_MS_COMMENT_COPYRIGHT, &CopyrightComment);
  762. if (FAILED(hr))
  763. return false;
  764. if (FAILED(hr = ptDocument->appendChild(CopyrightComment, NULL)))
  765. return false;
  766. }
  767. //
  768. // Create the <assembly> root element.
  769. //
  770. vt.vt = VT_INT;
  771. vt.intVal = NODE_ELEMENT;
  772. if (FAILED(ptDocument->createNode(
  773. vt,
  774. _bstr_t(L"assembly"),
  775. _bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
  776. &AssemblyRootNode)))
  777. return false;
  778. if ((AssemblyRootElement = AssemblyRootNode) == NULL)
  779. return false;
  780. if (FAILED(AssemblyRootElement->setAttribute(CString(L"manifestVersion"), _variant_t(L"1.0"))))
  781. return false;
  782. if (FAILED(ptDocument->putref_documentElement(AssemblyRootElement)))
  783. return false;
  784. //
  785. // Construct the identity tag if possible
  786. //
  787. if (this->m_IdentityBlob.Size())
  788. {
  789. CSmartPointer<IXMLDOMNode> ptIdentityNode;
  790. CSmartPointer<IXMLDOMElement> ptIdentity;
  791. CSmartPointer<IXMLDOMElement> ptDocRoot;
  792. hr = ptDocument->createNode(
  793. vt,
  794. _bstr_t(L"assemblyIdentity"),
  795. _bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
  796. &ptIdentityNode);
  797. if (FAILED(hr) || ((ptIdentity = ptIdentityNode) == NULL))
  798. {
  799. Display(ePlError, L"Can't create assemblyIdentity node!\r\n");
  800. DisplayErrorInfo(ptDocument);
  801. }
  802. else
  803. {
  804. //
  805. // For each identity pair that was passed in, decide on
  806. // the name and the value components.
  807. //
  808. CString strName, strValue;
  809. for (SIZE_T sz = 0; sz < m_IdentityBlob.Size(); sz++)
  810. {
  811. if (!SplitIdentityItem(m_IdentityBlob[sz], strName, strValue))
  812. {
  813. Display(ePlError, L"Unable to interpret identity pair '%ls'\r\n",
  814. static_cast<PCWSTR>(m_IdentityBlob[sz]));
  815. }
  816. else if (FAILED(hr = ptIdentity->setAttribute(strName, _variant_t(strValue))))
  817. {
  818. Display(ePlError, L"Unable to set attribute pair %ls = '%ls'\r\n",
  819. static_cast<PCWSTR>(strName),
  820. static_cast<PCWSTR>(strValue));
  821. DisplayErrorInfo(ptIdentity);
  822. }
  823. }
  824. }
  825. hr = ptDocument->get_documentElement(&ptDocRoot);
  826. hr = ptDocRoot->appendChild(ptIdentityNode, NULL);
  827. }
  828. PrintXML(ptDocument);
  829. return true;
  830. }
  831. CString
  832. FormatVersion(DWORD dwMaj, DWORD dwMin)
  833. {
  834. WCHAR wchBuffer[200];
  835. _snwprintf(wchBuffer, 200, L"%d.%d", dwMaj, dwMin);
  836. return CString(wchBuffer);
  837. }
  838. CString
  839. StringFromCLSID(REFCLSID rclsid)
  840. {
  841. PWSTR pwsz = NULL;
  842. HRESULT hr;
  843. CString rvalue = L"(unknown)";
  844. hr = StringFromCLSID(rclsid, &pwsz);
  845. if (pwsz)
  846. {
  847. rvalue = pwsz;
  848. CoTaskMemFree(pwsz);
  849. pwsz = NULL;
  850. }
  851. return rvalue;
  852. }
  853. BOOL CALLBACK
  854. EnumTypeLibsFunc(
  855. HMODULE hModule,
  856. LPCWSTR lpType,
  857. LPWSTR lpName,
  858. LONG_PTR lp
  859. )
  860. {
  861. static WCHAR wchBuiltFilePath[MAX_PATH*2];
  862. CString tgt;
  863. if ((UINT)lpName < 0xFFFF)
  864. {
  865. wsprintfW(wchBuiltFilePath, L"%d", (UINT)lpName);
  866. tgt = wchBuiltFilePath;
  867. }
  868. else
  869. {
  870. tgt = lpName;
  871. }
  872. ((CSimpleList<CString>*)lp)->Append(tgt);
  873. return TRUE;
  874. }
  875. bool
  876. CManBuilder::ProcessDllEntry(
  877. CSmartPointer<IXMLDOMElement> ptFileElement
  878. )
  879. {
  880. _variant_t vtFileName;
  881. CSimpleList<CString> ResourceIdentList;
  882. HMODULE hmDll = NULL;
  883. CString dll;
  884. if (FAILED(ptFileElement->getAttribute(_bstr_t(L"name"), &vtFileName)))
  885. return false;
  886. // instead using the pure dll filename, find the real path of this file,
  887. dll = static_cast<_bstr_t>(vtFileName);
  888. SIZE_T len = (static_cast<_bstr_t>(vtFileName)).length();
  889. for (SIZE_T c = 0; c < m_InputDllListing.Size(); c++)
  890. {
  891. if (m_InputDllListing[c].length()>= len)
  892. {
  893. PCWSTR pstr = wcsstr(m_InputDllListing[c], (PWSTR)(static_cast<_bstr_t>(vtFileName)));
  894. if ((pstr != NULL) && (wcslen(pstr) == len))
  895. {
  896. dll = m_InputDllListing[c];
  897. break;
  898. }
  899. }
  900. }
  901. //
  902. // Gather all the resource idents of TYPELIB resources
  903. //
  904. hmDll = LoadLibraryExW(dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
  905. if (hmDll == NULL)
  906. {
  907. ResourceIdentList.Append(CString(L""));
  908. Display(ePlWarning, L"Warning - %ls can not been loaded, ResourceIdentList is appended with an empty string.\n",
  909. static_cast<PCWSTR>(dll));
  910. }
  911. else
  912. {
  913. EnumResourceNamesW(
  914. hmDll,
  915. L"TYPELIB",
  916. EnumTypeLibsFunc,
  917. (LONG_PTR)&ResourceIdentList);
  918. }
  919. //
  920. // If there were no resource idents, then just do a single pass
  921. //
  922. for (SIZE_T sz = 0; sz < ResourceIdentList.Size(); sz++)
  923. {
  924. CSmartPointer<ITypeLib> ptTypeLibrary;
  925. CString strGuidString;
  926. CString strLoadTypeLibParam;
  927. UINT uiTypeInfoCount;
  928. TLIBATTR *pLibAttr;
  929. CTlbInformation* tlbInfo;
  930. bool fSetResourceIdent = false;
  931. CDllInformation &dllInfo = this->m_DllInformation[CString(vtFileName)];
  932. tlbInfo = new CTlbInformation();
  933. //
  934. // The "blank" string is a placeholder so that we know that the file in question
  935. // may not be a loadable dll.
  936. //
  937. if (ResourceIdentList[sz].length() == 0)
  938. {
  939. strLoadTypeLibParam = static_cast<_bstr_t>(vtFileName);
  940. }
  941. //
  942. // Otherwise, the ResourceIdentList contains the resourceID of the typelibrary
  943. // in question.
  944. //
  945. else
  946. {
  947. strLoadTypeLibParam = dll + CString(L"\\") + ResourceIdentList[sz];
  948. tlbInfo->m_ResourceIdent = ResourceIdentList[sz];
  949. }
  950. tlbInfo->m_SourceFile = dll;
  951. if (FAILED(LoadTypeLibEx(strLoadTypeLibParam, REGKIND_NONE, &ptTypeLibrary)))
  952. continue;
  953. //
  954. // Now look through the tlb and see what there is to see.. Assume all CoClasses found
  955. // in the typelib are implemented for this dll.
  956. //
  957. uiTypeInfoCount = ptTypeLibrary->GetTypeInfoCount();
  958. if (FAILED(ptTypeLibrary->GetLibAttr(&pLibAttr)))
  959. continue;
  960. Display(ePlProgress, L"Found type library in file %ls, guid %ls (contains %d types)\n",
  961. static_cast<PCWSTR>(_bstr_t(vtFileName)),
  962. static_cast<PCWSTR>(StringFromCLSID(pLibAttr->guid)),
  963. uiTypeInfoCount);
  964. tlbInfo->m_Ident = pLibAttr->guid;
  965. tlbInfo->m_Version[0] = pLibAttr->wMajorVerNum;
  966. tlbInfo->m_Version[1] = pLibAttr->wMinorVerNum;
  967. m_TlbInfo.Append(tlbInfo);
  968. for (UINT ui = 0; ui < uiTypeInfoCount; ui++)
  969. {
  970. CSmartPointer<ITypeInfo> ptTypeInfo;
  971. BSTR rawbstTypeName;
  972. BSTR rawbstDocumentation;
  973. CString strTypeName;
  974. CString strDocumentation;
  975. TYPEKIND tk;
  976. TYPEATTR *pTypeAttr = NULL;
  977. if (FAILED(ptTypeLibrary->GetTypeInfoType(ui, &tk)))
  978. continue;
  979. if (FAILED(ptTypeLibrary->GetTypeInfo(ui, &ptTypeInfo)))
  980. continue;
  981. if (FAILED(ptTypeInfo->GetTypeAttr(&pTypeAttr)))
  982. continue;
  983. //
  984. // Get a little documentation
  985. //
  986. if (SUCCEEDED(ptTypeLibrary->GetDocumentation(
  987. ui,
  988. &rawbstTypeName,
  989. &rawbstDocumentation,
  990. NULL,
  991. NULL)))
  992. {
  993. if (rawbstTypeName != NULL)
  994. {
  995. strTypeName = _bstr_t(rawbstTypeName, FALSE);
  996. rawbstTypeName = NULL;
  997. }
  998. if (rawbstDocumentation != NULL)
  999. {
  1000. strDocumentation = _bstr_t(rawbstDocumentation, FALSE);
  1001. rawbstDocumentation = NULL;
  1002. }
  1003. }
  1004. if (pTypeAttr->wTypeFlags & TYPEFLAG_FDUAL)
  1005. {
  1006. if (tk == TKIND_DISPATCH)
  1007. {
  1008. CSmartPointer<ITypeInfo> ptDispInfo;
  1009. HREFTYPE hrTypeInfo;
  1010. if (SUCCEEDED(ptTypeInfo->GetRefTypeOfImplType((UINT)-1, &hrTypeInfo)))
  1011. if (SUCCEEDED(ptTypeInfo->GetRefTypeInfo(hrTypeInfo, &ptDispInfo)))
  1012. this->AddInterface(dllInfo, ptDispInfo);
  1013. }
  1014. else if (tk == TKIND_INTERFACE)
  1015. {
  1016. this->AddInterface(dllInfo, ptTypeInfo);
  1017. }
  1018. }
  1019. if (tk == TKIND_COCLASS)
  1020. {
  1021. CComClassInformation *pClassInfo = NULL;
  1022. bool fCreated = false;
  1023. pClassInfo = FindClassInfoForClsid(pTypeAttr->guid);
  1024. if (pClassInfo == NULL)
  1025. {
  1026. pClassInfo = new CComClassInformation;
  1027. m_ComClassData.Append(pClassInfo);
  1028. }
  1029. pClassInfo->m_Description = strDocumentation;
  1030. pClassInfo->m_ObjectIdent = pTypeAttr->guid;
  1031. pClassInfo->m_Name = strTypeName;
  1032. pClassInfo->m_TlbIdent = pLibAttr->guid;
  1033. }
  1034. else if (tk == TKIND_INTERFACE)
  1035. {
  1036. this->AddInterface(dllInfo, ptTypeInfo);
  1037. }
  1038. if (pTypeAttr != NULL)
  1039. {
  1040. ptTypeInfo->ReleaseTypeAttr(pTypeAttr);
  1041. pTypeAttr = NULL;
  1042. }
  1043. }
  1044. }
  1045. if (hmDll)
  1046. {
  1047. FreeLibrary(hmDll);
  1048. hmDll = NULL;
  1049. }
  1050. return true;
  1051. }
  1052. bool
  1053. CManBuilder::AddInterface(
  1054. CDllInformation &dll,
  1055. CSmartPointer<ITypeInfo> ptTypeInfo
  1056. )
  1057. {
  1058. CInterfaceInformation *pInterface = NULL;
  1059. TYPEATTR *pTypeAttr = NULL;
  1060. BSTR bstName = NULL, bstDocumentation = NULL;
  1061. bool fRVal = false;
  1062. if (SUCCEEDED(ptTypeInfo->GetTypeAttr(&pTypeAttr)))
  1063. {
  1064. if (SUCCEEDED(ptTypeInfo->GetDocumentation(MEMBERID_NIL, &bstName, &bstDocumentation, NULL, NULL)))
  1065. {
  1066. pInterface = new CInterfaceInformation;
  1067. pInterface->m_InterfaceIID = pTypeAttr->guid;
  1068. pInterface->m_Name = bstName;
  1069. dll.m_pInterfaces.Append(pInterface);
  1070. Display(ePlSpew, L"Found interface %ls '%ls'\r\n",
  1071. static_cast<PCWSTR>(StringFromCLSID(pTypeAttr->guid)),
  1072. bstName);
  1073. fRVal = true;
  1074. }
  1075. }
  1076. if (bstName) ::SysFreeString(bstName);
  1077. if (bstDocumentation) ::SysFreeString(bstDocumentation);
  1078. if (pTypeAttr) ptTypeInfo->ReleaseTypeAttr(pTypeAttr);
  1079. return fRVal;
  1080. }
  1081. bool
  1082. CManBuilder::FindFileDataFor(
  1083. const CString & FileName,
  1084. CSmartPointer < IXMLDOMElement > ptDocumentRoot,
  1085. CSmartPointer < IXMLDOMElement > & ptFileElementFound,
  1086. bool fAddIfNotPresent
  1087. )
  1088. {
  1089. HRESULT hr;
  1090. CSmartPointer<IXMLDOMNode> ptFoundNode;
  1091. /*
  1092. const _bstr_t bstSearchPattern =
  1093. _bstr_t(L"/" STR_ASM_NS L":assembly/" STR_ASM_NS L":file[@name = '")
  1094. + _bstr_t(FileName)
  1095. + _bstr_t(L"']");
  1096. */
  1097. CString StrippedName;
  1098. PCWSTR pcwsz;
  1099. //
  1100. // If the file name contains a slash of some sort, we need to get
  1101. // just the file name and not the path.
  1102. //
  1103. pcwsz = wcsrchr(FileName, L'\\');
  1104. if (pcwsz)
  1105. {
  1106. StrippedName = pcwsz + wcsspn(pcwsz, L"\\");
  1107. }
  1108. else
  1109. {
  1110. StrippedName = FileName;
  1111. }
  1112. _bstr_t bstSearchPattern =
  1113. _bstr_t(L"/" STR_ASM_NS L":assembly/" STR_ASM_NS L":file[@name = '")
  1114. + _bstr_t(StrippedName)
  1115. + _bstr_t(L"']");
  1116. if (ptFileElementFound != NULL)
  1117. ptFileElementFound.Release();
  1118. //
  1119. // Use single-select, since there should only be one entry that matches the
  1120. // above pattern anyhow.
  1121. //
  1122. if (SUCCEEDED(hr = ptDocumentRoot->selectSingleNode(bstSearchPattern, &ptFoundNode)))
  1123. {
  1124. //
  1125. // Convert from an IXMLDOMNode to an IXMLDOMElement
  1126. //
  1127. if ((ptFileElementFound = ptFoundNode) != NULL)
  1128. {
  1129. return true;
  1130. }
  1131. }
  1132. else
  1133. {
  1134. DisplayErrorInfo(ptDocumentRoot);
  1135. }
  1136. if (fAddIfNotPresent)
  1137. {
  1138. //
  1139. // Create a new file node and insert it as the child of the document
  1140. // root. Print the XML just so we can see what it current is...
  1141. //
  1142. CSmartPointer<IXMLDOMDocument> ptDocument;
  1143. CSmartPointer<IXMLDOMNode> ptCreatedNode;
  1144. CSmartPointer<IXMLDOMElement> ptCreatedFileTag;
  1145. CSmartPointer<IXMLDOMNode> ptNodeInDocument;
  1146. VARIANT vt;
  1147. vt.vt = VT_INT;
  1148. vt.intVal = NODE_ELEMENT;
  1149. if (FAILED(ptDocumentRoot->get_ownerDocument(&ptDocument)))
  1150. return false;
  1151. //
  1152. // Create the file element (element = 'tag')
  1153. //
  1154. if (FAILED(ptDocument->createNode(
  1155. vt,
  1156. _bstr_t(STR_FILE_TAG_NAME),
  1157. _bstr_t(STR_ASSEMBLY_MANIFEST_NAMESPACE),
  1158. &ptCreatedNode)))
  1159. return false;
  1160. //
  1161. // Convert the 'node' (base xml type) to an 'element' (tag)
  1162. //
  1163. if ((ptCreatedFileTag = ptCreatedNode) == NULL)
  1164. {
  1165. return false;
  1166. }
  1167. if (FAILED(ptCreatedFileTag->setAttribute(
  1168. _bstr_t(L"name"),
  1169. _variant_t(_bstr_t(StrippedName)))))
  1170. {
  1171. return false;
  1172. }
  1173. if (FAILED(ptDocumentRoot->appendChild(ptCreatedNode, &ptNodeInDocument)))
  1174. return false;
  1175. return ((ptFileElementFound = ptNodeInDocument) != NULL);
  1176. }
  1177. return true;
  1178. }
  1179. CManBuilder::CManBuilder() : m_fAddCopyrightData(false), m_fUseRegistryData(false), m_fTestCreation(false), m_plPrintLevel(ePlProgress)
  1180. {
  1181. }
  1182. bool
  1183. CManBuilder::Display(ErrorLevel pl, PCWSTR format, ...)
  1184. {
  1185. if ((pl & m_plPrintLevel) == 0)
  1186. return true;
  1187. va_list va;
  1188. va_start(va, format);
  1189. vwprintf(format, va);
  1190. va_end(va);
  1191. return true;
  1192. }
  1193. bool
  1194. CManBuilder::RegServerDll(
  1195. CString strDllName
  1196. )
  1197. {
  1198. UINT uiMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1199. bool fReturnValue = true;
  1200. HMODULE hmModule = LoadLibraryW(strDllName);
  1201. if (hmModule != NULL)
  1202. {
  1203. typedef HRESULT (STDAPICALLTYPE *tpfnRegisterServer)();
  1204. tpfnRegisterServer pfnRegisterServer;
  1205. pfnRegisterServer = (tpfnRegisterServer)GetProcAddress(hmModule, "DllRegisterServer");
  1206. if (pfnRegisterServer != NULL)
  1207. {
  1208. pfnRegisterServer();
  1209. }
  1210. FreeLibrary(hmModule);
  1211. }else
  1212. {
  1213. Display(ePlError, L"%ls could not be loaded, can not call DllRegisterServer.\n", (PCWSTR)strDllName);
  1214. fReturnValue = false;
  1215. }
  1216. SetErrorMode(uiMode);
  1217. return fReturnValue;
  1218. }
  1219. bool
  1220. CManBuilder::Run()
  1221. {
  1222. bool fOk = true;
  1223. CSmartPointer<IXMLDOMDocument2> ptDocument;
  1224. CSmartPointer<ITypeLib2> ptBaseTypeLibrary;
  1225. CSmartPointer<IXMLDOMElement> ptDocumentRoot;
  1226. CSmartPointer<IXMLDOMNodeList> ptFileElements;
  1227. HRESULT hr;
  1228. //
  1229. // Create the XML document. Assume the user has MSXML 3 or better.
  1230. //
  1231. if (FAILED(hr = ptDocument.CreateInstance(CLSID_DOMDocument30)))
  1232. {
  1233. Display(ePlError, L"Unable to create instance of XML DOM, can't continue\n");
  1234. return false;
  1235. }
  1236. hr = ptDocument->setProperty(_bstr_t(L"SelectionLanguage"), _variant_t(_bstr_t(L"XPath")));
  1237. hr = ptDocument->setProperty(_bstr_t(L"SelectionNamespaces"), _variant_t(_bstr_t(SELECTION_NAMESPACES)));
  1238. ConstructEmptyAssemblyManifest(ptDocument);
  1239. //
  1240. // Get the document element - the <assembly> tag.
  1241. //
  1242. if (FAILED(ptDocument->get_documentElement(&ptDocumentRoot)))
  1243. {
  1244. Display(ePlError, L"Unable to get the document base element for this XML file. Bad XML?\n");
  1245. return false;
  1246. }
  1247. User32Trampolines::Initialize();
  1248. //
  1249. // Ensure there's file tags for the listed files on the -dlls parameter.
  1250. // If an entry is missing, add it.
  1251. //
  1252. for (SIZE_T sz = 0; sz < m_InputDllListing.Size(); sz++)
  1253. {
  1254. CSmartPointer<IXMLDOMElement> SingleFileNode;
  1255. this->FindFileDataFor(m_InputDllListing[sz], ptDocumentRoot, SingleFileNode, true);
  1256. if (m_fUseRegistryData)
  1257. {
  1258. if ( false == RegServerDll(m_InputDllListing[sz]))
  1259. {
  1260. Display(ePlError, L"%ls could not be Registered.\n", (PCWSTR)m_InputDllListing[sz]);
  1261. return false;
  1262. }
  1263. }
  1264. }
  1265. //
  1266. // First pass is to load all the files in the manifest, then go and
  1267. // think that they might contain type information.
  1268. //
  1269. if (SUCCEEDED(ptDocumentRoot->selectNodes(_bstr_t(STR_FILESEARCH_PATTERN), &ptFileElements)))
  1270. {
  1271. CSmartPointer<IXMLDOMNode> ptSingleFileNode;
  1272. while (SUCCEEDED(ptFileElements->nextNode(&ptSingleFileNode)))
  1273. {
  1274. if (ptSingleFileNode == NULL)
  1275. break;
  1276. //
  1277. // This will load the TLB from the DLL, and do all the Right Things
  1278. // in terms of getting the TLB information into the right file nodes
  1279. // (assuming they're not already in those file nodes..)
  1280. //
  1281. ProcessDllEntry(ptSingleFileNode);
  1282. //
  1283. // The one above will get released, but the one for the nextNode
  1284. // iteration is outside of the scope and should be nuked - do
  1285. // that here before the next loop.
  1286. //
  1287. ptSingleFileNode.Release();
  1288. }
  1289. }
  1290. //
  1291. // Were we to look at the registry data? Fine, then let's go and look it all up.
  1292. //
  1293. if (this->m_fUseRegistryData)
  1294. {
  1295. GatherRegistryData();
  1296. }
  1297. //
  1298. // Now let's determine what DLLs actually expose the com classes we found. It is
  1299. // an error to expose a com class via a tlb that's not actually available from one
  1300. // of the DLLs listed.
  1301. //
  1302. {
  1303. SIZE_T iComClass = 0;
  1304. typedef HRESULT (__stdcall *pfnDllGetClassObject)(REFCLSID, REFIID, LPVOID*);
  1305. UINT uiErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1306. class CDllPairing
  1307. {
  1308. public:
  1309. CString DllName;
  1310. pfnDllGetClassObject pfnDGCO;
  1311. HMODULE hmModule;
  1312. CDllPairing() : hmModule(NULL), pfnDGCO(NULL) { }
  1313. ~CDllPairing() { if (hmModule) { FreeLibrary(hmModule); hmModule = NULL; } }
  1314. };
  1315. SIZE_T cDllCount = this->m_DllInformation.Size();
  1316. CDllPairing *Dlls = new CDllPairing[cDllCount];
  1317. CDllPairing *pHere = Dlls;
  1318. for (m_DllInformation.Reset(); m_DllInformation.More(); m_DllInformation.Next())
  1319. {
  1320. pHere->DllName = m_DllInformation.CurrentKey();
  1321. pHere->hmModule = LoadLibraryW(pHere->DllName);
  1322. if (pHere->hmModule != NULL)
  1323. {
  1324. pHere->pfnDGCO = (pfnDllGetClassObject)GetProcAddress(pHere->hmModule, "DllGetClassObject");
  1325. }
  1326. pHere++;
  1327. }
  1328. for (iComClass = 0; iComClass < this->m_ComClassData.Size(); iComClass++)
  1329. {
  1330. CComClassInformation *pComClass = m_ComClassData[iComClass];
  1331. //
  1332. // Somehow we've already found this out?
  1333. //
  1334. if (pComClass->m_DllName.length() != 0)
  1335. continue;
  1336. //
  1337. // Ask all the DLLs for the class
  1338. //
  1339. for (SIZE_T idx = 0; idx < cDllCount; idx++)
  1340. {
  1341. CSmartPointer<IUnknown> punk;
  1342. HRESULT hres;
  1343. if (Dlls[idx].pfnDGCO == NULL)
  1344. continue;
  1345. hres = Dlls[idx].pfnDGCO(pComClass->m_ObjectIdent, IID_IUnknown, (LPVOID*)&punk);
  1346. if (hres != CLASS_E_CLASSNOTAVAILABLE)
  1347. pComClass->m_DllName = Dlls[idx].DllName;
  1348. if (punk != NULL)
  1349. punk->Release();
  1350. }
  1351. }
  1352. delete[] Dlls;
  1353. SetErrorMode(uiErrorMode);
  1354. }
  1355. //
  1356. // Do the "loadlibrary implies registering classes" thing
  1357. //
  1358. FindWindowClasses();
  1359. //
  1360. // Now take all the com class information and put it in files.
  1361. //
  1362. UpdateManifestWithData(ptDocument);
  1363. //
  1364. // And save it out to an xml file
  1365. //
  1366. if (FAILED(PrettyFormatXmlDocument(ptDocument)))
  1367. Display(ePlProgress, L"Could not pretty-format the document - the manifest will not be easily human-readable.\r\n");
  1368. //
  1369. // Dump current XML for fun
  1370. //
  1371. PrintXML(ptDocument);
  1372. if (FAILED(ptDocument->save(_variant_t(this->m_ManifestFilename))))
  1373. {
  1374. DisplayErrorInfo(ptDocument);
  1375. fOk = false;
  1376. }
  1377. //
  1378. // Are we on a sxs-aware platform?
  1379. //
  1380. if (m_fTestCreation)
  1381. {
  1382. HANDLE (WINAPI *pfnCreateActCtxW)(PCACTCTXW);
  1383. VOID (WINAPI *pfnReleaseActCtx)(HANDLE);
  1384. HANDLE hContext = INVALID_HANDLE_VALUE;
  1385. HMODULE hmKernel32 = NULL;
  1386. ACTCTXW actctxw = { sizeof(actctxw) };
  1387. actctxw.lpSource = this->m_ManifestFilename;
  1388. hmKernel32 = GetModuleHandleW(L"kernel32.dll");
  1389. if (hmKernel32 != NULL)
  1390. {
  1391. pfnCreateActCtxW = (HANDLE (WINAPI*)(PCACTCTXW))GetProcAddress(hmKernel32, "CreateActCtxW");
  1392. pfnReleaseActCtx = (VOID (WINAPI*)(HANDLE))GetProcAddress(hmKernel32, "ReleaseActCtx");
  1393. if ((pfnCreateActCtxW != NULL) && (pfnReleaseActCtx != NULL))
  1394. {
  1395. hContext = pfnCreateActCtxW(&actctxw);
  1396. if (hContext != INVALID_HANDLE_VALUE)
  1397. {
  1398. pfnReleaseActCtx(hContext);
  1399. Display(ePlProgress, L"Created valid assembly manifest.\r\n");
  1400. }
  1401. else
  1402. {
  1403. Display(ePlWarning, L"Warning - this manifest needs more work to be a valid component.\r\n");
  1404. }
  1405. }
  1406. else
  1407. {
  1408. Display(ePlWarning, L"Warning - can't test this manifest, this system does not support CreateActCtxW\r\n");
  1409. }
  1410. }
  1411. else
  1412. {
  1413. Display(ePlWarning, L"Warning - unable to test manifest, kernel32.dll module not found.\r\n");
  1414. }
  1415. }
  1416. User32Trampolines::Stop();
  1417. return fOk;
  1418. }
  1419. bool
  1420. CManBuilder::UpdateManifestWithData(
  1421. CSmartPointer<IXMLDOMDocument> ptDocument
  1422. )
  1423. {
  1424. CSimpleList<CString> FoundFiles;
  1425. this->m_DllInformation.GetKeys(FoundFiles);
  1426. const _bstr_t bstNamespace = STR_ASSEMBLY_MANIFEST_NAMESPACE;
  1427. HRESULT hr;
  1428. SIZE_T idx;
  1429. CSmartPointer<IXMLDOMElement> ptDocumentRoot;
  1430. VARIANT vt;
  1431. hr = ptDocument->get_documentElement(&ptDocumentRoot);
  1432. if (FAILED(hr))
  1433. {
  1434. Display(ePlError, L"Failed getting document root element!\r\n");
  1435. DisplayErrorInfo(ptDocument);
  1436. return false;
  1437. }
  1438. for (idx = 0; idx < this->m_WindowClasses.Size(); idx++)
  1439. {
  1440. CWindowClass *ptInfo = this->m_WindowClasses[idx];
  1441. CSmartPointer<IXMLDOMElement> ptFileElement;
  1442. CSmartPointer<IXMLDOMNode> ptWindowClassNode;
  1443. vt.vt = VT_INT;
  1444. vt.intVal = NODE_ELEMENT;
  1445. hr = ptDocument->createNode(vt, _bstr_t(L"windowClass"), bstNamespace, &ptWindowClassNode);
  1446. if (FAILED(hr))
  1447. {
  1448. continue;
  1449. }
  1450. if (ptInfo->CompleteElement(ptWindowClassNode) &&
  1451. this->FindFileDataFor(ptInfo->m_SourceDll, ptDocumentRoot, ptFileElement, true))
  1452. {
  1453. hr = ptFileElement->appendChild(ptWindowClassNode, NULL);
  1454. }
  1455. }
  1456. for (idx = 0; idx < this->m_ComClassData.Size(); idx++)
  1457. {
  1458. CComClassInformation *ptInfo = this->m_ComClassData[idx];
  1459. CSmartPointer<IXMLDOMElement> ptFileElement;
  1460. CSmartPointer<IXMLDOMNode> ptComNodeNode;
  1461. vt.vt = VT_INT;
  1462. vt.intVal = NODE_ELEMENT;
  1463. if (ptInfo->m_DllName.length() == 0)
  1464. {
  1465. Display(ePlWarning, L"Com clsid %ls (%ls) not associated with a DLL, it will not be listed in the manifest\r\n",
  1466. static_cast<PCWSTR>(StringFromCLSID(ptInfo->m_ObjectIdent)),
  1467. static_cast<PCWSTR>(ptInfo->m_Name));
  1468. continue;
  1469. }
  1470. hr = ptDocument->createNode(vt, _bstr_t(L"comClass"), bstNamespace, &ptComNodeNode);
  1471. if (FAILED(hr))
  1472. {
  1473. continue;
  1474. }
  1475. if (ptInfo->CompleteElement(ptComNodeNode) &&
  1476. this->FindFileDataFor(ptInfo->m_DllName, ptDocumentRoot, ptFileElement, true))
  1477. {
  1478. hr = ptFileElement->appendChild(ptComNodeNode, NULL);
  1479. }
  1480. }
  1481. for (idx = 0; idx < this->m_TlbInfo.Size(); idx++)
  1482. {
  1483. CTlbInformation *ptInfo = this->m_TlbInfo[idx];
  1484. CSmartPointer<IXMLDOMElement> ptFileElement;
  1485. CSmartPointer<IXMLDOMNode> ptTlbNode;
  1486. vt.vt = VT_INT;
  1487. vt.intVal = NODE_ELEMENT;
  1488. hr = ptDocument->createNode(vt, _bstr_t(L"typelib"), bstNamespace, &ptTlbNode);
  1489. if (FAILED(hr))
  1490. {
  1491. continue;
  1492. }
  1493. if (ptInfo->CompleteElement(ptTlbNode) &&
  1494. this->FindFileDataFor(ptInfo->m_SourceFile, ptDocumentRoot, ptFileElement, true))
  1495. {
  1496. hr = ptFileElement->appendChild(ptTlbNode, NULL);
  1497. }
  1498. }
  1499. for (SIZE_T sz = 0; sz < FoundFiles.Size(); sz++)
  1500. {
  1501. CSmartPointer<IXMLDOMElement> ptFileElement;
  1502. SIZE_T c;
  1503. CString &szFoundFilename = FoundFiles[sz];
  1504. CDllInformation &DllInfo = m_DllInformation[szFoundFilename];
  1505. // File node for this map entry not there? Insert it.
  1506. if (!this->FindFileDataFor(szFoundFilename, ptDocumentRoot, ptFileElement, true))
  1507. continue;
  1508. //
  1509. // Finally, proxy/stub interface implementors
  1510. //
  1511. for (c = 0; c < DllInfo.m_IfaceProxies.Size(); c++)
  1512. {
  1513. CSmartPointer<IXMLDOMNode> ptCreatedNode;
  1514. CComInterfaceProxyStub *pIfaceInfo = DllInfo.m_IfaceProxies[c];
  1515. VARIANT vt;
  1516. vt.vt = VT_INT;
  1517. vt.intVal = NODE_ELEMENT;
  1518. if (FAILED(ptDocument->createNode(vt, _bstr_t(L"comInterfaceProxyStub"), bstNamespace, &ptCreatedNode)))
  1519. continue;
  1520. if (pIfaceInfo->CompleteElement(ptCreatedNode))
  1521. {
  1522. if (FAILED(ptFileElement->appendChild(ptCreatedNode, NULL)))
  1523. {
  1524. DisplayErrorInfo(ptFileElement);
  1525. }
  1526. }
  1527. }
  1528. }
  1529. //
  1530. // For all the external proxies...
  1531. //
  1532. for (SIZE_T sz = 0; sz < m_ExternalProxies.Size(); sz++)
  1533. {
  1534. CSmartPointer<IXMLDOMNode> ptExtInterface;
  1535. VARIANT vt;
  1536. vt.vt = VT_INT;
  1537. vt.intVal = NODE_ELEMENT;
  1538. if (FAILED(ptDocument->createNode(vt, _bstr_t(L"comInterfaceExternalProxyStub"), bstNamespace, &ptExtInterface)))
  1539. {
  1540. DisplayErrorInfo(ptDocument);
  1541. continue;
  1542. }
  1543. m_ExternalProxies[sz]->CompleteElement(ptExtInterface);
  1544. if (FAILED(ptDocumentRoot->appendChild(ptExtInterface, NULL)))
  1545. {
  1546. DisplayErrorInfo(ptDocumentRoot);
  1547. continue;
  1548. }
  1549. }
  1550. return true;
  1551. }
  1552. void
  1553. CManBuilder::DisplayParams()
  1554. {
  1555. static PCWSTR pcwszHelpText =
  1556. L"Side-by-Side component manifest building tool\r\n"
  1557. L"\r\n"
  1558. L"Parameters:\r\n"
  1559. L"\r\n"
  1560. L"-dlls [dll1] [[dll2] ...] List of DLLs to include in the component\r\n"
  1561. L" Include multiple files (-dlls foo.dll bar.dll) to create a manifest with\r\n"
  1562. L" multiple members\r\n"
  1563. L"-manifest <manifestname> File to output generated manifest to\r\n"
  1564. L"-verbose Print lots of extra debugging spew during run\r\n"
  1565. L"-silent Print minimal output, error only\r\n"
  1566. L"-nologo Don't display copyright banner\r\n"
  1567. L"-test Verify created manifest's structure\r\n"
  1568. L"-captureregistry Simulate regsvr32 of the DLL in question, and use\r\n"
  1569. L" information gathered from HKEY_CLASSES_ROOT\r\n"
  1570. L"-identity [identstring] Use the text in identstring to build the\r\n"
  1571. L" assembly's identity. See below for format\r\n"
  1572. L"\r\n"
  1573. L"Minimally, you should provide -manifest.\r\n"
  1574. L"\r\n"
  1575. L"[identstring] should be composed of name=value pairs, just like those\r\n"
  1576. L"present in a normal component. For example - the Microsoft Common Controls\r\n"
  1577. L"version 6.0.0.0 assembly for x86 could be built as follows:\r\n"
  1578. L"\r\n"
  1579. L"-identity type='win32' name='Microsoft.Windows.Common-Controls'\r\n"
  1580. L" version='6.0.0.0' processorArchitecture='x86'\r\n"
  1581. L" publicKeyToken='6595b64144ccf1df'\r\n"
  1582. L"\r\n";
  1583. Display(ePlSpew, pcwszHelpText);
  1584. }
  1585. bool
  1586. CManBuilder::Initialize(
  1587. SIZE_T argc,
  1588. WCHAR** argv
  1589. )
  1590. {
  1591. bool fNoLogo = false;
  1592. bool fParamsOk = true;
  1593. SIZE_T i;
  1594. m_Parameters.EnsureSize(argc);
  1595. for (i = 0; i < argc; i++)
  1596. {
  1597. if (lstrcmpiW(argv[i], STR_NOLOGO) == 0)
  1598. fNoLogo = true;
  1599. else
  1600. m_Parameters[m_Parameters.Size()] = argv[i];
  1601. }
  1602. if (!fNoLogo)
  1603. {
  1604. this->Display(ePlProgress, MS_LOGO);
  1605. }
  1606. for (i = 0; fParamsOk && (i < m_Parameters.Size()); i++)
  1607. {
  1608. if (CString(L"-manifest") == m_Parameters[i])
  1609. {
  1610. if ((i + 1) < m_Parameters.Size())
  1611. m_ManifestFilename = m_Parameters[++i];
  1612. else
  1613. fParamsOk = false;
  1614. }
  1615. else if (CString(L"-?") == m_Parameters[i])
  1616. {
  1617. this->m_plPrintLevel = (ErrorLevel)0xf;
  1618. DisplayParams();
  1619. return false;
  1620. }
  1621. else if (CString(L"-dlls") == m_Parameters[i])
  1622. {
  1623. while (++i < m_Parameters.Size())
  1624. {
  1625. CString param = m_Parameters[i];
  1626. if (((PCWSTR)param)[0] == L'-')
  1627. break;
  1628. m_InputDllListing.Append(param); // keep the path info
  1629. }
  1630. --i;
  1631. }
  1632. else if (CString(L"-identity") == m_Parameters[i])
  1633. {
  1634. while (++i < m_Parameters.Size())
  1635. {
  1636. CString param = m_Parameters[i];
  1637. if ((static_cast<PCWSTR>(param))[0] == L'-')
  1638. break;
  1639. m_IdentityBlob.Append(param);
  1640. }
  1641. --i;
  1642. }
  1643. else if (CString(L"-silent") == m_Parameters[i])
  1644. {
  1645. this->m_plPrintLevel = ePlError;
  1646. }
  1647. else if (CString(L"-mscopyright") == m_Parameters[i])
  1648. {
  1649. m_fAddCopyrightData = true;
  1650. }
  1651. else if (CString(L"-captureregistry") == m_Parameters[i])
  1652. {
  1653. m_fUseRegistryData = true;
  1654. }
  1655. else if (CString(L"-test") == m_Parameters[i])
  1656. {
  1657. this->m_fTestCreation = true;
  1658. }
  1659. else if (CString(L"-verbose") == m_Parameters[i])
  1660. {
  1661. this->m_plPrintLevel = (ErrorLevel)0xf;
  1662. }
  1663. }
  1664. //
  1665. // Bad parameters?
  1666. //
  1667. if (
  1668. (m_ManifestFilename.length() == 0))
  1669. {
  1670. this->m_plPrintLevel = (ErrorLevel)0xf;
  1671. DisplayParams();
  1672. return false;
  1673. }
  1674. return fParamsOk;
  1675. }
  1676. CString
  1677. CreateStringGuid()
  1678. {
  1679. GUID uuid;
  1680. CoCreateGuid(&uuid);
  1681. return StringFromCLSID(uuid);
  1682. }
  1683. int __cdecl wmain(int argc, WCHAR** argv)
  1684. {
  1685. CManBuilder builder;
  1686. CoInitialize(NULL);
  1687. if (builder.Initialize(argc, argv))
  1688. {
  1689. builder.Run();
  1690. }
  1691. return GetLastError();
  1692. }