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.

1058 lines
42 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. comclass.cpp
  5. Abstract:
  6. Activation context section contributor for COM servers.
  7. Author:
  8. Michael J. Grier (MGrier) 23-Feb-2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include <windows.h>
  13. #include "sxsp.h"
  14. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(clsid);
  15. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(iid);
  16. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(name);
  17. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(progid);
  18. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(proxyStubClsid32);
  19. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(runtimeVersion);
  20. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(threadingModel);
  21. DECLARE_STD_ATTRIBUTE_NAME_DESCRIPTOR(tlbid);
  22. #define ALLOCATE_BUFFER_SPACE(_bytesNeeded, _bufferCursor, _bytesLeft, _bytesWritten, _typeName, _ptr) \
  23. do { \
  24. if ((_bytesLeft) < (_bytesNeeded)) \
  25. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER); \
  26. (_bytesLeft) -= (_bytesNeeded); \
  27. (_bytesWritten) += (_bytesNeeded); \
  28. (_ptr) = (_typeName)(_bufferCursor); \
  29. (_bufferCursor) = (PVOID) (((ULONG_PTR) (_bufferCursor)) + (_bytesNeeded)); \
  30. } while (0)
  31. #define ALLOCATE_BUFFER_SPACE_TYPE(_typeName, _bufferCursor, _bytesLeft, _bytesWritten, _ptr) \
  32. ALLOCATE_BUFFER_SPACE(sizeof(_typeName), _bufferCursor, _bytesLeft, _bytesWritten, _typeName *, _ptr)
  33. typedef struct _COM_GLOBAL_CONTEXT *PCOM_GLOBAL_CONTEXT;
  34. typedef struct _COM_FILE_CONTEXT *PCOM_FILE_CONTEXT;
  35. typedef struct _COM_SERVER_ENTRY *PCOM_SERVER_ENTRY;
  36. typedef struct _COM_GLOBAL_CONTEXT
  37. {
  38. _COM_GLOBAL_CONTEXT() { }
  39. // Temporary holding buffer for the filename until the first COM server entry is
  40. // found, at which time a COM_FILE_CONTEXT is allocated and the filename moved to it.
  41. CSmallStringBuffer m_FileNameBuffer;
  42. PCOM_FILE_CONTEXT m_FileContextListHead;
  43. ULONG m_FileContextListCount;
  44. CTinyStringBuffer m_FirstShimNameBuffer;
  45. ULONG m_FirstShimNameOffset;
  46. ULONG m_FirstShimNameLength;
  47. // When the first clrClass entry is created, its file context is written here for
  48. // easy access in the future. It will exist in the normal list of files as well,
  49. // however, and will get cleaned up when the file list goes away.
  50. PCOM_FILE_CONTEXT m_MscoreeFileContext;
  51. private:
  52. _COM_GLOBAL_CONTEXT(const _COM_GLOBAL_CONTEXT &);
  53. void operator =(const _COM_GLOBAL_CONTEXT &);
  54. } COM_GLOBAL_CONTEXT;
  55. typedef struct _COM_FILE_CONTEXT
  56. {
  57. public:
  58. _COM_FILE_CONTEXT() { }
  59. PCOM_FILE_CONTEXT m_Next;
  60. CSmallStringBuffer m_FileNameBuffer;
  61. PCOM_SERVER_ENTRY m_ServerListHead;
  62. ULONG m_ServerListCount;
  63. ULONG m_Offset; // populated during section generation
  64. PCOM_GLOBAL_CONTEXT m_GlobalContext;
  65. private:
  66. _COM_FILE_CONTEXT(const _COM_FILE_CONTEXT &);
  67. void operator =(const _COM_FILE_CONTEXT &);
  68. } COM_FILE_CONTEXT;
  69. typedef struct _COM_SERVER_ENTRY
  70. {
  71. public:
  72. _COM_SERVER_ENTRY() { }
  73. PCOM_SERVER_ENTRY m_Next;
  74. PCOM_FILE_CONTEXT m_FileContext;
  75. GUID m_ReferenceClsid;
  76. GUID m_ConfiguredClsid;
  77. GUID m_ImplementedClsid;
  78. GUID m_TypeLibraryId;
  79. ULONG m_ThreadingModel;
  80. CSmallStringBuffer m_ProgIdBuffer;
  81. CTinyStringBuffer m_TypeNameBuffer;
  82. CTinyStringBuffer m_ShimNameBuffer;
  83. CTinyStringBuffer m_RuntimeVersionBuffer;
  84. ULONG m_ShimType;
  85. bool m_IsFirstShim;
  86. private:
  87. _COM_SERVER_ENTRY(const _COM_SERVER_ENTRY &);
  88. void operator =(const _COM_SERVER_ENTRY &);
  89. } COM_SERVER_ENTRY;
  90. VOID
  91. WINAPI
  92. SxspComClassRedirectionContributorCallback(
  93. PACTCTXCTB_CALLBACK_DATA Data
  94. )
  95. {
  96. FN_TRACE();
  97. PGUID_SECTION_GENERATION_CONTEXT GSGenContext = (PGUID_SECTION_GENERATION_CONTEXT) Data->Header.ActCtxGenContext;
  98. PCOM_GLOBAL_CONTEXT ComGlobalContext = NULL;
  99. if (GSGenContext != NULL)
  100. ComGlobalContext = (PCOM_GLOBAL_CONTEXT) ::SxsGetGuidSectionGenerationContextCallbackContext(GSGenContext);
  101. switch (Data->Header.Reason)
  102. {
  103. case ACTCTXCTB_CBREASON_ACTCTXGENBEGINNING:
  104. Data->GenBeginning.Success = FALSE;
  105. INTERNAL_ERROR_CHECK(ComGlobalContext == NULL);
  106. INTERNAL_ERROR_CHECK(GSGenContext == NULL);
  107. IFALLOCFAILED_EXIT(ComGlobalContext = new COM_GLOBAL_CONTEXT);
  108. ComGlobalContext->m_FileContextListHead = NULL;
  109. ComGlobalContext->m_FileContextListCount = 0;
  110. ComGlobalContext->m_FirstShimNameOffset = 0;
  111. ComGlobalContext->m_FirstShimNameLength = 0;
  112. ComGlobalContext->m_MscoreeFileContext = NULL;
  113. if (!::SxsInitGuidSectionGenerationContext(
  114. &GSGenContext,
  115. ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_FORMAT_WHISTLER,
  116. &::SxspComClassRedirectionGuidSectionGenerationCallback,
  117. ComGlobalContext))
  118. {
  119. FUSION_DELETE_SINGLETON(ComGlobalContext);
  120. goto Exit;
  121. }
  122. Data->Header.ActCtxGenContext = GSGenContext;
  123. Data->GenBeginning.Success = TRUE;
  124. break;
  125. case ACTCTXCTB_CBREASON_ACTCTXGENENDED:
  126. if (GSGenContext != NULL)
  127. ::SxsDestroyGuidSectionGenerationContext(GSGenContext);
  128. FUSION_DELETE_SINGLETON(ComGlobalContext);
  129. break;
  130. case ACTCTXCTB_CBREASON_ALLPARSINGDONE:
  131. Data->AllParsingDone.Success = FALSE;
  132. #if 0 // guid section optimiziation not yet implemented
  133. if ((GSGenContext != NULL) && !::SxsDoneModifyingGuidSectionGenerationContext(GSGenContext))
  134. goto Exit;
  135. #endif
  136. Data->AllParsingDone.Success = TRUE;
  137. break;
  138. case ACTCTXCTB_CBREASON_GETSECTIONSIZE:
  139. Data->GetSectionSize.Success = FALSE;
  140. // Someone shouldn't be asking for the section size if this is a parse-only
  141. // run. These two asserts should be equivalent...
  142. INTERNAL_ERROR_CHECK(Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT);
  143. INTERNAL_ERROR_CHECK(GSGenContext != NULL);
  144. IFW32FALSE_EXIT(::SxsGetGuidSectionGenerationContextSectionSize(GSGenContext, &Data->GetSectionSize.SectionSize));
  145. Data->GetSectionSize.Success = TRUE;
  146. break;
  147. case ACTCTXCTB_CBREASON_ELEMENTPARSED:
  148. Data->ElementParsed.Success = FALSE;
  149. if ((Data->ElementParsed.ParseContext->XMLElementDepth == 2) &&
  150. (::FusionpCompareStrings(
  151. Data->ElementParsed.ParseContext->ElementPath,
  152. Data->ElementParsed.ParseContext->ElementPathCch,
  153. L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file",
  154. NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file") - 1,
  155. false) == 0))
  156. {
  157. CStringBuffer FileNameBuffer;
  158. bool fFound = false;
  159. SIZE_T cbBytesWritten = 0;
  160. // capture the name of the file
  161. IFW32FALSE_EXIT(::SxspGetAttributeValue(
  162. 0,
  163. &s_AttributeName_name,
  164. &Data->ElementParsed,
  165. fFound,
  166. sizeof(FileNameBuffer),
  167. &FileNameBuffer,
  168. cbBytesWritten,
  169. NULL,
  170. NULL));
  171. // If there's no NAME attribute, someone else will puke; we'll handle it
  172. // gracefully.
  173. if (fFound || (FileNameBuffer.Cch() == 0))
  174. {
  175. INTERNAL_ERROR_CHECK2(
  176. ComGlobalContext != NULL,
  177. "Window class context NULL while processing file element's name attribute.");
  178. IFW32FALSE_EXIT(ComGlobalContext->m_FileNameBuffer.Win32Assign(FileNameBuffer));
  179. }
  180. }
  181. else if (
  182. (Data->ElementParsed.ParseContext->XMLElementDepth == 3) &&
  183. (::FusionpCompareStrings(
  184. Data->ElementParsed.ParseContext->ElementPath,
  185. Data->ElementParsed.ParseContext->ElementPathCch,
  186. L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file!urn:schemas-microsoft-com:asm.v1^comClass",
  187. NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file!urn:schemas-microsoft-com:asm.v1^comClass") - 1,
  188. false) == 0))
  189. {
  190. bool fFound = false;
  191. SIZE_T cb;
  192. CSmallStringBuffer VersionIndependentComClassIdBuffer;
  193. PCOM_SERVER_ENTRY Entry = NULL;
  194. PCOM_FILE_CONTEXT FileContext = NULL;
  195. CStringBuffer TempBuffer;
  196. CSmallStringBuffer ProgIdBuffer;
  197. ULONG ThreadingModel;
  198. GUID ReferenceClsid, ConfiguredClsid, ImplementedClsid;
  199. GUID TypeLibraryId;
  200. TypeLibraryId = GUID_NULL;
  201. INTERNAL_ERROR_CHECK2(
  202. ComGlobalContext != NULL,
  203. "COM global context NULL while processing comClass tag");
  204. IFW32FALSE_EXIT(
  205. ::SxspGetAttributeValue(
  206. SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE,
  207. &s_AttributeName_clsid,
  208. &Data->ElementParsed,
  209. fFound,
  210. sizeof(VersionIndependentComClassIdBuffer),
  211. &VersionIndependentComClassIdBuffer,
  212. cb,
  213. NULL,
  214. 0));
  215. INTERNAL_ERROR_CHECK(fFound);
  216. IFW32FALSE_EXIT(::SxspParseGUID(VersionIndependentComClassIdBuffer,
  217. VersionIndependentComClassIdBuffer.Cch(),
  218. ReferenceClsid));
  219. IFW32FALSE_EXIT(
  220. ::SxspGetAttributeValue(
  221. 0,
  222. &s_AttributeName_threadingModel,
  223. &Data->ElementParsed,
  224. fFound,
  225. sizeof(TempBuffer),
  226. &TempBuffer,
  227. cb,
  228. NULL,
  229. 0));
  230. if (fFound)
  231. IFW32FALSE_EXIT(::SxspParseThreadingModel(TempBuffer, TempBuffer.Cch(), &ThreadingModel));
  232. else
  233. ThreadingModel = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_SINGLE;
  234. IFW32FALSE_EXIT(
  235. ::SxspGetAttributeValue(
  236. 0,
  237. &s_AttributeName_progid,
  238. &Data->ElementParsed,
  239. fFound,
  240. sizeof(ProgIdBuffer),
  241. &ProgIdBuffer,
  242. cb,
  243. NULL,
  244. 0));
  245. IFW32FALSE_EXIT(
  246. ::SxspGetAttributeValue(
  247. 0,
  248. &s_AttributeName_tlbid,
  249. &Data->ElementParsed,
  250. fFound,
  251. sizeof(TempBuffer),
  252. &TempBuffer,
  253. cb,
  254. NULL,
  255. 0));
  256. if (fFound)
  257. IFW32FALSE_EXIT(::SxspParseGUID(TempBuffer, TempBuffer.Cch(), TypeLibraryId));
  258. else
  259. TypeLibraryId = GUID_NULL;
  260. // That was sufficient if we are generating a context.
  261. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT)
  262. {
  263. BOOL fNewAllocate = FALSE;
  264. IFW32FALSE_EXIT(Data->Header.ClsidMappingContext->Map->MapReferenceClsidToConfiguredClsid(
  265. &ReferenceClsid,
  266. Data->ElementParsed.AssemblyContext,
  267. &ConfiguredClsid,
  268. &ImplementedClsid));
  269. // See if we already have a file context; if we do not, allocate one.
  270. if (ComGlobalContext->m_FileNameBuffer.Cch() != 0)
  271. {
  272. IFALLOCFAILED_EXIT(FileContext = new COM_FILE_CONTEXT);
  273. fNewAllocate = TRUE;
  274. IFW32FALSE_EXIT(FileContext->m_FileNameBuffer.Win32Assign(ComGlobalContext->m_FileNameBuffer));
  275. FileContext->m_Next = ComGlobalContext->m_FileContextListHead;
  276. ComGlobalContext->m_FileContextListHead = FileContext;
  277. ComGlobalContext->m_FileContextListCount++;
  278. FileContext->m_ServerListHead = NULL;
  279. FileContext->m_ServerListCount = 0;
  280. FileContext->m_GlobalContext = ComGlobalContext;
  281. }
  282. else
  283. FileContext = ComGlobalContext->m_FileContextListHead;
  284. ASSERT(FileContext != NULL);
  285. IFALLOCFAILED_EXIT(Entry = new COM_SERVER_ENTRY);
  286. Entry->m_ShimType = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_OTHER;
  287. Entry->m_Next = FileContext->m_ServerListHead;
  288. Entry->m_ReferenceClsid = ReferenceClsid;
  289. Entry->m_ConfiguredClsid = ConfiguredClsid;
  290. Entry->m_ImplementedClsid = ImplementedClsid;
  291. Entry->m_TypeLibraryId = TypeLibraryId;
  292. Entry->m_ThreadingModel = ThreadingModel;
  293. Entry->m_FileContext = FileContext;
  294. IFW32FALSE_EXIT(Entry->m_ProgIdBuffer.Win32Assign(ProgIdBuffer));
  295. if (!::SxsAddGuidToGuidSectionGenerationContext(
  296. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  297. &ReferenceClsid,
  298. Entry,
  299. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  300. ERROR_SXS_DUPLICATE_CLSID))
  301. {
  302. if (fNewAllocate)
  303. FUSION_DELETE_SINGLETON(FileContext);
  304. FUSION_DELETE_SINGLETON(Entry);
  305. goto Exit;
  306. }
  307. FileContext->m_ServerListHead = Entry;
  308. FileContext->m_ServerListCount++;
  309. // And we add another, indexed by the configured clsid
  310. IFALLOCFAILED_EXIT(Entry = new COM_SERVER_ENTRY);
  311. Entry->m_Next = FileContext->m_ServerListHead;
  312. Entry->m_ReferenceClsid = ReferenceClsid;
  313. Entry->m_ConfiguredClsid = ConfiguredClsid;
  314. Entry->m_ImplementedClsid = ImplementedClsid;
  315. Entry->m_TypeLibraryId = TypeLibraryId;
  316. Entry->m_ThreadingModel = ThreadingModel;
  317. Entry->m_FileContext = FileContext;
  318. IFW32FALSE_EXIT(Entry->m_ProgIdBuffer.Win32Assign(ProgIdBuffer));
  319. if (!::SxsAddGuidToGuidSectionGenerationContext(
  320. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  321. &ConfiguredClsid,
  322. Entry,
  323. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  324. ERROR_SXS_DUPLICATE_CLSID))
  325. {
  326. //if (fNewAllocate) // should not deleted here.
  327. // FUSION_DELETE_SINGLETON(FileContext);
  328. FUSION_DELETE_SINGLETON(Entry);
  329. goto Exit;
  330. }
  331. FileContext->m_ServerListHead = Entry;
  332. FileContext->m_ServerListCount++;
  333. }
  334. }
  335. else if (
  336. (Data->ElementParsed.ParseContext->XMLElementDepth == 3) &&
  337. (::FusionpCompareStrings(
  338. Data->ElementParsed.ParseContext->ElementPath,
  339. Data->ElementParsed.ParseContext->ElementPathCch,
  340. L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file!urn:schemas-microsoft-com:asm.v1^comInterfaceProxyStub",
  341. NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^file!urn:schemas-microsoft-com:asm.v1^comInterfaceProxyStub") - 1,
  342. false) == 0))
  343. {
  344. bool fFound = false;
  345. SIZE_T cb;
  346. PCOM_SERVER_ENTRY Entry = NULL;
  347. PCOM_FILE_CONTEXT FileContext = NULL;
  348. CStringBuffer TempBuffer;
  349. ULONG ThreadingModel;
  350. GUID ReferenceClsid, ConfiguredClsid, ImplementedClsid;
  351. GUID TypeLibraryId, iid;
  352. TypeLibraryId = GUID_NULL;
  353. INTERNAL_ERROR_CHECK2(
  354. ComGlobalContext != NULL,
  355. "COM global context NULL while processing comInterfaceProxyStub tag");
  356. IFW32FALSE_EXIT(
  357. ::SxspGetAttributeValue(
  358. SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE,
  359. &s_AttributeName_iid,
  360. &Data->ElementParsed,
  361. fFound,
  362. sizeof(iid),
  363. &iid,
  364. cb,
  365. &::SxspValidateGuidAttribute,
  366. 0));
  367. IFW32FALSE_EXIT(
  368. ::SxspGetAttributeValue(
  369. 0,
  370. &s_AttributeName_proxyStubClsid32,
  371. &Data->ElementParsed,
  372. fFound,
  373. sizeof(ReferenceClsid),
  374. &ReferenceClsid,
  375. cb,
  376. &::SxspValidateGuidAttribute,
  377. 0));
  378. if (!fFound)
  379. ReferenceClsid = iid;
  380. IFW32FALSE_EXIT(
  381. ::SxspGetAttributeValue(
  382. 0,
  383. &s_AttributeName_threadingModel,
  384. &Data->ElementParsed,
  385. fFound,
  386. sizeof(TempBuffer),
  387. &TempBuffer,
  388. cb,
  389. NULL,
  390. 0));
  391. if (fFound)
  392. IFW32FALSE_EXIT(::SxspParseThreadingModel(TempBuffer, TempBuffer.Cch(), &ThreadingModel));
  393. else
  394. ThreadingModel = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_SINGLE;
  395. // That was sufficient if we are generating a context.
  396. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT)
  397. {
  398. BOOL fNewAllocate = FALSE;
  399. IFW32FALSE_EXIT(Data->Header.ClsidMappingContext->Map->MapReferenceClsidToConfiguredClsid(
  400. &ReferenceClsid,
  401. Data->ElementParsed.AssemblyContext,
  402. &ConfiguredClsid,
  403. &ImplementedClsid));
  404. // See if we already have a file context; if we do not, allocate one.
  405. if (ComGlobalContext->m_FileNameBuffer.Cch() != 0)
  406. {
  407. IFALLOCFAILED_EXIT(FileContext = new COM_FILE_CONTEXT);
  408. fNewAllocate = TRUE;
  409. IFW32FALSE_EXIT(FileContext->m_FileNameBuffer.Win32Assign(ComGlobalContext->m_FileNameBuffer));
  410. FileContext->m_Next = ComGlobalContext->m_FileContextListHead;
  411. ComGlobalContext->m_FileContextListHead = FileContext;
  412. ComGlobalContext->m_FileContextListCount++;
  413. FileContext->m_ServerListHead = NULL;
  414. FileContext->m_ServerListCount = 0;
  415. FileContext->m_GlobalContext = ComGlobalContext;
  416. }
  417. else
  418. FileContext = ComGlobalContext->m_FileContextListHead;
  419. ASSERT(FileContext != NULL);
  420. IFALLOCFAILED_EXIT(Entry = new COM_SERVER_ENTRY);
  421. INTERNAL_ERROR_CHECK(FileContext != NULL);
  422. Entry->m_ShimType = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_OTHER;
  423. Entry->m_Next = FileContext->m_ServerListHead;
  424. Entry->m_ReferenceClsid = ReferenceClsid;
  425. Entry->m_ConfiguredClsid = ConfiguredClsid;
  426. Entry->m_ImplementedClsid = ImplementedClsid;
  427. Entry->m_TypeLibraryId = GUID_NULL;
  428. Entry->m_ThreadingModel = ThreadingModel;
  429. Entry->m_FileContext = FileContext;
  430. Entry->m_ProgIdBuffer.Clear();
  431. if (!::SxsAddGuidToGuidSectionGenerationContext(
  432. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  433. &ReferenceClsid,
  434. Entry,
  435. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  436. ERROR_SXS_DUPLICATE_CLSID))
  437. {
  438. if (fNewAllocate)
  439. FUSION_DELETE_SINGLETON(FileContext);
  440. FUSION_DELETE_SINGLETON(Entry);
  441. goto Exit;
  442. }
  443. FileContext->m_ServerListHead = Entry;
  444. FileContext->m_ServerListCount++;
  445. // And we add another, indexed by the configured clsid
  446. IFALLOCFAILED_EXIT(Entry = new COM_SERVER_ENTRY);
  447. Entry->m_Next = FileContext->m_ServerListHead;
  448. Entry->m_ReferenceClsid = ReferenceClsid;
  449. Entry->m_ConfiguredClsid = ConfiguredClsid;
  450. Entry->m_ImplementedClsid = ImplementedClsid;
  451. Entry->m_TypeLibraryId = GUID_NULL;
  452. Entry->m_ThreadingModel = ThreadingModel;
  453. Entry->m_FileContext = FileContext;
  454. Entry->m_ProgIdBuffer.Clear();
  455. if (!::SxsAddGuidToGuidSectionGenerationContext(
  456. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  457. &ConfiguredClsid,
  458. Entry,
  459. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  460. ERROR_SXS_DUPLICATE_CLSID))
  461. {
  462. //if (fNewAllocate) // should not deleted here.
  463. // FUSION_DELETE_SINGLETON(FileContext);
  464. FUSION_DELETE_SINGLETON(Entry);
  465. goto Exit;
  466. }
  467. FileContext->m_ServerListHead = Entry;
  468. FileContext->m_ServerListCount++;
  469. }
  470. }
  471. else if (
  472. (Data->ElementParsed.ParseContext->XMLElementDepth == 2) &&
  473. (::FusionpCompareStrings(
  474. Data->ElementParsed.ParseContext->ElementPath,
  475. Data->ElementParsed.ParseContext->ElementPathCch,
  476. L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^clrClass",
  477. NUMBER_OF(L"urn:schemas-microsoft-com:asm.v1^assembly!urn:schemas-microsoft-com:asm.v1^clrClass") - 1,
  478. false) == 0))
  479. {
  480. bool fFound = false;
  481. SIZE_T cb;
  482. CSmallStringBuffer VersionIndependentComClassIdBuffer;
  483. PCOM_SERVER_ENTRY Entry;
  484. PCOM_FILE_CONTEXT FileContext;
  485. CSmallStringBuffer TempBuffer;
  486. CSmallStringBuffer ProgIdBuffer;
  487. CSmallStringBuffer RuntimeVersionBuffer;
  488. CSmallStringBuffer NameBuffer;
  489. ULONG ThreadingModel;
  490. GUID ReferenceClsid, ConfiguredClsid, ImplementedClsid;
  491. GUID TypeLibraryId;
  492. bool fIsFirstShim = false;
  493. TypeLibraryId = GUID_NULL;
  494. INTERNAL_ERROR_CHECK2(
  495. ComGlobalContext != NULL,
  496. "COM global context NULL while processing ndpClass tag");
  497. IFW32FALSE_EXIT(
  498. ::SxspGetAttributeValue(
  499. SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE,
  500. &s_AttributeName_name,
  501. &Data->ElementParsed,
  502. fFound,
  503. sizeof(NameBuffer),
  504. &NameBuffer,
  505. cb,
  506. NULL,
  507. 0));
  508. INTERNAL_ERROR_CHECK(fFound);
  509. IFW32FALSE_EXIT(
  510. ::SxspGetAttributeValue(
  511. SXSP_GET_ATTRIBUTE_VALUE_FLAG_REQUIRED_ATTRIBUTE,
  512. &s_AttributeName_clsid,
  513. &Data->ElementParsed,
  514. fFound,
  515. sizeof(VersionIndependentComClassIdBuffer),
  516. &VersionIndependentComClassIdBuffer,
  517. cb,
  518. NULL,
  519. 0));
  520. INTERNAL_ERROR_CHECK(fFound);
  521. IFW32FALSE_EXIT(
  522. ::SxspParseGUID(
  523. VersionIndependentComClassIdBuffer,
  524. VersionIndependentComClassIdBuffer.Cch(),
  525. ReferenceClsid));
  526. IFW32FALSE_EXIT(
  527. ::SxspGetAttributeValue(
  528. 0,
  529. &s_AttributeName_threadingModel,
  530. &Data->ElementParsed,
  531. fFound,
  532. sizeof(TempBuffer),
  533. &TempBuffer,
  534. cb,
  535. NULL,
  536. 0));
  537. if (fFound)
  538. IFW32FALSE_EXIT(::SxspParseThreadingModel(TempBuffer, TempBuffer.Cch(), &ThreadingModel));
  539. else
  540. ThreadingModel = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_THREADING_MODEL_BOTH;
  541. IFW32FALSE_EXIT(
  542. ::SxspGetAttributeValue(
  543. 0,
  544. &s_AttributeName_progid,
  545. &Data->ElementParsed,
  546. fFound,
  547. sizeof(ProgIdBuffer),
  548. &ProgIdBuffer,
  549. cb,
  550. NULL,
  551. 0));
  552. IFW32FALSE_EXIT(
  553. ::SxspGetAttributeValue(
  554. 0,
  555. &s_AttributeName_tlbid,
  556. &Data->ElementParsed,
  557. fFound,
  558. sizeof(TempBuffer),
  559. &TempBuffer,
  560. cb,
  561. NULL,
  562. 0));
  563. if (fFound)
  564. IFW32FALSE_EXIT(::SxspParseGUID(TempBuffer, TempBuffer.Cch(), TypeLibraryId));
  565. else
  566. TypeLibraryId = GUID_NULL;
  567. IFW32FALSE_EXIT(
  568. ::SxspGetAttributeValue(
  569. 0,
  570. &s_AttributeName_runtimeVersion,
  571. &Data->ElementParsed,
  572. fFound,
  573. sizeof(RuntimeVersionBuffer),
  574. &RuntimeVersionBuffer,
  575. cb,
  576. NULL,
  577. 0));
  578. // That was sufficient if we are generating a context.
  579. if (Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT)
  580. {
  581. if (ComGlobalContext->m_FirstShimNameBuffer.Cch() == 0)
  582. {
  583. fIsFirstShim = true;
  584. IFW32FALSE_EXIT(ComGlobalContext->m_FirstShimNameBuffer.Win32Assign(L"MSCOREE.DLL", 11));
  585. }
  586. else
  587. {
  588. IFW32FALSE_EXIT(
  589. ComGlobalContext->m_FirstShimNameBuffer.Win32Equals(
  590. L"MSCOREE.DLL", 11,
  591. fIsFirstShim,
  592. true));
  593. }
  594. IFW32FALSE_EXIT(
  595. Data->Header.ClsidMappingContext->Map->MapReferenceClsidToConfiguredClsid(
  596. &ReferenceClsid,
  597. Data->ElementParsed.AssemblyContext,
  598. &ConfiguredClsid,
  599. &ImplementedClsid));
  600. // If we don't already have a file context for mscoree, then we have to create a new one.
  601. if (ComGlobalContext->m_MscoreeFileContext == NULL)
  602. {
  603. IFALLOCFAILED_EXIT(FileContext = FUSION_NEW_SINGLETON(COM_FILE_CONTEXT));
  604. IFW32FALSE_EXIT(FileContext->m_FileNameBuffer.Win32Assign("mscoree.dll", 11));
  605. FileContext->m_Next = ComGlobalContext->m_FileContextListHead;
  606. ComGlobalContext->m_FileContextListHead = FileContext;
  607. ComGlobalContext->m_FileContextListCount++;
  608. ComGlobalContext->m_MscoreeFileContext = FileContext;
  609. FileContext->m_ServerListHead = NULL;
  610. FileContext->m_ServerListCount = 0;
  611. FileContext->m_GlobalContext = ComGlobalContext;
  612. }
  613. else
  614. FileContext = ComGlobalContext->m_MscoreeFileContext;
  615. #if 0
  616. // See if we already have a file context; if we do not, allocate one.
  617. if (ComGlobalContext->m_FileNameBuffer.Cch() != 0)
  618. {
  619. IFALLOCFAILED_EXIT(FileContext = FUSION_NEW_SINGLETON(COM_FILE_CONTEXT));
  620. IFW32FALSE_EXIT(FileContext->m_FileNameBuffer.Win32Assign(ComGlobalContext->m_FileNameBuffer));
  621. FileContext->m_Next = ComGlobalContext->m_FileContextListHead;
  622. ComGlobalContext->m_FileContextListHead = FileContext;
  623. ComGlobalContext->m_FileContextListCount++;
  624. FileContext->m_ServerListHead = NULL;
  625. FileContext->m_ServerListCount = 0;
  626. FileContext->m_GlobalContext = ComGlobalContext;
  627. }
  628. else
  629. FileContext = ComGlobalContext->m_FileContextListHead;
  630. #endif
  631. INTERNAL_ERROR_CHECK(FileContext != NULL);
  632. IFALLOCFAILED_EXIT(Entry = FUSION_NEW_SINGLETON(COM_SERVER_ENTRY));
  633. Entry->m_ShimType = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_CLR_CLASS;
  634. Entry->m_Next = FileContext->m_ServerListHead;
  635. Entry->m_ReferenceClsid = ReferenceClsid;
  636. Entry->m_ConfiguredClsid = ConfiguredClsid;
  637. Entry->m_ImplementedClsid = ImplementedClsid;
  638. Entry->m_TypeLibraryId = TypeLibraryId;
  639. Entry->m_ThreadingModel = ThreadingModel;
  640. Entry->m_FileContext = FileContext;
  641. IFW32FALSE_EXIT(Entry->m_ProgIdBuffer.Win32Assign(ProgIdBuffer));
  642. IFW32FALSE_EXIT(Entry->m_ShimNameBuffer.Win32Assign(L"MSCOREE.DLL", 11));
  643. IFW32FALSE_EXIT(Entry->m_RuntimeVersionBuffer.Win32Assign(RuntimeVersionBuffer));
  644. IFW32FALSE_EXIT(Entry->m_TypeNameBuffer.Win32Assign(NameBuffer));
  645. Entry->m_IsFirstShim = fIsFirstShim;
  646. IFW32FALSE_EXIT(
  647. ::SxsAddGuidToGuidSectionGenerationContext(
  648. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  649. &ReferenceClsid,
  650. Entry,
  651. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  652. ERROR_SXS_DUPLICATE_CLSID));
  653. FileContext->m_ServerListHead = Entry;
  654. FileContext->m_ServerListCount++;
  655. // And we add another, indexed by the configured clsid
  656. IFALLOCFAILED_EXIT(Entry = FUSION_NEW_SINGLETON(COM_SERVER_ENTRY));
  657. Entry->m_ShimType = ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_CLR_CLASS;
  658. Entry->m_Next = FileContext->m_ServerListHead;
  659. Entry->m_ReferenceClsid = ReferenceClsid;
  660. Entry->m_ConfiguredClsid = ConfiguredClsid;
  661. Entry->m_ImplementedClsid = ImplementedClsid;
  662. Entry->m_TypeLibraryId = TypeLibraryId;
  663. Entry->m_ThreadingModel = ThreadingModel;
  664. Entry->m_FileContext = FileContext;
  665. IFW32FALSE_EXIT(Entry->m_ProgIdBuffer.Win32Assign(ProgIdBuffer));
  666. IFW32FALSE_EXIT(Entry->m_ShimNameBuffer.Win32Assign(L"MSCOREE.DLL", 11));
  667. IFW32FALSE_EXIT(Entry->m_TypeNameBuffer.Win32Assign(NameBuffer));
  668. IFW32FALSE_EXIT(Entry->m_RuntimeVersionBuffer.Win32Assign(RuntimeVersionBuffer));
  669. Entry->m_IsFirstShim = fIsFirstShim;
  670. IFW32FALSE_EXIT(
  671. ::SxsAddGuidToGuidSectionGenerationContext(
  672. (PGUID_SECTION_GENERATION_CONTEXT) Data->ElementParsed.Header.ActCtxGenContext,
  673. &ConfiguredClsid,
  674. Entry,
  675. Data->ElementParsed.AssemblyContext->AssemblyRosterIndex,
  676. ERROR_SXS_DUPLICATE_CLSID));
  677. FileContext->m_ServerListHead = Entry;
  678. FileContext->m_ServerListCount++;
  679. }
  680. }
  681. // Everything's groovy!
  682. Data->ElementParsed.Success = TRUE;
  683. break;
  684. case ACTCTXCTB_CBREASON_GETSECTIONDATA:
  685. Data->GetSectionData.Success = FALSE;
  686. INTERNAL_ERROR_CHECK(GSGenContext != NULL);
  687. INTERNAL_ERROR_CHECK(Data->Header.ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT);
  688. IFW32FALSE_EXIT(::SxsGetGuidSectionGenerationContextSectionData(GSGenContext, Data->GetSectionData.SectionSize, Data->GetSectionData.SectionDataStart, NULL));
  689. Data->GetSectionData.Success = TRUE;
  690. break;
  691. }
  692. Exit:
  693. ;
  694. }
  695. BOOL
  696. SxspComClassRedirectionGuidSectionGenerationCallback(
  697. PVOID Context,
  698. ULONG Reason,
  699. PVOID CallbackData
  700. )
  701. {
  702. BOOL fSuccess = FALSE;
  703. FN_TRACE_WIN32(fSuccess);
  704. PCOM_GLOBAL_CONTEXT ComGlobalContext = (PCOM_GLOBAL_CONTEXT) Context;
  705. INTERNAL_ERROR_CHECK(CallbackData != NULL);
  706. switch (Reason)
  707. {
  708. case GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE:
  709. {
  710. INTERNAL_ERROR_CHECK(ComGlobalContext != NULL);
  711. PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATASIZE CBData =
  712. (PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATASIZE) CallbackData;
  713. PCOM_FILE_CONTEXT FileContext = ComGlobalContext->m_FileContextListHead;
  714. CBData->DataSize = 0;
  715. // If we have a mscoree shim, add its size to the user data buffer area.
  716. if (ComGlobalContext->m_FirstShimNameBuffer.Cch() != 0)
  717. CBData->DataSize += ((ComGlobalContext->m_FirstShimNameBuffer.Cch() + 1) * sizeof(WCHAR));
  718. while (FileContext != NULL)
  719. {
  720. CBData->DataSize += ((FileContext->m_FileNameBuffer.Cch() + 1) * sizeof(WCHAR));
  721. FileContext = FileContext->m_Next;
  722. }
  723. break;
  724. }
  725. case GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATA:
  726. {
  727. INTERNAL_ERROR_CHECK( ComGlobalContext != NULL );
  728. PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATA CBData =
  729. (PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATA) CallbackData;
  730. SIZE_T BytesWritten = 0;
  731. SIZE_T BytesLeft = CBData->BufferSize;
  732. PWSTR Cursor = (PWSTR) CBData->Buffer;
  733. PCOM_FILE_CONTEXT FileContext = ComGlobalContext->m_FileContextListHead;
  734. if (ComGlobalContext->m_FirstShimNameBuffer.Cch() != 0)
  735. {
  736. IFW32FALSE_EXIT(
  737. ComGlobalContext->m_FirstShimNameBuffer.Win32CopyIntoBuffer(
  738. &Cursor,
  739. &BytesLeft,
  740. &BytesWritten,
  741. CBData->SectionHeader,
  742. &ComGlobalContext->m_FirstShimNameOffset,
  743. &ComGlobalContext->m_FirstShimNameLength));
  744. }
  745. while (FileContext != NULL)
  746. {
  747. IFW32FALSE_EXIT(
  748. FileContext->m_FileNameBuffer.Win32CopyIntoBuffer(
  749. &Cursor,
  750. &BytesLeft,
  751. &BytesWritten,
  752. CBData->SectionHeader,
  753. &FileContext->m_Offset,
  754. NULL)); // the length is tracked elsewhere
  755. FileContext = FileContext->m_Next;
  756. }
  757. CBData->BytesWritten = BytesWritten;
  758. break;
  759. }
  760. case GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED:
  761. {
  762. INTERNAL_ERROR_CHECK( ComGlobalContext != NULL );
  763. PGUID_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED CBData =
  764. (PGUID_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED) CallbackData;
  765. PCOM_SERVER_ENTRY Entry = (PCOM_SERVER_ENTRY) CBData->DataContext;
  766. if (Entry != NULL)
  767. {
  768. if (Entry->m_FileContext != NULL)
  769. {
  770. Entry->m_FileContext->m_ServerListCount--;
  771. if (Entry->m_FileContext->m_ServerListCount == 0)
  772. FUSION_DELETE_SINGLETON(Entry->m_FileContext);
  773. }
  774. FUSION_DELETE_SINGLETON(Entry);
  775. }
  776. break;
  777. }
  778. case GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE:
  779. {
  780. PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE CBData =
  781. (PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE) CallbackData;
  782. PCOM_SERVER_ENTRY Entry = (PCOM_SERVER_ENTRY) CBData->DataContext;
  783. CBData->DataSize = sizeof(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION);
  784. if (Entry->m_ProgIdBuffer.Cch() != 0)
  785. CBData->DataSize += ((Entry->m_ProgIdBuffer.Cch() + 1) * sizeof(WCHAR));
  786. if (Entry->m_ShimNameBuffer.Cch() != 0)
  787. {
  788. CBData->DataSize += sizeof(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM);
  789. if (Entry->m_RuntimeVersionBuffer.Cch() != 0)
  790. CBData->DataSize += ((Entry->m_RuntimeVersionBuffer.Cch() + 1) * sizeof(WCHAR));
  791. if (!Entry->m_IsFirstShim)
  792. CBData->DataSize += ((Entry->m_ShimNameBuffer.Cch() + 1) * sizeof(WCHAR));
  793. if (Entry->m_TypeNameBuffer.Cch() != 0)
  794. CBData->DataSize += ((Entry->m_TypeNameBuffer.Cch() + 1) * sizeof(WCHAR));
  795. }
  796. break;
  797. }
  798. case GUID_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA:
  799. {
  800. PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA CBData =
  801. (PGUID_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA) CallbackData;
  802. PCOM_SERVER_ENTRY Entry = (PCOM_SERVER_ENTRY) CBData->DataContext;
  803. PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION Info;
  804. PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM ShimInfo = NULL;
  805. PVOID Cursor = CBData->Buffer;
  806. SIZE_T BytesLeft = CBData->BufferSize;
  807. SIZE_T BytesWritten = 0;
  808. ALLOCATE_BUFFER_SPACE_TYPE(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION, Cursor, BytesLeft, BytesWritten, Info);
  809. Info->Size = sizeof(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION);
  810. Info->Flags = 0;
  811. Info->ThreadingModel = Entry->m_ThreadingModel;
  812. Info->ReferenceClsid = Entry->m_ReferenceClsid;
  813. Info->ConfiguredClsid = Entry->m_ConfiguredClsid;
  814. Info->ImplementedClsid = Entry->m_ImplementedClsid;
  815. Info->TypeLibraryId = Entry->m_TypeLibraryId;
  816. if (Entry->m_ShimNameBuffer.Cch() != 0)
  817. {
  818. PWSTR ShimName = NULL;
  819. SIZE_T OldBytesWritten = BytesWritten;
  820. SIZE_T ShimDataSize = 0;
  821. ALLOCATE_BUFFER_SPACE_TYPE(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM, Cursor, BytesLeft, BytesWritten, ShimInfo);
  822. IFW32FALSE_EXIT(
  823. Entry->m_TypeNameBuffer.Win32CopyIntoBuffer(
  824. (PWSTR *) &Cursor,
  825. &BytesLeft,
  826. &BytesWritten,
  827. ShimInfo,
  828. &ShimInfo->TypeOffset,
  829. &ShimInfo->TypeLength));
  830. ShimInfo->ModuleLength = static_cast<ULONG>(Entry->m_FileContext->m_FileNameBuffer.Cch() * sizeof(WCHAR));
  831. ShimInfo->ModuleOffset = Entry->m_FileContext->m_Offset;
  832. IFW32FALSE_EXIT(
  833. Entry->m_RuntimeVersionBuffer.Win32CopyIntoBuffer(
  834. (PWSTR *) &Cursor,
  835. &BytesLeft,
  836. &BytesWritten,
  837. ShimInfo,
  838. &ShimInfo->ShimVersionOffset,
  839. &ShimInfo->ShimVersionLength));
  840. ShimDataSize = BytesWritten - OldBytesWritten;
  841. if (Entry->m_IsFirstShim)
  842. {
  843. Info->ModuleOffset = Entry->m_FileContext->m_GlobalContext->m_FirstShimNameOffset;
  844. Info->ModuleLength = Entry->m_FileContext->m_GlobalContext->m_FirstShimNameLength;
  845. }
  846. else
  847. {
  848. IFW32FALSE_EXIT(
  849. Entry->m_ShimNameBuffer.Win32CopyIntoBuffer(
  850. (PWSTR *) &Cursor,
  851. &BytesLeft,
  852. &BytesWritten,
  853. CBData->SectionHeader,
  854. &Info->ModuleOffset,
  855. &Info->ModuleLength));
  856. }
  857. ShimInfo->Size = sizeof(ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM);
  858. ShimInfo->Flags = 0;
  859. ShimInfo->Type = Entry->m_ShimType;
  860. ShimInfo->DataLength = 0;
  861. ShimInfo->DataOffset = 0;
  862. Info->ShimDataLength = static_cast<ULONG>(ShimDataSize);
  863. Info->ShimDataOffset = static_cast<ULONG>(((ULONG_PTR) ShimInfo) - ((ULONG_PTR) Info));
  864. }
  865. else
  866. {
  867. Info->ModuleLength = static_cast<ULONG>(Entry->m_FileContext->m_FileNameBuffer.Cch() * sizeof(WCHAR));
  868. Info->ModuleOffset = Entry->m_FileContext->m_Offset;
  869. Info->ShimDataLength = 0;
  870. Info->ShimDataOffset = 0;
  871. }
  872. IFW32FALSE_EXIT(Entry->m_ProgIdBuffer.Win32CopyIntoBuffer(
  873. (PWSTR *) &Cursor,
  874. &BytesLeft,
  875. &BytesWritten,
  876. Info,
  877. &Info->ProgIdOffset,
  878. &Info->ProgIdLength));
  879. CBData->BytesWritten = BytesWritten;
  880. }
  881. }
  882. fSuccess = TRUE;
  883. Exit:
  884. return fSuccess;
  885. }