main
cpp 1,905 lines 54.5 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4 #include <mscoree.h>
5
6 // GAC related declarations
7
8 typedef struct _FUSION_INSTALL_REFERENCE_
9 {
10 DWORD cbSize;
11 DWORD dwFlags;
12 GUID guidScheme;
13 LPCWSTR szIdentifier;
14 LPCWSTR szNonCannonicalData;
15 } FUSION_INSTALL_REFERENCE;
16
17 typedef struct _FUSION_INSTALL_REFERENCE_ *LPFUSION_INSTALL_REFERENCE;
18
19 typedef const FUSION_INSTALL_REFERENCE *LPCFUSION_INSTALL_REFERENCE;
20
21 typedef struct _ASSEMBLY_INFO
22 {
23 ULONG cbAssemblyInfo;
24 DWORD dwAssemblyFlags;
25 ULARGE_INTEGER uliAssemblySizeInKB;
26 LPWSTR pszCurrentAssemblyPathBuf;
27 ULONG cchBuf;
28 } ASSEMBLY_INFO;
29
30 typedef interface IAssemblyCacheItem IAssemblyCacheItem;
31
32 MIDL_INTERFACE("e707dcde-d1cd-11d2-bab9-00c04f8eceae")
33 IAssemblyCache : public IUnknown
34 {
35 public:
36 virtual HRESULT STDMETHODCALLTYPE UninstallAssembly(
37 /* [in] */ DWORD dwFlags,
38 /* [in] */ LPCWSTR pszAssemblyName,
39 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData,
40 /* [optional][out] */ ULONG *pulDisposition) = 0;
41
42 virtual HRESULT STDMETHODCALLTYPE QueryAssemblyInfo(
43 /* [in] */ DWORD dwFlags,
44 /* [in] */ LPCWSTR pszAssemblyName,
45 /* [out][in] */ ASSEMBLY_INFO *pAsmInfo) = 0;
46
47 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyCacheItem(
48 /* [in] */ DWORD dwFlags,
49 /* [in] */ PVOID pvReserved,
50 /* [out] */ IAssemblyCacheItem **ppAsmItem,
51 /* [optional][in] */ LPCWSTR pszAssemblyName) = 0;
52
53 virtual HRESULT STDMETHODCALLTYPE CreateAssemblyScavenger(
54 /* [out] */ IUnknown **ppUnkReserved) = 0;
55
56 virtual HRESULT STDMETHODCALLTYPE InstallAssembly(
57 /* [in] */ DWORD dwFlags,
58 /* [in] */ LPCWSTR pszManifestFilePath,
59 /* [in] */ LPCFUSION_INSTALL_REFERENCE pRefData) = 0;
60 };
61
62 typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
63 typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved);
64 typedef HRESULT (__stdcall *GetFileVersionFnPtr)(LPCWSTR szFilename, _Out_writes_to_opt_(cchBuffer, *dwLength) LPWSTR szBuffer, DWORD cchBuffer, DWORD* dwLength);
65 typedef HRESULT (__stdcall *CorBindToRuntimeExFnPtr)(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv);
66
67
68 // RegistrationHelper related declarations
69 enum eInstallationFlags {
70 ifConfigureComponentsOnly = 16,
71 ifFindOrCreateTargetApplication = 4,
72 ifExpectExistingTypeLib = 1
73 };
74
75
76 // private structs
77
78 struct CPIEXEC_ROLE_ASSIGNMENT
79 {
80 WCHAR wzKey[MAX_DARWIN_KEY + 1];
81 WCHAR wzRoleName[MAX_DARWIN_COLUMN + 1];
82
83 CPIEXEC_ROLE_ASSIGNMENT* pNext;
84 };
85
86 struct CPIEXEC_METHOD
87 {
88 WCHAR wzIndex[11 + 1];
89 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
90
91 CPI_PROPERTY* pPropertyList;
92 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
93
94 CPIEXEC_METHOD* pNext;
95 };
96
97 struct CPIEXEC_INTERFACE
98 {
99 WCHAR wzIID[CPI_MAX_GUID + 1];
100
101 CPI_PROPERTY* pPropertyList;
102 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
103 CPIEXEC_METHOD* pMethodList;
104
105 CPIEXEC_INTERFACE* pNext;
106 };
107
108 struct CPIEXEC_COMPONENT
109 {
110 WCHAR wzCLSID[CPI_MAX_GUID + 1];
111
112 CPI_PROPERTY* pPropertyList;
113 CPIEXEC_ROLE_ASSIGNMENT* pRoleAssignmentList;
114 CPIEXEC_INTERFACE* pInterfaceList;
115
116 CPIEXEC_COMPONENT* pNext;
117 };
118
119 struct CPI_ASSEMBLY_ATTRIBUTES
120 {
121 int iActionType;
122 int iActionCost;
123 LPWSTR pwzKey;
124 LPWSTR pwzAssemblyName;
125 LPWSTR pwzDllPath;
126 LPWSTR pwzTlbPath;
127 LPWSTR pwzPSDllPath;
128 LPWSTR pwzAppID;
129 LPWSTR pwzPartID;
130 int iAttributes;
131 CPIEXEC_COMPONENT* pCompList;
132 };
133
134 struct CPI_ROLE_ASSIGNMENTS_ATTRIBUTES
135 {
136 int iActionType;
137 int iActionCost;
138 LPWSTR pwzKey;
139 LPWSTR pwzAppID;
140 LPWSTR pwzPartID;
141 int iRoleCount;
142 CPIEXEC_COMPONENT* pCompList;
143 };
144
145
146 // prototypes for private helper functions
147
148 static HRESULT RegisterAssembly(
149 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
150 );
151 static HRESULT UnregisterAssembly(
152 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
153 );
154 static void InitAssemblyExec();
155 static void UninitAssemblyExec();
156 static HRESULT GetRegistrationHelper(
157 IDispatch** ppiRegHlp,
158 LPCWSTR pwzAssemblyPath
159 );
160 static HRESULT GetAssemblyCacheObject(
161 IAssemblyCache** ppAssemblyCache
162 );
163 static HRESULT GetAssemblyPathFromGAC(
164 LPCWSTR pwzAssemblyName,
165 LPWSTR* ppwzAssemblyPath
166 );
167 static HRESULT RegisterDotNetAssembly(
168 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
169 );
170 static HRESULT RegisterNativeAssembly(
171 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
172 );
173 static HRESULT UnregisterDotNetAssembly(
174 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
175 );
176 static HRESULT RemoveComponents(
177 ICatalogCollection* piCompColl,
178 CPIEXEC_COMPONENT* pCompList
179 );
180 static HRESULT ReadAssemblyAttributes(
181 LPWSTR* ppwzData,
182 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
183 );
184 static void FreeAssemblyAttributes(
185 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
186 );
187 static HRESULT ReadRoleAssignmentsAttributes(
188 LPWSTR* ppwzData,
189 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
190 );
191 static void FreeRoleAssignmentsAttributes(
192 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
193 );
194 static HRESULT ConfigureComponents(
195 LPCWSTR pwzPartID,
196 LPCWSTR pwzAppID,
197 CPIEXEC_COMPONENT* pCompList,
198 BOOL fCreate,
199 BOOL fProgress
200 );
201 static HRESULT ConfigureInterfaces(
202 ICatalogCollection* piCompColl,
203 ICatalogObject* piCompObj,
204 CPIEXEC_INTERFACE* pIntfList,
205 BOOL fCreate
206 );
207 static HRESULT ConfigureMethods(
208 ICatalogCollection* piIntfColl,
209 ICatalogObject* piIntfObj,
210 CPIEXEC_METHOD* pMethList,
211 BOOL fCreate
212 );
213 static HRESULT ConfigureRoleAssignments(
214 LPCWSTR pwzCollName,
215 ICatalogCollection* piCompColl,
216 ICatalogObject* piCompObj,
217 CPIEXEC_ROLE_ASSIGNMENT* pRoleList,
218 BOOL fCreate
219 );
220 static HRESULT ReadComponentList(
221 LPWSTR* ppwzData,
222 CPIEXEC_COMPONENT** ppCompList
223 );
224 static HRESULT ReadInterfaceList(
225 LPWSTR* ppwzData,
226 CPIEXEC_INTERFACE** ppIntfList
227 );
228 static HRESULT ReadMethodList(
229 LPWSTR* ppwzData,
230 CPIEXEC_METHOD** ppMethList
231 );
232 static HRESULT ReadRoleAssignmentList(
233 LPWSTR* ppwzData,
234 CPIEXEC_ROLE_ASSIGNMENT** ppRoleList
235 );
236 static void FreeComponentList(
237 CPIEXEC_COMPONENT* pList
238 );
239 static void FreeInterfaceList(
240 CPIEXEC_INTERFACE* pList
241 );
242 static void FreeMethodList(
243 CPIEXEC_METHOD* pList
244 );
245 static void FreeRoleAssignmentList(
246 CPIEXEC_ROLE_ASSIGNMENT* pList
247 );
248
249
250 // variables
251
252 static IDispatch* gpiRegHlp;
253 static IAssemblyCache* gpAssemblyCache;
254 static HMODULE ghMscoree;
255 static HMODULE ghFusion;
256
257
258 // function definitions
259
260 HRESULT CpiConfigureAssemblies(
261 LPWSTR* ppwzData,
262 HANDLE hRollbackFile
263 )
264 {
265 HRESULT hr = S_OK;
266
267 CPI_ASSEMBLY_ATTRIBUTES attrs;
268 ::ZeroMemory(&attrs, sizeof(attrs));
269
270 // initialize
271 InitAssemblyExec();
272
273 // read action text
274 hr = CpiActionStartMessage(ppwzData, FALSE);
275 ExitOnFailure(hr, "Failed to send action start message");
276
277 // get count
278 int iCnt = 0;
279 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
280 ExitOnFailure(hr, "Failed to read count");
281
282 // write count to rollback file
283 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
284 ExitOnFailure(hr, "Failed to write count to rollback file");
285
286 for (int i = 0; i < iCnt; i++)
287 {
288 // read attributes from CustomActionData
289 hr = ReadAssemblyAttributes(ppwzData, &attrs);
290 ExitOnFailure(hr, "Failed to read assembly attributes");
291
292 // write key to rollback file
293 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
294 ExitOnFailure(hr, "Failed to write key to rollback file");
295
296 // action
297 switch (attrs.iActionType)
298 {
299 case atCreate:
300 hr = RegisterAssembly(&attrs);
301 ExitOnFailure(hr, "Failed to register assembly, key: %S", attrs.pwzKey);
302 break;
303 case atRemove:
304 hr = UnregisterAssembly(&attrs);
305 ExitOnFailure(hr, "Failed to unregister assembly, key: %S", attrs.pwzKey);
306 break;
307 default:
308 hr = S_OK;
309 break;
310 }
311
312 if (S_FALSE == hr)
313 ExitFunction(); // aborted by user
314
315 // write completion status to rollback file
316 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
317 ExitOnFailure(hr, "Failed to write completion status to rollback file");
318
319 // progress
320 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
321 ExitOnFailure(hr, "Failed to update progress");
322 }
323
324 hr = S_OK;
325
326 LExit:
327 // clean up
328 FreeAssemblyAttributes(&attrs);
329
330 // uninitialize
331 UninitAssemblyExec();
332
333 return hr;
334 }
335
336 HRESULT CpiRollbackConfigureAssemblies(
337 LPWSTR* ppwzData,
338 CPI_ROLLBACK_DATA* pRollbackDataList
339 )
340 {
341 HRESULT hr = S_OK;
342
343 int iRollbackStatus;
344
345 CPI_ASSEMBLY_ATTRIBUTES attrs;
346 ::ZeroMemory(&attrs, sizeof(attrs));
347
348 // initialize
349 InitAssemblyExec();
350
351 // read action text
352 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
353 ExitOnFailure(hr, "Failed to send action start message");
354
355 // get count
356 int iCnt = 0;
357 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
358 ExitOnFailure(hr, "Failed to read count");
359
360 for (int i = 0; i < iCnt; i++)
361 {
362 // read attributes from CustomActionData
363 hr = ReadAssemblyAttributes(ppwzData, &attrs);
364 ExitOnFailure(hr, "Failed to read assembly attributes");
365
366 // rollback status
367 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
368
369 if (S_FALSE == hr)
370 continue; // not found, nothing to rollback
371
372 // action
373 switch (attrs.iActionType)
374 {
375 case atCreate:
376 hr = RegisterAssembly(&attrs);
377 if (FAILED(hr))
378 WcaLog(LOGMSG_STANDARD, "Failed to register assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
379 break;
380 case atRemove:
381 hr = UnregisterAssembly(&attrs);
382 if (FAILED(hr))
383 WcaLog(LOGMSG_STANDARD, "Failed to unregister assembly, hr: 0x%x, key: %S", hr, attrs.pwzKey);
384 break;
385 }
386
387 // check rollback status
388 if (0 == iRollbackStatus)
389 continue; // operation did not complete, skip progress
390
391 // progress
392 hr = WcaProgressMessage(attrs.iActionCost, FALSE);
393 ExitOnFailure(hr, "Failed to update progress");
394 }
395
396 hr = S_OK;
397
398 LExit:
399 // clean up
400 FreeAssemblyAttributes(&attrs);
401
402 // uninitialize
403 UninitAssemblyExec();
404
405 return hr;
406 }
407
408 HRESULT CpiConfigureRoleAssignments(
409 LPWSTR* ppwzData,
410 HANDLE hRollbackFile
411 )
412 {
413 HRESULT hr = S_OK;
414
415 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
416 ::ZeroMemory(&attrs, sizeof(attrs));
417
418 // read action text
419 hr = CpiActionStartMessage(ppwzData, FALSE);
420 ExitOnFailure(hr, "Failed to send action start message");
421
422 // get count
423 int iCnt = 0;
424 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
425 ExitOnFailure(hr, "Failed to read count");
426
427 // write count to rollback file
428 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt);
429 ExitOnFailure(hr, "Failed to write count to rollback file");
430
431 for (int i = 0; i < iCnt; i++)
432 {
433 // read attributes from CustomActionData
434 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
435 ExitOnFailure(hr, "Failed to read role assignments attributes");
436
437 // write key to rollback file
438 hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey);
439 ExitOnFailure(hr, "Failed to write key to rollback file");
440
441 // action
442 if (atNoOp != attrs.iActionType)
443 {
444 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
445 ExitOnFailure(hr, "Failed to configure components");
446
447 if (S_FALSE == hr)
448 ExitFunction(); // aborted by user
449 }
450
451 // write completion status to rollback file
452 hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1);
453 ExitOnFailure(hr, "Failed to write completion status to rollback file");
454
455 // progress
456 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
457 ExitOnFailure(hr, "Failed to update progress");
458 }
459
460 hr = S_OK;
461
462 LExit:
463 // clean up
464 FreeRoleAssignmentsAttributes(&attrs);
465
466 return hr;
467 }
468
469 HRESULT CpiRollbackConfigureRoleAssignments(
470 LPWSTR* ppwzData,
471 CPI_ROLLBACK_DATA* pRollbackDataList
472 )
473 {
474 HRESULT hr = S_OK;
475
476 int iRollbackStatus;
477
478 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES attrs;
479 ::ZeroMemory(&attrs, sizeof(attrs));
480
481 // read action text
482 hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList);
483 ExitOnFailure(hr, "Failed to send action start message");
484
485 // get count
486 int iCnt = 0;
487 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
488 ExitOnFailure(hr, "Failed to read count");
489
490 for (int i = 0; i < iCnt; i++)
491 {
492 // read attributes from CustomActionData
493 hr = ReadRoleAssignmentsAttributes(ppwzData, &attrs);
494 ExitOnFailure(hr, "Failed to read role assignments attributes");
495
496 // rollback status
497 hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus);
498
499 if (S_FALSE == hr)
500 continue; // not found, nothing to rollback
501
502 // action
503 if (atNoOp != attrs.iActionType)
504 {
505 hr = ConfigureComponents(attrs.pwzPartID, attrs.pwzAppID, attrs.pCompList, atCreate == attrs.iActionType, TRUE);
506 ExitOnFailure(hr, "Failed to configure components");
507
508 if (S_FALSE == hr)
509 ExitFunction(); // aborted by user
510 }
511
512 // check rollback status
513 if (0 == iRollbackStatus)
514 continue; // operation did not complete, skip progress
515
516 // progress
517 hr = WcaProgressMessage(attrs.iActionCost * attrs.iRoleCount, FALSE);
518 ExitOnFailure(hr, "Failed to update progress");
519 }
520
521 hr = S_OK;
522
523 LExit:
524 // clean up
525 FreeRoleAssignmentsAttributes(&attrs);
526
527 return hr;
528 }
529
530
531 // helper function definitions
532
533 static HRESULT RegisterAssembly(
534 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
535 )
536 {
537 HRESULT hr = S_OK;
538
539 // progress message
540 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
541 ExitOnFailure(hr, "Failed to send progress messages");
542
543 if (S_FALSE == hr)
544 ExitFunction(); // aborted by user
545
546 // log
547 WcaLog(LOGMSG_VERBOSE, "Registering assembly, key: %S", pAttrs->pwzKey);
548
549 // extract path from GAC
550 if (pAttrs->iAttributes & aaPathFromGAC)
551 {
552 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
553 if (S_FALSE == hr)
554 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
555 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
556
557 // log
558 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
559 }
560
561 // .net assembly
562 if (pAttrs->iAttributes & aaDotNetAssembly)
563 {
564 hr = RegisterDotNetAssembly(pAttrs);
565 ExitOnFailure(hr, "Failed to register .NET assembly");
566 }
567
568 // native assembly
569 else
570 {
571 hr = RegisterNativeAssembly(pAttrs);
572 ExitOnFailure(hr, "Failed to register native assembly");
573 }
574
575 // configure components
576 if (pAttrs->pCompList)
577 {
578 hr = ConfigureComponents(pAttrs->pwzPartID, pAttrs->pwzAppID, pAttrs->pCompList, TRUE, FALSE);
579 ExitOnFailure(hr, "Failed to configure components");
580 }
581
582 hr = S_OK;
583
584 LExit:
585 return hr;
586 }
587
588 static HRESULT UnregisterAssembly(
589 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
590 )
591 {
592 HRESULT hr = S_OK;
593
594 long lChanges = 0;
595
596 ICatalogCollection* piColl = NULL;
597 ICatalogObject* piObj = NULL;
598
599 // progress message
600 hr = CpiActionDataMessage(1, (pAttrs->iAttributes & aaPathFromGAC) ? pAttrs->pwzAssemblyName : pAttrs->pwzDllPath);
601 ExitOnFailure(hr, "Failed to send progress messages");
602
603 if (S_FALSE == hr)
604 ExitFunction(); // aborted by user
605
606 // log
607 WcaLog(LOGMSG_VERBOSE, "Unregistering assembly, key: %S", pAttrs->pwzKey);
608
609 // extract path from GAC
610 if (pAttrs->iAttributes & aaPathFromGAC)
611 {
612 hr = GetAssemblyPathFromGAC(pAttrs->pwzAssemblyName, &pAttrs->pwzDllPath);
613 ExitOnFailure(hr, "Failed to get path for assembly from GAC");
614
615 if (S_FALSE == hr)
616 {
617 WcaLog(LOGMSG_VERBOSE, "Unable to locate assembly in GAC, assembly will not be unregistered from COM+, key: %S", pAttrs->pwzKey);
618 ExitFunction1(hr = S_OK);
619 }
620
621 // log
622 WcaLog(LOGMSG_VERBOSE, "Assembly path extracted from GAC, key: %S, path: '%S'", pAttrs->pwzKey, pAttrs->pwzDllPath);
623 }
624
625 // .NET assembly
626 if (pAttrs->iAttributes & aaDotNetAssembly)
627 {
628 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
629 {
630 // When unregistering a .net assembly using the RegistrationHelper class, and the application is
631 // left empty after all components in the assembly are removed, the RegistrationHelper class also
632 // attempts to remove the application for some reason. However, it does not handle the situation
633 // when the application has its deleteable property set to false, and will simply fail if this is
634 // the case. This is the reason we are clearing the deleatable property of the application here.
635 //
636 // TODO: handle rollbacks
637
638 // get applications collection
639 hr = CpiExecGetApplicationsCollection(pAttrs->pwzPartID, &piColl);
640 ExitOnFailure(hr, "Failed to get applications collection");
641
642 if (S_FALSE == hr)
643 {
644 // applications collection not found
645 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve applications collection, nothing to delete, key: %S", pAttrs->pwzKey);
646 ExitFunction1(hr = S_OK);
647 }
648
649 // find application object
650 hr = CpiFindCollectionObjectByStringKey(piColl, pAttrs->pwzAppID, &piObj);
651 ExitOnFailure(hr, "Failed to find application object");
652
653 if (S_FALSE == hr)
654 {
655 // application not found
656 WcaLog(LOGMSG_VERBOSE, "Unable to find application object, nothing to delete, key: %S", pAttrs->pwzKey);
657 ExitFunction1(hr = S_OK);
658 }
659
660 // reset deleteable property
661 hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
662 ExitOnFailure(hr, "Failed to reset deleteable property");
663 }
664
665 // unregister assembly
666 hr = UnregisterDotNetAssembly(pAttrs);
667 ExitOnFailure(hr, "Failed to unregister .NET assembly");
668 }
669
670 // native assembly
671 else
672 {
673 // get components collection
674 hr = CpiGetComponentsCollection(pAttrs->pwzPartID, pAttrs->pwzAppID, &piColl);
675 ExitOnFailure(hr, "Failed to get components collection");
676
677 if (S_FALSE == hr)
678 {
679 // components collection not found
680 WcaLog(LOGMSG_VERBOSE, "Unable to retrieve components collection, nothing to delete, key: %S", pAttrs->pwzKey);
681 ExitFunction1(hr = S_OK);
682 }
683
684 // remove components
685 hr = RemoveComponents(piColl, pAttrs->pCompList);
686 ExitOnFailure(hr, "Failed to get remove components");
687
688 // save changes
689 hr = piColl->SaveChanges(&lChanges);
690 if (COMADMIN_E_OBJECTERRORS == hr)
691 CpiLogCatalogErrorInfo();
692 ExitOnFailure(hr, "Failed to save changes");
693 }
694
695 hr = S_OK;
696
697 LExit:
698 // clean up
699 ReleaseObject(piColl);
700 ReleaseObject(piObj);
701
702 return hr;
703 }
704
705 static void InitAssemblyExec()
706 {
707 gpiRegHlp = NULL;
708 gpAssemblyCache = NULL;
709 ghMscoree = NULL;
710 ghFusion = NULL;
711 }
712
713 static void UninitAssemblyExec()
714 {
715 ReleaseObject(gpiRegHlp);
716 ReleaseObject(gpAssemblyCache);
717 if (ghFusion)
718 ::FreeLibrary(ghFusion);
719 if (ghMscoree)
720 ::FreeLibrary(ghMscoree);
721 }
722
723 static HRESULT GetRegistrationHelper(
724 IDispatch** ppiRegHlp,
725 LPCWSTR pwzAssemblyPath
726 )
727 {
728 HRESULT hr = S_OK;
729 wchar_t pwzVersion[MAX_PATH];
730 DWORD pcchVersionLen = MAX_PATH;
731 ICLRRuntimeHost* runtimeHost = NULL;
732
733 if (!ghMscoree)
734 {
735 ghMscoree = ::LoadLibraryW(L"mscoree.dll");
736 ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
737 }
738 GetFileVersionFnPtr GetFileVersion = (GetFileVersionFnPtr)::GetProcAddress(ghMscoree, "GetFileVersion");
739 ExitOnNull(GetFileVersion, hr, E_FAIL, "Failed to GetProcAddress for 'GetFileVersion' from 'mscoree.dll'");
740 hr = GetFileVersion(pwzAssemblyPath, pwzVersion, pcchVersionLen, &pcchVersionLen);
741
742 if (!gpiRegHlp)
743 {
744 CLSID CLSID_RegistrationHelper{};
745 hr = ::CLSIDFromProgID(OLESTR("System.EnterpriseServices.RegistrationHelper"), &CLSID_RegistrationHelper);
746 ExitOnFailure(hr, "Failed to identify CLSID for 'System.EnterpriseServices.RegistrationHelper'");
747
748 // NOTE: The 'CoreBindToRuntimeEx' method is DEPRECATED in .NET v4.
749 // HOWEVER, we might be running in an earlier context at this point so we don't want to rely upon stuff that is particularly v4 dependent.
750 // Even if we are about to try to fire up a v4 runtime.
751 // The .NET v4 runtime with STARTUP_LOADER_SAFEMODE flag (to disable version checking of loaded assemblies) is what lets us launch the
752 // RegistrationHelper. The v4 RegistrationHelper is able to register both v4 and v3 assemblies however, so if we can get it, we most as well
753 // use it.
754 CorBindToRuntimeExFnPtr CorBindToRuntimeEx = (CorBindToRuntimeExFnPtr)::GetProcAddress(ghMscoree, "CorBindToRuntimeEx");
755 hr = CorBindToRuntimeEx(L"v4.0.30319", L"wks", STARTUP_LOADER_SAFEMODE, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);
756 // we ignore the HRESULT here. If it worked, great, we'll use it moving forward. If it didn't work, we'll end up trying to resort to legacy .NET FW
757 // when we just try the COM Create below
758
759 // create registration helper object
760 // This will be created in the .NET FW 4 version if we managed to launch it above, or in the .NET FW <4 version based on the COM dispatch otherwise
761 hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
762 ExitOnFailure(hr, "Failed to create registration helper object");
763 }
764
765 gpiRegHlp->AddRef();
766 *ppiRegHlp = gpiRegHlp;
767
768 hr = S_OK;
769
770 LExit:
771 return hr;
772 }
773
774 static HRESULT GetAssemblyCacheObject(
775 IAssemblyCache** ppAssemblyCache
776 )
777 {
778 HRESULT hr = S_OK;
779
780 if (!gpAssemblyCache)
781 {
782 // mscoree.dll
783 if (!ghMscoree)
784 {
785 // load mscoree.dll
786 ghMscoree = ::LoadLibraryW(L"mscoree.dll");
787 ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
788 }
789
790 // fusion.dll
791 if (!ghFusion)
792 {
793 // get LoadLibraryShim function address
794 LoadLibraryShimFunc pfnLoadLibraryShim = (LoadLibraryShimFunc)::GetProcAddress(ghMscoree, "LoadLibraryShim");
795 ExitOnNull(pfnLoadLibraryShim, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for LoadLibraryShim() function");
796
797 // load fusion.dll
798 hr = pfnLoadLibraryShim(L"fusion.dll", NULL, NULL, &ghFusion);
799 ExitOnFailure(hr, "Failed to load fusion.dll");
800 }
801
802 // get CreateAssemblyCache function address
803 CreateAssemblyCacheFunc pfnCreateAssemblyCache = (CreateAssemblyCacheFunc)::GetProcAddress(ghFusion, "CreateAssemblyCache");
804 ExitOnNull(pfnCreateAssemblyCache, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for CreateAssemblyCache() function");
805
806 // create AssemblyCache object
807 hr = pfnCreateAssemblyCache(&gpAssemblyCache, 0);
808 ExitOnFailure(hr, "Failed to create AssemblyCache object");
809 }
810
811 gpAssemblyCache->AddRef();
812 *ppAssemblyCache = gpAssemblyCache;
813
814 hr = S_OK;
815
816 LExit:
817 return hr;
818 }
819
820 static HRESULT GetAssemblyPathFromGAC(
821 LPCWSTR pwzAssemblyName,
822 LPWSTR* ppwzAssemblyPath
823 )
824 {
825 HRESULT hr = S_OK;
826
827 IAssemblyCache* pAssemblyCache = NULL;
828
829 ASSEMBLY_INFO assemblyInfo;
830 WCHAR wzPathBuf[MAX_PATH];
831
832 ::ZeroMemory(&assemblyInfo, sizeof(ASSEMBLY_INFO));
833 ::ZeroMemory(wzPathBuf, countof(wzPathBuf));
834
835 // get AssemblyCache object
836 hr = GetAssemblyCacheObject(&pAssemblyCache);
837 ExitOnFailure(hr, "Failed to get AssemblyCache object");
838
839 // get assembly info
840 assemblyInfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
841 assemblyInfo.pszCurrentAssemblyPathBuf = wzPathBuf;
842 assemblyInfo.cchBuf = countof(wzPathBuf);
843
844 hr = pAssemblyCache->QueryAssemblyInfo(0, pwzAssemblyName, &assemblyInfo);
845 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
846 ExitFunction1(hr = S_FALSE);
847 ExitOnFailure(hr, "Failed to get assembly info");
848
849 // copy assembly path
850 hr = StrAllocString(ppwzAssemblyPath, wzPathBuf, 0);
851 ExitOnFailure(hr, "Failed to copy assembly path");
852
853 hr = S_OK;
854
855 LExit:
856 // clean up
857 ReleaseObject(pAssemblyCache);
858
859 return hr;
860 }
861
862 static HRESULT RegisterDotNetAssembly(
863 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
864 )
865 {
866 HRESULT hr = S_OK;
867
868 IDispatch* piRegHlp = NULL;
869
870 DISPID dispid;
871 BSTR bstrMember = NULL;
872
873 long lInstallationFlags = 0;
874
875 VARIANTARG rgvarg[5];
876 DISPPARAMS dispparams;
877 EXCEPINFO excepInfo;
878
879 BSTR bstrPartName = NULL;
880 BSTR bstrAppName = NULL;
881 BSTR bstrDllPath = NULL;
882 BSTR bstrTlbPath = NULL;
883
884 ::ZeroMemory(rgvarg, sizeof(rgvarg));
885 ::ZeroMemory(&dispparams, sizeof(dispparams));
886 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
887
888 bstrMember = ::SysAllocString(L"InstallAssembly_2");
889 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
890
891 // create BSTRs for parameters
892 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
893 {
894 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
895 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
896 }
897
898 if (pAttrs->pwzAppID && *pAttrs->pwzAppID)
899 {
900 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
901 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
902 }
903
904 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
905 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
906
907 if (pAttrs->pwzTlbPath && *pAttrs->pwzTlbPath)
908 {
909 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath);
910 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
911 }
912
913 // get registration helper object
914 hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
915 ExitOnFailure(hr, "Failed to get registration helper object");
916
917 // get dispatch id of InstallAssembly() method
918 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
919 ExitOnFailure(hr, "Failed to get dispatch id of InstallAssembly() method");
920
921 // set installation flags
922 lInstallationFlags = ifExpectExistingTypeLib;
923
924 if (!bstrAppName)
925 lInstallationFlags |= ifFindOrCreateTargetApplication;
926
927 // invoke InstallAssembly() method
928 rgvarg[0].vt = VT_I4;
929 rgvarg[0].lVal = lInstallationFlags;
930 rgvarg[1].vt = VT_BYREF|VT_BSTR;
931 rgvarg[1].pbstrVal = &bstrTlbPath;
932 rgvarg[2].vt = VT_BSTR;
933 rgvarg[2].bstrVal = bstrPartName;
934 rgvarg[3].vt = VT_BYREF|VT_BSTR;
935 rgvarg[3].pbstrVal = &bstrAppName;
936 rgvarg[4].vt = VT_BSTR;
937 rgvarg[4].bstrVal = bstrDllPath;
938 dispparams.rgvarg = rgvarg;
939 dispparams.cArgs = 5;
940 dispparams.cNamedArgs = 0;
941
942 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
943 if (DISP_E_EXCEPTION == hr)
944 {
945 // log exception information
946 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
947 {
948 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
949 excepInfo.wCode, excepInfo.bstrSource,
950 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
951 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
952 excepInfo.dwHelpContext);
953 }
954 }
955 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.InstallAssembly() method");
956
957 hr = S_OK;
958
959 LExit:
960 // clean up
961 ReleaseObject(piRegHlp);
962
963 ReleaseBSTR(bstrMember);
964
965 ReleaseBSTR(excepInfo.bstrSource);
966 ReleaseBSTR(excepInfo.bstrDescription);
967 ReleaseBSTR(excepInfo.bstrHelpFile);
968
969 ReleaseBSTR(bstrPartName);
970 ReleaseBSTR(bstrAppName);
971 ReleaseBSTR(bstrDllPath);
972 ReleaseBSTR(bstrTlbPath);
973
974 return hr;
975 }
976
977 static HRESULT RegisterNativeAssembly(
978 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
979 )
980 {
981 HRESULT hr = S_OK;
982
983 ICOMAdminCatalog* piCatalog = NULL;
984 ICOMAdminCatalog2* piCatalog2 = NULL;
985 BSTR bstrGlobPartID = NULL;
986
987 BSTR bstrPartID = NULL;
988 BSTR bstrAppID = NULL;
989 BSTR bstrDllPath = NULL;
990 BSTR bstrTlbPath = NULL;
991 BSTR bstrPSDllPath = NULL;
992
993 // create BSTRs for parameters
994 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
995 {
996 bstrPartID = ::SysAllocString(pAttrs->pwzPartID);
997 ExitOnNull(bstrPartID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
998 }
999
1000 bstrAppID = ::SysAllocString(pAttrs->pwzAppID);
1001 ExitOnNull(bstrAppID, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
1002
1003 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
1004 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
1005
1006 bstrTlbPath = ::SysAllocString(pAttrs->pwzTlbPath ? pAttrs->pwzTlbPath : L"");
1007 ExitOnNull(bstrTlbPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for tlb path");
1008
1009 bstrPSDllPath = ::SysAllocString(pAttrs->pwzPSDllPath ? pAttrs->pwzPSDllPath : L"");
1010 ExitOnNull(bstrPSDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for proxy/stub dll path");
1011
1012 // get catalog
1013 hr = CpiExecGetAdminCatalog(&piCatalog);
1014 ExitOnFailure(hr, "Failed to get COM+ admin catalog");
1015
1016 // get ICOMAdminCatalog2 interface
1017 hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2);
1018
1019 // COM+ 1.5 or later
1020 if (E_NOINTERFACE != hr)
1021 {
1022 ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface");
1023
1024 // partition id
1025 if (!bstrPartID)
1026 {
1027 // get global partition id
1028 hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID);
1029 ExitOnFailure(hr, "Failed to get global partition id");
1030 }
1031
1032 // set current partition
1033 hr = piCatalog2->put_CurrentPartition(bstrPartID ? bstrPartID : bstrGlobPartID);
1034 ExitOnFailure(hr, "Failed to set current partition");
1035 }
1036
1037 // COM+ pre 1.5
1038 else
1039 {
1040 // this version of COM+ does not support partitions, make sure a partition was not specified
1041 if (bstrPartID)
1042 ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+");
1043 }
1044
1045 // install event classes
1046 if (pAttrs->iAttributes & aaEventClass)
1047 {
1048 hr = piCatalog->InstallEventClass(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1049 if (COMADMIN_E_OBJECTERRORS == hr)
1050 CpiLogCatalogErrorInfo();
1051 ExitOnFailure(hr, "Failed to install event classes");
1052 }
1053
1054 // install components
1055 else
1056 {
1057 hr = piCatalog->InstallComponent(bstrAppID, bstrDllPath, bstrTlbPath, bstrPSDllPath);
1058 if (COMADMIN_E_OBJECTERRORS == hr)
1059 CpiLogCatalogErrorInfo();
1060 ExitOnFailure(hr, "Failed to install components");
1061 }
1062
1063 hr = S_OK;
1064
1065 LExit:
1066 // clean up
1067 ReleaseObject(piCatalog);
1068 ReleaseObject(piCatalog2);
1069 ReleaseBSTR(bstrGlobPartID);
1070
1071 ReleaseBSTR(bstrPartID);
1072 ReleaseBSTR(bstrAppID);
1073 ReleaseBSTR(bstrDllPath);
1074 ReleaseBSTR(bstrTlbPath);
1075 ReleaseBSTR(bstrPSDllPath);
1076
1077 return hr;
1078 }
1079
1080 static HRESULT UnregisterDotNetAssembly(
1081 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1082 )
1083 {
1084 HRESULT hr = S_OK;
1085
1086 IDispatch* piRegHlp = NULL;
1087
1088 DISPID dispid;
1089 BSTR bstrMember = NULL;
1090
1091 VARIANTARG rgvarg[3];
1092 DISPPARAMS dispparams;
1093 EXCEPINFO excepInfo;
1094
1095 BSTR bstrPartName = NULL;
1096 BSTR bstrAppName = NULL;
1097 BSTR bstrDllPath = NULL;
1098
1099 ::ZeroMemory(rgvarg, sizeof(rgvarg));
1100 ::ZeroMemory(&dispparams, sizeof(dispparams));
1101 ::ZeroMemory(&excepInfo, sizeof(excepInfo));
1102
1103 bstrMember = ::SysAllocString(L"UninstallAssembly_2");
1104 ExitOnNull(bstrMember, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for method name");
1105
1106 // create BSTRs for parameters
1107 if (pAttrs->pwzPartID && *pAttrs->pwzPartID)
1108 {
1109 bstrPartName = ::SysAllocString(pAttrs->pwzPartID);
1110 ExitOnNull(bstrPartName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for partition id");
1111 }
1112
1113 bstrAppName = ::SysAllocString(pAttrs->pwzAppID);
1114 ExitOnNull(bstrAppName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for application id");
1115
1116 bstrDllPath = ::SysAllocString(pAttrs->pwzDllPath);
1117 ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");
1118
1119 // get registration helper object
1120 hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
1121 ExitOnFailure(hr, "Failed to get registration helper object");
1122
1123 // get dispatch id of UninstallAssembly() method
1124 hr = piRegHlp->GetIDsOfNames(IID_NULL, &bstrMember, 1, LOCALE_USER_DEFAULT, &dispid);
1125 ExitOnFailure(hr, "Failed to get dispatch id of UninstallAssembly() method");
1126
1127 // invoke UninstallAssembly() method
1128 rgvarg[0].vt = VT_BSTR;
1129 rgvarg[0].bstrVal = bstrPartName;
1130 rgvarg[1].vt = VT_BSTR;
1131 rgvarg[1].bstrVal = bstrAppName;
1132 rgvarg[2].vt = VT_BSTR;
1133 rgvarg[2].bstrVal = bstrDllPath;
1134 dispparams.rgvarg = rgvarg;
1135 dispparams.cArgs = 3;
1136 dispparams.cNamedArgs = 0;
1137
1138 hr = piRegHlp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, NULL, &excepInfo, NULL);
1139 if (DISP_E_EXCEPTION == hr)
1140 {
1141 // log exception information
1142 if (!excepInfo.pfnDeferredFillIn || (excepInfo.pfnDeferredFillIn && SUCCEEDED(excepInfo.pfnDeferredFillIn(&excepInfo))))
1143 {
1144 WcaLog(LOGMSG_STANDARD, "ExceptionInfo: Code='%hu', Source='%S', Description='%S', HelpFile='%S', HelpContext='%u'",
1145 excepInfo.wCode, excepInfo.bstrSource,
1146 excepInfo.bstrDescription ? excepInfo.bstrDescription : L"",
1147 excepInfo.bstrHelpFile ? excepInfo.bstrHelpFile : L"",
1148 excepInfo.dwHelpContext);
1149 }
1150 }
1151 ExitOnFailure(hr, "Failed to invoke RegistrationHelper.UninstallAssembly() method");
1152
1153 hr = S_OK;
1154
1155 LExit:
1156 // clean up
1157 ReleaseObject(piRegHlp);
1158
1159 ReleaseBSTR(bstrMember);
1160
1161 ReleaseBSTR(excepInfo.bstrSource);
1162 ReleaseBSTR(excepInfo.bstrDescription);
1163 ReleaseBSTR(excepInfo.bstrHelpFile);
1164
1165 ReleaseBSTR(bstrPartName);
1166 ReleaseBSTR(bstrAppName);
1167 ReleaseBSTR(bstrDllPath);
1168
1169 return hr;
1170 }
1171
1172 static HRESULT RemoveComponents(
1173 ICatalogCollection* piCompColl,
1174 CPIEXEC_COMPONENT* pCompList
1175 )
1176 {
1177 HRESULT hr = S_OK;
1178
1179 for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1180 {
1181 // remove
1182 hr = CpiRemoveCollectionObject(piCompColl, pItm->wzCLSID, NULL, FALSE);
1183 ExitOnFailure(hr, "Failed to remove component");
1184
1185 if (S_FALSE == hr)
1186 WcaLog(LOGMSG_VERBOSE, "Component not found, nothing to delete, key: %S", pItm->wzCLSID);
1187 }
1188
1189 hr = S_OK;
1190
1191 LExit:
1192 return hr;
1193 }
1194
1195 static HRESULT ReadAssemblyAttributes(
1196 LPWSTR* ppwzData,
1197 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1198 )
1199 {
1200 HRESULT hr = S_OK;
1201
1202 // read attributes
1203 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1204 ExitOnFailure(hr, "Failed to read action type");
1205 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1206 ExitOnFailure(hr, "Failed to read action cost");
1207 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1208 ExitOnFailure(hr, "Failed to read key");
1209 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAssemblyName);
1210 ExitOnFailure(hr, "Failed to read assembly name");
1211 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDllPath);
1212 ExitOnFailure(hr, "Failed to read dll path");
1213 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzTlbPath);
1214 ExitOnFailure(hr, "Failed to read tlb path");
1215 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPSDllPath);
1216 ExitOnFailure(hr, "Failed to read proxy-stub dll path");
1217 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes);
1218 ExitOnFailure(hr, "Failed to read attributes");
1219 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1220 ExitOnFailure(hr, "Failed to read application id");
1221 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1222 ExitOnFailure(hr, "Failed to read partition id");
1223
1224 // free existing component list
1225 if (pAttrs->pCompList)
1226 {
1227 FreeComponentList(pAttrs->pCompList);
1228 pAttrs->pCompList = NULL;
1229 }
1230
1231 // read components
1232 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1233 ExitOnFailure(hr, "Failed to read components");
1234
1235 hr = S_OK;
1236
1237 LExit:
1238 return hr;
1239 }
1240
1241 static void FreeAssemblyAttributes(
1242 CPI_ASSEMBLY_ATTRIBUTES* pAttrs
1243 )
1244 {
1245 ReleaseStr(pAttrs->pwzKey);
1246 ReleaseStr(pAttrs->pwzAssemblyName);
1247 ReleaseStr(pAttrs->pwzDllPath);
1248 ReleaseStr(pAttrs->pwzTlbPath);
1249 ReleaseStr(pAttrs->pwzPSDllPath);
1250 ReleaseStr(pAttrs->pwzAppID);
1251 ReleaseStr(pAttrs->pwzPartID);
1252
1253 if (pAttrs->pCompList)
1254 FreeComponentList(pAttrs->pCompList);
1255 }
1256
1257 static HRESULT ReadRoleAssignmentsAttributes(
1258 LPWSTR* ppwzData,
1259 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1260 )
1261 {
1262 HRESULT hr = S_OK;
1263
1264 // read attributes
1265 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType);
1266 ExitOnFailure(hr, "Failed to read action type");
1267 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost);
1268 ExitOnFailure(hr, "Failed to read action cost");
1269 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
1270 ExitOnFailure(hr, "Failed to read key");
1271 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iRoleCount);
1272 ExitOnFailure(hr, "Failed to read role assignments count");
1273 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID);
1274 ExitOnFailure(hr, "Failed to read application id");
1275 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID);
1276 ExitOnFailure(hr, "Failed to read partition id");
1277
1278 // free existing component list
1279 if (pAttrs->pCompList)
1280 {
1281 FreeComponentList(pAttrs->pCompList);
1282 pAttrs->pCompList = NULL;
1283 }
1284
1285 // read components
1286 hr = ReadComponentList(ppwzData, &pAttrs->pCompList);
1287 ExitOnFailure(hr, "Failed to read components");
1288
1289 hr = S_OK;
1290
1291 LExit:
1292 return hr;
1293 }
1294
1295 static void FreeRoleAssignmentsAttributes(
1296 CPI_ROLE_ASSIGNMENTS_ATTRIBUTES* pAttrs
1297 )
1298 {
1299 ReleaseStr(pAttrs->pwzKey);
1300 ReleaseStr(pAttrs->pwzAppID);
1301 ReleaseStr(pAttrs->pwzPartID);
1302
1303 if (pAttrs->pCompList)
1304 FreeComponentList(pAttrs->pCompList);
1305 }
1306
1307
1308 static HRESULT ConfigureComponents(
1309 LPCWSTR pwzPartID,
1310 LPCWSTR pwzAppID,
1311 CPIEXEC_COMPONENT* pCompList,
1312 BOOL fCreate,
1313 BOOL fProgress
1314 )
1315 {
1316 HRESULT hr = S_OK;
1317
1318 ICatalogCollection* piCompColl = NULL;
1319 ICatalogObject* piCompObj = NULL;
1320
1321 long lChanges = 0;
1322
1323 // get components collection
1324 hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl);
1325 if (S_FALSE == hr)
1326 if (fCreate)
1327 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1328 else
1329 ExitFunction1(hr = S_OK);
1330 ExitOnFailure(hr, "Failed to get components collection");
1331
1332 // read components
1333 for (CPIEXEC_COMPONENT* pItm = pCompList; pItm; pItm = pItm->pNext)
1334 {
1335 // progress message
1336 if (fProgress)
1337 {
1338 hr = CpiActionDataMessage(1, pItm->wzCLSID);
1339 ExitOnFailure(hr, "Failed to send progress messages");
1340
1341 if (S_FALSE == hr)
1342 ExitFunction(); // aborted by user
1343 }
1344
1345 // find component
1346 hr = CpiFindCollectionObjectByStringKey(piCompColl, pItm->wzCLSID, &piCompObj);
1347 if (S_FALSE == hr)
1348 if (fCreate)
1349 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1350 else
1351 continue;
1352 ExitOnFailure(hr, "Failed to find component object");
1353
1354 // properties
1355 hr = CpiPutCollectionObjectValues(piCompObj, pItm->pPropertyList);
1356 ExitOnFailure(hr, "Failed to write properties");
1357
1358 // read roles
1359 if (pItm->pRoleAssignmentList)
1360 {
1361 hr = ConfigureRoleAssignments(L"RolesForComponent", piCompColl, piCompObj, pItm->pRoleAssignmentList, fCreate);
1362 ExitOnFailure(hr, "Failed to read roles");
1363 }
1364
1365 // read interfaces
1366 if (pItm->pInterfaceList)
1367 {
1368 hr = ConfigureInterfaces(piCompColl, piCompObj, pItm->pInterfaceList, fCreate);
1369 ExitOnFailure(hr, "Failed to read interfaces");
1370 }
1371
1372 // clean up
1373 ReleaseNullObject(piCompObj);
1374 }
1375
1376 // save changes
1377 hr = piCompColl->SaveChanges(&lChanges);
1378 if (COMADMIN_E_OBJECTERRORS == hr)
1379 CpiLogCatalogErrorInfo();
1380 ExitOnFailure(hr, "Failed to save changes");
1381
1382 hr = S_OK;
1383
1384 LExit:
1385 // clean up
1386 ReleaseObject(piCompColl);
1387 ReleaseObject(piCompObj);
1388
1389 return hr;
1390 }
1391
1392 static HRESULT ConfigureInterfaces(
1393 ICatalogCollection* piCompColl,
1394 ICatalogObject* piCompObj,
1395 CPIEXEC_INTERFACE* pIntfList,
1396 BOOL fCreate
1397 )
1398 {
1399 HRESULT hr = S_OK;
1400
1401 ICatalogCollection* piIntfColl = NULL;
1402 ICatalogObject* piIntfObj = NULL;
1403
1404 long lChanges = 0;
1405
1406 // get interfaces collection
1407 hr = CpiGetInterfacesCollection(piCompColl, piCompObj, &piIntfColl);
1408 if (S_FALSE == hr)
1409 if (fCreate)
1410 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1411 else
1412 ExitFunction1(hr = S_OK);
1413 ExitOnFailure(hr, "Failed to get interfaces collection");
1414
1415 // read interfaces
1416 for (CPIEXEC_INTERFACE* pItm = pIntfList; pItm; pItm = pItm->pNext)
1417 {
1418 // find interface
1419 hr = CpiFindCollectionObjectByStringKey(piIntfColl, pItm->wzIID, &piIntfObj);
1420 if (S_FALSE == hr)
1421 if (fCreate)
1422 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1423 else
1424 continue;
1425 ExitOnFailure(hr, "Failed to find interface object");
1426
1427 // properties
1428 hr = CpiPutCollectionObjectValues(piIntfObj, pItm->pPropertyList);
1429 ExitOnFailure(hr, "Failed to write properties");
1430
1431 // read roles
1432 if (pItm->pRoleAssignmentList)
1433 {
1434 hr = ConfigureRoleAssignments(L"RolesForInterface", piIntfColl, piIntfObj, pItm->pRoleAssignmentList, fCreate);
1435 ExitOnFailure(hr, "Failed to read roles");
1436 }
1437
1438 // read methods
1439 if (pItm->pMethodList)
1440 {
1441 hr = ConfigureMethods(piIntfColl, piIntfObj, pItm->pMethodList, fCreate);
1442 ExitOnFailure(hr, "Failed to read methods");
1443 }
1444
1445 // clean up
1446 ReleaseNullObject(piIntfObj);
1447 }
1448
1449 // save changes
1450 hr = piIntfColl->SaveChanges(&lChanges);
1451 if (COMADMIN_E_OBJECTERRORS == hr)
1452 CpiLogCatalogErrorInfo();
1453 ExitOnFailure(hr, "Failed to save changes");
1454
1455 hr = S_OK;
1456
1457 LExit:
1458 // clean up
1459 ReleaseObject(piIntfColl);
1460 ReleaseObject(piIntfObj);
1461
1462 return hr;
1463 }
1464
1465 static HRESULT ConfigureMethods(
1466 ICatalogCollection* piIntfColl,
1467 ICatalogObject* piIntfObj,
1468 CPIEXEC_METHOD* pMethList,
1469 BOOL fCreate
1470 )
1471 {
1472 HRESULT hr = S_OK;
1473
1474 ICatalogCollection* piMethColl = NULL;
1475 ICatalogObject* piMethObj = NULL;
1476
1477 long lChanges = 0;
1478
1479 // get methods collection
1480 hr = CpiGetMethodsCollection(piIntfColl, piIntfObj, &piMethColl);
1481 if (S_FALSE == hr)
1482 if (fCreate)
1483 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1484 else
1485 ExitFunction1(hr = S_OK);
1486 ExitOnFailure(hr, "Failed to get methods collection");
1487
1488 // read methods
1489 for (CPIEXEC_METHOD* pItm = pMethList; pItm; pItm = pItm->pNext)
1490 {
1491 // find method
1492 if (*pItm->wzIndex)
1493 hr = CpiFindCollectionObjectByIntegerKey(piMethColl, _wtol(pItm->wzIndex), &piMethObj);
1494 else
1495 hr = CpiFindCollectionObjectByName(piMethColl, pItm->wzName, &piMethObj);
1496
1497 if (S_FALSE == hr)
1498 if (fCreate)
1499 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1500 else
1501 continue;
1502 ExitOnFailure(hr, "Failed to find method object");
1503
1504 // properties
1505 hr = CpiPutCollectionObjectValues(piMethObj, pItm->pPropertyList);
1506 ExitOnFailure(hr, "Failed to write properties");
1507
1508 // read roles
1509 if (pItm->pRoleAssignmentList)
1510 {
1511 hr = ConfigureRoleAssignments(L"RolesForMethod", piMethColl, piMethObj, pItm->pRoleAssignmentList, fCreate);
1512 ExitOnFailure(hr, "Failed to read roles");
1513 }
1514
1515 // clean up
1516 ReleaseNullObject(piMethObj);
1517 }
1518
1519 // save changes
1520 hr = piMethColl->SaveChanges(&lChanges);
1521 if (COMADMIN_E_OBJECTERRORS == hr)
1522 CpiLogCatalogErrorInfo();
1523 ExitOnFailure(hr, "Failed to save changes");
1524
1525 hr = S_OK;
1526
1527 LExit:
1528 // clean up
1529 ReleaseObject(piMethColl);
1530 ReleaseObject(piMethObj);
1531
1532 return hr;
1533 }
1534
1535 static HRESULT ConfigureRoleAssignments(
1536 LPCWSTR pwzCollName,
1537 ICatalogCollection* piCompColl,
1538 ICatalogObject* piCompObj,
1539 CPIEXEC_ROLE_ASSIGNMENT* pRoleList,
1540 BOOL fCreate
1541 )
1542 {
1543 HRESULT hr = S_OK;
1544
1545 ICatalogCollection* piRoleColl = NULL;
1546 ICatalogObject* piRoleObj = NULL;
1547
1548 long lChanges = 0;
1549
1550 // get roles collection
1551 hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, pwzCollName, &piRoleColl);
1552 if (S_FALSE == hr)
1553 if (fCreate)
1554 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1555 else
1556 ExitFunction1(hr = S_OK);
1557 ExitOnFailure(hr, "Failed to get role assignments collection");
1558
1559 // read roles
1560 for (CPIEXEC_ROLE_ASSIGNMENT* pItm = pRoleList; pItm; pItm = pItm->pNext)
1561 {
1562 if (fCreate)
1563 {
1564 // find existing role
1565 hr = CpiFindCollectionObjectByName(piRoleColl, pItm->wzRoleName, NULL);
1566 ExitOnFailure(hr, "Failed to find role, key: %S", pItm->wzKey);
1567
1568 if (S_OK == hr)
1569 continue; // role already exists
1570
1571 // add object
1572 hr = CpiAddCollectionObject(piRoleColl, &piRoleObj);
1573 ExitOnFailure(hr, "Failed to add role assignment to collection");
1574
1575 // role name
1576 hr = CpiPutCollectionObjectValue(piRoleObj, L"Name", pItm->wzRoleName);
1577 ExitOnFailure(hr, "Failed to set role name property, key: %S", pItm->wzKey);
1578
1579 // clean up
1580 ReleaseNullObject(piRoleObj);
1581 }
1582 else
1583 {
1584 // remove role
1585 hr = CpiRemoveCollectionObject(piRoleColl, NULL, pItm->wzRoleName, FALSE);
1586 ExitOnFailure(hr, "Failed to remove role, key: %S", pItm->wzKey);
1587 }
1588 }
1589
1590 // save changes
1591 hr = piRoleColl->SaveChanges(&lChanges);
1592 if (COMADMIN_E_OBJECTERRORS == hr)
1593 CpiLogCatalogErrorInfo();
1594 ExitOnFailure(hr, "Failed to save changes");
1595
1596 hr = S_OK;
1597
1598 LExit:
1599 // clean up
1600 ReleaseObject(piRoleColl);
1601 ReleaseObject(piRoleObj);
1602
1603 return hr;
1604 }
1605
1606 static HRESULT ReadComponentList(
1607 LPWSTR* ppwzData,
1608 CPIEXEC_COMPONENT** ppCompList
1609 )
1610 {
1611 HRESULT hr = S_OK;
1612
1613 LPWSTR pwzData = NULL;
1614
1615 CPIEXEC_COMPONENT* pItm = NULL;
1616
1617 int iCnt = 0;
1618
1619 // read count
1620 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1621 ExitOnFailure(hr, "Failed to read count");
1622
1623 // read components
1624 for (int i = 0; i < iCnt; i++)
1625 {
1626 pItm = (CPIEXEC_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_COMPONENT));
1627 if (!pItm)
1628 ExitFunction1(hr = E_OUTOFMEMORY);
1629
1630 // read clsid
1631 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1632 ExitOnFailure(hr, "Failed to read clsid");
1633 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1634
1635 // read properties
1636 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1637 ExitOnFailure(hr, "Failed to read properties");
1638
1639 // read role assignments
1640 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1641 ExitOnFailure(hr, "Failed to read role assignments");
1642
1643 // read interfaces
1644 hr = ReadInterfaceList(ppwzData, &pItm->pInterfaceList);
1645 ExitOnFailure(hr, "Failed to read interfaces");
1646
1647 // add to list
1648 if (*ppCompList)
1649 pItm->pNext = *ppCompList;
1650 *ppCompList = pItm;
1651 pItm = NULL;
1652 }
1653
1654 hr = S_OK;
1655
1656 LExit:
1657 // clean up
1658 ReleaseStr(pwzData);
1659
1660 if (pItm)
1661 FreeComponentList(pItm);
1662
1663 return hr;
1664 }
1665
1666 static HRESULT ReadInterfaceList(
1667 LPWSTR* ppwzData,
1668 CPIEXEC_INTERFACE** ppIntfList
1669 )
1670 {
1671 HRESULT hr = S_OK;
1672
1673 LPWSTR pwzData = NULL;
1674
1675 CPIEXEC_INTERFACE* pItm = NULL;
1676
1677 int iCnt = 0;
1678
1679 // read count
1680 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1681 ExitOnFailure(hr, "Failed to read count");
1682
1683 // read interfaces
1684 for (int i = 0; i < iCnt; i++)
1685 {
1686 pItm = (CPIEXEC_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_INTERFACE));
1687 if (!pItm)
1688 ExitFunction1(hr = E_OUTOFMEMORY);
1689
1690 // read iid
1691 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1692 ExitOnFailure(hr, "Failed to read iid");
1693 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1694
1695 // read properties
1696 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1697 ExitOnFailure(hr, "Failed to read properties");
1698
1699 // read role assignments
1700 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1701 ExitOnFailure(hr, "Failed to read role assignments");
1702
1703 // read methods
1704 hr = ReadMethodList(ppwzData, &pItm->pMethodList);
1705 ExitOnFailure(hr, "Failed to read methods");
1706
1707 // add to list
1708 if (*ppIntfList)
1709 pItm->pNext = *ppIntfList;
1710 *ppIntfList = pItm;
1711 pItm = NULL;
1712 }
1713
1714 hr = S_OK;
1715
1716 LExit:
1717 // clean up
1718 ReleaseStr(pwzData);
1719
1720 if (pItm)
1721 FreeInterfaceList(pItm);
1722
1723 return hr;
1724 }
1725
1726 static HRESULT ReadMethodList(
1727 LPWSTR* ppwzData,
1728 CPIEXEC_METHOD** ppMethList
1729 )
1730 {
1731 HRESULT hr = S_OK;
1732
1733 LPWSTR pwzData = NULL;
1734
1735 CPIEXEC_METHOD* pItm = NULL;
1736
1737 int iCnt = 0;
1738
1739 // read count
1740 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1741 ExitOnFailure(hr, "Failed to read count");
1742
1743 // read methods
1744 for (int i = 0; i < iCnt; i++)
1745 {
1746 pItm = (CPIEXEC_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_METHOD));
1747 if (!pItm)
1748 ExitFunction1(hr = E_OUTOFMEMORY);
1749
1750 // read index
1751 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1752 ExitOnFailure(hr, "Failed to read index");
1753 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1754
1755 // read name
1756 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1757 ExitOnFailure(hr, "Failed to read name");
1758 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1759
1760 // read properties
1761 hr = CpiReadPropertyList(ppwzData, &pItm->pPropertyList);
1762 ExitOnFailure(hr, "Failed to read properties");
1763
1764 // read role assignments
1765 hr = ReadRoleAssignmentList(ppwzData, &pItm->pRoleAssignmentList);
1766 ExitOnFailure(hr, "Failed to read role assignments");
1767
1768 // add to list
1769 if (*ppMethList)
1770 pItm->pNext = *ppMethList;
1771 *ppMethList = pItm;
1772 pItm = NULL;
1773 }
1774
1775 hr = S_OK;
1776
1777 LExit:
1778 // clean up
1779 ReleaseStr(pwzData);
1780
1781 if (pItm)
1782 FreeMethodList(pItm);
1783
1784 return hr;
1785 }
1786
1787 static HRESULT ReadRoleAssignmentList(
1788 LPWSTR* ppwzData,
1789 CPIEXEC_ROLE_ASSIGNMENT** ppRoleList
1790 )
1791 {
1792 HRESULT hr = S_OK;
1793
1794 LPWSTR pwzData = NULL;
1795
1796 CPIEXEC_ROLE_ASSIGNMENT* pItm = NULL;
1797
1798 int iCnt = 0;
1799
1800 // read role count
1801 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
1802 ExitOnFailure(hr, "Failed to read role assignments count");
1803
1804 // read roles
1805 for (int i = 0; i < iCnt; i++)
1806 {
1807 pItm = (CPIEXEC_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPIEXEC_ROLE_ASSIGNMENT));
1808 if (!pItm)
1809 ExitFunction1(hr = E_OUTOFMEMORY);
1810
1811 // read key
1812 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1813 ExitOnFailure(hr, "Failed to read key");
1814 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1815
1816 // read role name
1817 hr = WcaReadStringFromCaData(ppwzData, &pwzData);
1818 ExitOnFailure(hr, "Failed to read role name");
1819 StringCchCopyW(pItm->wzRoleName, countof(pItm->wzRoleName), pwzData);
1820
1821 // add to list
1822 if (*ppRoleList)
1823 pItm->pNext = *ppRoleList;
1824 *ppRoleList = pItm;
1825 pItm = NULL;
1826 }
1827
1828 hr = S_OK;
1829
1830 LExit:
1831 // clean up
1832 ReleaseStr(pwzData);
1833
1834 if (pItm)
1835 FreeRoleAssignmentList(pItm);
1836
1837 return hr;
1838 }
1839
1840 static void FreeComponentList(
1841 CPIEXEC_COMPONENT* pList
1842 )
1843 {
1844 while (pList)
1845 {
1846 if (pList->pPropertyList)
1847 CpiFreePropertyList(pList->pPropertyList);
1848 if (pList->pRoleAssignmentList)
1849 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1850 if (pList->pInterfaceList)
1851 FreeInterfaceList(pList->pInterfaceList);
1852
1853 CPIEXEC_COMPONENT* pDelete = pList;
1854 pList = pList->pNext;
1855 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1856 }
1857 }
1858
1859 static void FreeInterfaceList(
1860 CPIEXEC_INTERFACE* pList
1861 )
1862 {
1863 while (pList)
1864 {
1865 if (pList->pPropertyList)
1866 CpiFreePropertyList(pList->pPropertyList);
1867 if (pList->pRoleAssignmentList)
1868 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1869 if (pList->pMethodList)
1870 FreeMethodList(pList->pMethodList);
1871
1872 CPIEXEC_INTERFACE* pDelete = pList;
1873 pList = pList->pNext;
1874 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1875 }
1876 }
1877
1878 static void FreeMethodList(
1879 CPIEXEC_METHOD* pList
1880 )
1881 {
1882 while (pList)
1883 {
1884 if (pList->pPropertyList)
1885 CpiFreePropertyList(pList->pPropertyList);
1886 if (pList->pRoleAssignmentList)
1887 FreeRoleAssignmentList(pList->pRoleAssignmentList);
1888
1889 CPIEXEC_METHOD* pDelete = pList;
1890 pList = pList->pNext;
1891 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1892 }
1893 }
1894
1895 static void FreeRoleAssignmentList(
1896 CPIEXEC_ROLE_ASSIGNMENT* pList
1897 )
1898 {
1899 while (pList)
1900 {
1901 CPIEXEC_ROLE_ASSIGNMENT* pDelete = pList;
1902 pList = pList->pNext;
1903 ::HeapFree(::GetProcessHeap(), 0, pDelete);
1904 }
1905 }