aboutsummaryrefslogtreecommitdiff
path: root/src/ext/ComPlus/ca/cpasmsched.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-04 11:41:55 -0700
committerRob Mensching <rob@firegiant.com>2021-05-04 11:41:55 -0700
commit337124bed6a57b40fca11c5c2f5b554f570522a6 (patch)
tree06e8552b11852309a2275e4bd63ee61320061876 /src/ext/ComPlus/ca/cpasmsched.cpp
parenteab57c2ddebc3dc8cebc22f5337f50062f415c0d (diff)
downloadwix-337124bed6a57b40fca11c5c2f5b554f570522a6.tar.gz
wix-337124bed6a57b40fca11c5c2f5b554f570522a6.tar.bz2
wix-337124bed6a57b40fca11c5c2f5b554f570522a6.zip
Move ComPlus.wixext into ext
Diffstat (limited to 'src/ext/ComPlus/ca/cpasmsched.cpp')
-rw-r--r--src/ext/ComPlus/ca/cpasmsched.cpp2135
1 files changed, 2135 insertions, 0 deletions
diff --git a/src/ext/ComPlus/ca/cpasmsched.cpp b/src/ext/ComPlus/ca/cpasmsched.cpp
new file mode 100644
index 00000000..2d0573a5
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpasmsched.cpp
@@ -0,0 +1,2135 @@
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
5
6// sql queries
7
8LPCWSTR vcsMsiAssemblyNameQuery =
9 L"SELECT `Name`, `Value` FROM `MsiAssemblyName` WHERE `Component_` = ?";
10enum eMsiAssemblyNameQuery { manqName = 1, manqValue };
11
12LPCWSTR vcsModuleQuery =
13 L"SELECT `ModuleID` FROM `ModuleSignature`";
14enum eModuleQuery { mqModule = 1 };
15
16LPCWSTR vcsAssemblyQuery =
17 L"SELECT `Assembly`, `Component_`, `Application_`, `AssemblyName`, `DllPath`, `TlbPath`, `PSDllPath`, `Attributes` FROM `ComPlusAssembly`";
18enum eAssemblyQuery { aqAssembly = 1, aqComponent, aqApplication, aqAssemblyName, aqDllPath, aqTlbPath, aqPSDllPath, aqAttributes };
19
20LPCWSTR vcsComponentQuery =
21 L"SELECT `ComPlusComponent`, `CLSID` FROM `ComPlusComponent` WHERE `Assembly_` = ?";
22enum eComponentQuery { cqComponent = 1, cqCLSID };
23
24LPCWSTR vcsComponentPropertyQuery =
25 L"SELECT `Name`, `Value` FROM `ComPlusComponentProperty` WHERE `ComPlusComponent_` = ?";
26
27LPCWSTR vcsInterfaceQuery =
28 L"SELECT `Interface`, `IID` FROM `ComPlusInterface` WHERE `ComPlusComponent_` = ?";
29enum eInterfaceQuery { iqInterface = 1, iqIID };
30
31LPCWSTR vcsInterfacePropertyQuery =
32 L"SELECT `Name`, `Value` FROM `ComPlusInterfaceProperty` WHERE `Interface_` = ?";
33
34LPCWSTR vcsMethodQuery =
35 L"SELECT `Method`, `Index`, `Name` FROM `ComPlusMethod` WHERE `Interface_` = ?";
36enum eMethodQuery { mqMethod = 1, mqIndex, mqName };
37
38LPCWSTR vcsMethodPropertyQuery =
39 L"SELECT `Name`, `Value` FROM `ComPlusMethodProperty` WHERE `Method_` = ?";
40
41LPCWSTR vcsRoleForComponentQuery =
42 L"SELECT `RoleForComponent`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForComponent` WHERE `ComPlusComponent_` = ?";
43LPCWSTR vcsRoleForInterfaceQuery =
44 L"SELECT `RoleForInterface`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForInterface` WHERE `Interface_` = ?";
45LPCWSTR vcsRoleForMethodQuery =
46 L"SELECT `RoleForMethod`, `ApplicationRole_`, `Component_` FROM `ComPlusRoleForMethod` WHERE `Method_` = ?";
47
48enum eRoleAssignmentQuery { raqKey = 1, raqApplicationRole, raqComponent };
49
50LPCWSTR vcsModuleComponentsQuery =
51 L"SELECT `Component`, `ModuleID` FROM `ModuleComponents`";
52LPCWSTR vcsModuleDependencyQuery =
53 L"SELECT `ModuleID`, `RequiredID` FROM `ModuleDependency`";
54LPCWSTR vcsAssemblyDependencyQuery =
55 L"SELECT `Assembly_`, `RequiredAssembly_` FROM `ComPlusAssemblyDependency`";
56
57enum eKeyPairQuery { kpqFirstKey = 1, kpqSecondKey };
58
59
60// private structs
61
62struct CPI_KEY_PAIR
63{
64 WCHAR wzFirstKey[MAX_DARWIN_KEY + 1];
65 WCHAR wzSecondKey[MAX_DARWIN_KEY + 1];
66
67 CPI_KEY_PAIR* pNext;
68};
69
70struct CPI_DEPENDENCY_CHAIN
71{
72 LPCWSTR pwzKey;
73
74 CPI_DEPENDENCY_CHAIN* pPrev;
75};
76
77struct CPI_MODULE
78{
79 WCHAR wzKey[MAX_DARWIN_KEY + 1];
80
81 CPI_MODULE* pPrev;
82 CPI_MODULE* pNext;
83};
84
85struct CPI_MODULE_LIST
86{
87 CPI_MODULE* pFirst;
88 CPI_MODULE* pLast;
89};
90
91
92// property definitions
93
94CPI_PROPERTY_DEFINITION pdlComponentProperties[] =
95{
96 {L"AllowInprocSubscribers", cpptBoolean, 500},
97 {L"ComponentAccessChecksEnabled", cpptBoolean, 500},
98 {L"ComponentTransactionTimeout", cpptInteger, 500},
99 {L"ComponentTransactionTimeoutEnabled", cpptBoolean, 500},
100 {L"COMTIIntrinsics", cpptBoolean, 500},
101 {L"ConstructionEnabled", cpptBoolean, 500},
102 {L"ConstructorString", cpptString, 500},
103 {L"CreationTimeout", cpptInteger, 500},
104 {L"Description", cpptString, 500},
105 {L"EventTrackingEnabled", cpptBoolean, 500},
106 {L"ExceptionClass", cpptString, 500},
107 {L"FireInParallel", cpptBoolean, 500},
108 {L"IISIntrinsics", cpptBoolean, 500},
109 {L"InitializesServerApplication", cpptBoolean, 500},
110 {L"IsEnabled", cpptBoolean, 501},
111 {L"IsPrivateComponent", cpptBoolean, 501},
112 {L"JustInTimeActivation", cpptBoolean, 500},
113 {L"LoadBalancingSupported", cpptBoolean, 500},
114 {L"MaxPoolSize", cpptInteger, 500},
115 {L"MinPoolSize", cpptInteger, 500},
116 {L"MultiInterfacePublisherFilterCLSID", cpptString, 500},
117 {L"MustRunInClientContext", cpptBoolean, 500},
118 {L"MustRunInDefaultContext", cpptBoolean, 501},
119 {L"ObjectPoolingEnabled", cpptBoolean, 500},
120 {L"PublisherID", cpptString, 500},
121 {L"SoapAssemblyName", cpptString, 502},
122 {L"SoapTypeName", cpptString, 502},
123 {L"Synchronization", cpptInteger, 500},
124 {L"Transaction", cpptInteger, 500},
125 {L"TxIsolationLevel", cpptInteger, 501},
126 {NULL, cpptNone, 0}
127};
128
129CPI_PROPERTY_DEFINITION pdlInterfaceProperties[] =
130{
131 {L"Description", cpptString, 500},
132 {L"QueuingEnabled", cpptBoolean, 500},
133 {NULL, cpptNone, 0}
134};
135
136CPI_PROPERTY_DEFINITION pdlMethodProperties[] =
137{
138 {L"AutoComplete", cpptBoolean, 500},
139 {L"Description", cpptString, 500},
140 {NULL, cpptNone, 0}
141};
142
143
144// prototypes for private helper functions
145
146static HRESULT GetAssemblyName(
147 LPCWSTR pwzComponent,
148 LPWSTR* ppwzAssemblyName
149 );
150static HRESULT KeyPairsRead(
151 LPCWSTR pwzQuery,
152 CPI_KEY_PAIR** ppKeyPairList
153 );
154static HRESULT ModulesRead(
155 CPI_MODULE_LIST* pModList
156 );
157static HRESULT AssembliesRead(
158 CPI_KEY_PAIR* pModCompList,
159 CPI_APPLICATION_LIST* pAppList,
160 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
161 CPI_ASSEMBLY_LIST* pAsmList
162 );
163static HRESULT ComponentsRead(
164 LPCWSTR pwzAsmKey,
165 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
166 CPI_ASSEMBLY* pAsm
167 );
168static HRESULT InterfacesRead(
169 LPCWSTR pwzCompKey,
170 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
171 CPI_ASSEMBLY* pAsm,
172 CPISCHED_COMPONENT* pComp
173 );
174static HRESULT MethodsRead(
175 LPCWSTR pwzIntfKey,
176 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
177 CPI_ASSEMBLY* pAsm,
178 CPISCHED_INTERFACE* pIntf
179 );
180static HRESULT RoleAssignmentsRead(
181 LPCWSTR pwzQuery,
182 LPCWSTR pwzKey,
183 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
184 CPISCHED_ROLE_ASSIGNMENT** ppRoleList,
185 int* piInstallCount,
186 int* piUninstallCount
187 );
188static HRESULT TopSortModuleList(
189 CPI_KEY_PAIR* pDepList,
190 CPI_MODULE_LIST* pList
191 );
192static HRESULT SwapDependentModules(
193 CPI_DEPENDENCY_CHAIN* pdcPrev,
194 CPI_KEY_PAIR* pDepList,
195 CPI_MODULE_LIST* pList,
196 CPI_MODULE* pRoot,
197 CPI_MODULE* pItm
198 );
199static HRESULT ModuleFindByKey(
200 CPI_MODULE* pItm,
201 LPCWSTR pwzKey,
202 BOOL fReverse,
203 CPI_MODULE** ppItm
204 );
205static void SortAssemblyListByModule(
206 CPI_MODULE_LIST* pModList,
207 CPI_ASSEMBLY_LIST* pAsmList
208 );
209static HRESULT TopSortAssemblyList(
210 CPI_KEY_PAIR* pDepList,
211 CPI_ASSEMBLY_LIST* pList
212 );
213static HRESULT SwapDependentAssemblies(
214 CPI_DEPENDENCY_CHAIN* pdcPrev,
215 CPI_KEY_PAIR* pDepList,
216 CPI_ASSEMBLY_LIST* pList,
217 CPI_ASSEMBLY* pRoot,
218 CPI_ASSEMBLY* pItm
219 );
220static HRESULT AssemblyFindByKey(
221 CPI_ASSEMBLY* pItm,
222 LPCWSTR pwzKey,
223 BOOL fReverse,
224 CPI_ASSEMBLY** ppItm
225 );
226static HRESULT AddAssemblyToActionData(
227 CPI_ASSEMBLY* pItm,
228 BOOL fInstall,
229 int iActionType,
230 int iActionCost,
231 LPWSTR* ppwzActionData
232 );
233static HRESULT AddRoleAssignmentsToActionData(
234 CPI_ASSEMBLY* pItm,
235 BOOL fInstall,
236 int iActionType,
237 int iActionCost,
238 LPWSTR* ppwzActionData
239 );
240static HRESULT AddComponentToActionData(
241 CPISCHED_COMPONENT* pItm,
242 BOOL fInstall,
243 BOOL fProps,
244 BOOL fRoles,
245 LPWSTR* ppwzActionData
246 );
247static HRESULT AddInterfaceToActionData(
248 CPISCHED_INTERFACE* pItm,
249 BOOL fInstall,
250 BOOL fProps,
251 BOOL fRoles,
252 LPWSTR* ppwzActionData
253 );
254static HRESULT AddMethodToActionData(
255 CPISCHED_METHOD* pItm,
256 BOOL fInstall,
257 BOOL fProps,
258 BOOL fRoles,
259 LPWSTR* ppwzActionData
260 );
261static HRESULT AddRolesToActionData(
262 int iRoleInstallCount,
263 int iRoleUninstallCount,
264 CPISCHED_ROLE_ASSIGNMENT* pRoleList,
265 BOOL fInstall,
266 BOOL fRoles,
267 LPWSTR* ppwzActionData
268 );
269static HRESULT KeyPairFindByFirstKey(
270 CPI_KEY_PAIR* pList,
271 LPCWSTR pwzKey,
272 CPI_KEY_PAIR** ppItm
273 );
274static void AssemblyFree(
275 CPI_ASSEMBLY* pItm
276 );
277static void KeyPairsFreeList(
278 CPI_KEY_PAIR* pList
279 );
280void ModuleListFree(
281 CPI_MODULE_LIST* pList
282 );
283static void ModuleFree(
284 CPI_MODULE* pItm
285 );
286static void ComponentsFreeList(
287 CPISCHED_COMPONENT* pList
288 );
289static void InterfacesFreeList(
290 CPISCHED_INTERFACE* pList
291 );
292static void MethodsFreeList(
293 CPISCHED_METHOD* pList
294 );
295static void RoleAssignmentsFreeList(
296 CPISCHED_ROLE_ASSIGNMENT* pList
297 );
298
299
300// function definitions
301
302void CpiAssemblyListFree(
303 CPI_ASSEMBLY_LIST* pList
304 )
305{
306 CPI_ASSEMBLY* pItm = pList->pFirst;
307
308 while (pItm)
309 {
310 CPI_ASSEMBLY* pDelete = pItm;
311 pItm = pItm->pNext;
312 AssemblyFree(pDelete);
313 }
314}
315
316HRESULT CpiAssembliesRead(
317 CPI_APPLICATION_LIST* pAppList,
318 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
319 CPI_ASSEMBLY_LIST* pAsmList
320 )
321{
322 HRESULT hr = S_OK;
323 CPI_MODULE_LIST modList;
324 CPI_KEY_PAIR* pModCompList = NULL;
325 CPI_KEY_PAIR* pModDepList = NULL;
326 CPI_KEY_PAIR* pAsmDepList = NULL;
327
328 ::ZeroMemory(&modList, sizeof(CPI_MODULE_LIST));
329
330 BOOL fModuleSignatureTable = (S_OK == WcaTableExists(L"ModuleSignature"));
331 BOOL fModuleComponentsTable = (S_OK == WcaTableExists(L"ModuleComponents"));
332 BOOL fModuleDependencyTable = (S_OK == WcaTableExists(L"ModuleDependency"));
333
334 // read modules
335 if (fModuleSignatureTable)
336 {
337 hr = ModulesRead(&modList);
338 ExitOnFailure(hr, "Failed to read ModuleSignature table");
339 }
340
341 // read module components
342 if (fModuleComponentsTable)
343 {
344 hr = KeyPairsRead(vcsModuleComponentsQuery, &pModCompList);
345 ExitOnFailure(hr, "Failed to read ModuleComponents table");
346 }
347
348 // read module dependencies
349 if (fModuleDependencyTable)
350 {
351 hr = KeyPairsRead(vcsModuleDependencyQuery, &pModDepList);
352 ExitOnFailure(hr, "Failed to read ModuleDependency table");
353 }
354
355 // read assemblies
356 hr = AssembliesRead(pModCompList, pAppList, pAppRoleList, pAsmList);
357 ExitOnFailure(hr, "Failed to read ComPlusAssembly table");
358
359 // read assembly dependencies
360 if (CpiTableExists(cptComPlusAssemblyDependency))
361 {
362 hr = KeyPairsRead(vcsAssemblyDependencyQuery, &pAsmDepList);
363 ExitOnFailure(hr, "Failed to read ComPlusAssemblyDependency table");
364 }
365
366 // sort modules
367 if (modList.pFirst && pModDepList)
368 {
369 hr = TopSortModuleList(pModDepList, &modList);
370 ExitOnFailure(hr, "Failed to sort modules");
371 }
372
373 // sort assemblies by module
374 if (pAsmList->pFirst && modList.pFirst && pModDepList)
375 SortAssemblyListByModule(&modList, pAsmList);
376
377 // sort assemblies by dependency
378 if (pAsmList->pFirst && pAsmDepList)
379 {
380 hr = TopSortAssemblyList(pAsmDepList, pAsmList);
381 ExitOnFailure(hr, "Failed to sort assemblies");
382 }
383
384 hr = S_OK;
385
386LExit:
387 // clean up
388 ModuleListFree(&modList);
389 if (pModCompList)
390 KeyPairsFreeList(pModCompList);
391 if (pModDepList)
392 KeyPairsFreeList(pModDepList);
393 if (pAsmDepList)
394 KeyPairsFreeList(pAsmDepList);
395
396 return hr;
397}
398
399HRESULT CpiAssembliesVerifyInstall(
400 CPI_ASSEMBLY_LIST* pList
401 )
402{
403 HRESULT hr = S_OK;
404
405 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
406 {
407 // assemblies that are being installed
408 if (!pItm->fReferencedForInstall && !pItm->iRoleAssignmentsInstallCount && !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
409 continue;
410
411 // if the assembly is referensed, it must be installed
412 if ((pItm->fReferencedForInstall || pItm->iRoleAssignmentsInstallCount) && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
413 MessageExitOnFailure(hr = E_FAIL, msierrComPlusAssemblyDependency, "An assembly is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);
414 }
415
416 hr = S_OK;
417
418LExit:
419 return hr;
420}
421
422HRESULT CpiAssembliesVerifyUninstall(
423 CPI_ASSEMBLY_LIST* pList
424 )
425{
426 HRESULT hr = S_OK;
427
428 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
429 {
430 // assemblies that are being uninstalled
431 if (!pItm->fReferencedForUninstall && !pItm->iRoleAssignmentsUninstallCount && (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
432 continue;
433
434 // if the application is not present, there is no need to remove the components
435 if (pItm->pApplication && pItm->pApplication->fObjectNotFound)
436 {
437 pItm->fIgnore = TRUE;
438 pList->iUninstallCount--; // elements with the fIgnore flag set will not be scheduled for uninstall
439 pList->iRoleUninstallCount--;
440 }
441 }
442
443 hr = S_OK;
444
445//LExit:
446 return hr;
447}
448
449HRESULT CpiAssembliesInstall(
450 CPI_ASSEMBLY_LIST* pList,
451 int iRunMode,
452 LPWSTR* ppwzActionData,
453 int* piProgress
454 )
455{
456 HRESULT hr = S_OK;
457
458 int iActionType;
459 int iCount = 0;
460
461 // add action text
462 hr = CpiAddActionTextToActionData(L"RegisterComPlusAssemblies", ppwzActionData);
463 ExitOnFailure(hr, "Failed to add action text to custom action data");
464
465 // assembly count
466 switch (iRunMode)
467 {
468 case rmDeferred:
469 iCount = pList->iInstallCount - pList->iCommitCount;
470 break;
471 case rmCommit:
472 iCount = pList->iCommitCount;
473 break;
474 case rmRollback:
475 iCount = pList->iInstallCount;
476 break;
477 }
478
479 // add assembly count to action data
480 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
481 ExitOnFailure(hr, "Failed to add count to custom action data");
482
483 // add assemblies to custom action data in forward order
484 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
485 {
486 // assemblies that are being installed, or contains roll assignments to install
487 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
488 continue;
489
490 // assemblies that are being installed must be scheduled during the right type of action
491 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
492 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
493 continue;
494
495 // action type
496 if (rmRollback == iRunMode)
497 {
498 if (CpiIsInstalled(pItm->isInstalled))
499 iActionType = atNoOp;
500 else
501 iActionType = atRemove;
502 }
503 else
504 iActionType = atCreate;
505
506 // add to action data
507 hr = AddAssemblyToActionData(pItm, TRUE, iActionType, COST_ASSEMBLY_REGISTER, ppwzActionData);
508 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
509 }
510
511 // add progress tics
512 if (piProgress)
513 *piProgress += COST_ASSEMBLY_REGISTER * iCount;
514
515 hr = S_OK;
516
517LExit:
518 return hr;
519}
520
521HRESULT CpiAssembliesUninstall(
522 CPI_ASSEMBLY_LIST* pList,
523 int iRunMode,
524 LPWSTR* ppwzActionData,
525 int* piProgress
526 )
527{
528 HRESULT hr = S_OK;
529
530 int iActionType;
531
532 // add action text
533 hr = CpiAddActionTextToActionData(L"UnregisterComPlusAssemblies", ppwzActionData);
534 ExitOnFailure(hr, "Failed to add action text to custom action data");
535
536 // add assembly count to action data
537 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
538 ExitOnFailure(hr, "Failed to add count to custom action data");
539
540 // add assemblies to custom action data in reverse order
541 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
542 {
543 // assemblies that are being uninstalled
544 if (pItm->fIgnore || (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction) && !WcaIsReInstalling(pItm->isInstalled, pItm->isAction)))
545 continue;
546
547 // action type
548 if (rmRollback == iRunMode)
549 iActionType = atCreate;
550 else
551 iActionType = atRemove;
552
553 // add to action data
554 hr = AddAssemblyToActionData(pItm, FALSE, iActionType, COST_ASSEMBLY_UNREGISTER, ppwzActionData);
555 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
556 }
557
558 // add progress tics
559 if (piProgress)
560 *piProgress += COST_ASSEMBLY_UNREGISTER * pList->iUninstallCount;
561
562 hr = S_OK;
563
564LExit:
565 return hr;
566}
567
568HRESULT CpiRoleAssignmentsInstall(
569 CPI_ASSEMBLY_LIST* pList,
570 int iRunMode,
571 LPWSTR* ppwzActionData,
572 int* piProgress
573 )
574{
575 HRESULT hr = S_OK;
576
577 int iActionType;
578 int iCount = 0;
579
580 // add action text
581 hr = CpiAddActionTextToActionData(L"AddComPlusRoleAssignments", ppwzActionData);
582 ExitOnFailure(hr, "Failed to add action text to custom action data");
583
584 // assembly count
585 switch (iRunMode)
586 {
587 case rmDeferred:
588 iCount = pList->iRoleInstallCount - pList->iRoleCommitCount;
589 break;
590 case rmCommit:
591 iCount = pList->iRoleCommitCount;
592 break;
593 case rmRollback:
594 iCount = pList->iRoleInstallCount;
595 break;
596 }
597
598 // add assembly count to action data
599 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
600 ExitOnFailure(hr, "Failed to add count to custom action data");
601
602 // add assemblies to custom action data in forward order
603 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
604 {
605 // assemblies that are being installed, or contains roll assignments to install
606 if (!pItm->iRoleAssignmentsInstallCount)
607 continue;
608
609 // assemblies that are being installed must be scheduled during the right type of action
610 BOOL fRunInCommit = 0 != (pItm->iAttributes & aaRunInCommit);
611 if (((rmCommit == iRunMode && !fRunInCommit) || (rmDeferred == iRunMode && fRunInCommit)))
612 continue;
613
614 // action type
615 if (rmRollback == iRunMode)
616 {
617 if (CpiIsInstalled(pItm->isInstalled))
618 iActionType = atNoOp;
619 else
620 iActionType = atRemove;
621 }
622 else
623 iActionType = atCreate;
624
625 // add to action data
626 hr = AddRoleAssignmentsToActionData(pItm, TRUE, iActionType, COST_ROLLASSIGNMENT_CREATE, ppwzActionData);
627 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
628
629 // add progress tics
630 if (piProgress)
631 *piProgress += COST_ROLLASSIGNMENT_CREATE * pItm->iRoleAssignmentsInstallCount;
632 }
633
634 hr = S_OK;
635
636LExit:
637 return hr;
638}
639
640HRESULT CpiRoleAssignmentsUninstall(
641 CPI_ASSEMBLY_LIST* pList,
642 int iRunMode,
643 LPWSTR* ppwzActionData,
644 int* piProgress
645 )
646{
647 HRESULT hr = S_OK;
648
649 int iActionType;
650
651 // add action text
652 hr = CpiAddActionTextToActionData(L"RemoveComPlusRoleAssignments", ppwzActionData);
653 ExitOnFailure(hr, "Failed to add action text to custom action data");
654
655 // add assembly count to action data
656 hr = WcaWriteIntegerToCaData(pList->iRoleUninstallCount, ppwzActionData);
657 ExitOnFailure(hr, "Failed to add count to custom action data");
658
659 // add assemblies to custom action data in reverse order
660 for (CPI_ASSEMBLY* pItm = pList->pLast; pItm; pItm = pItm->pPrev)
661 {
662 // assemblies that are being uninstalled
663 if (pItm->fIgnore || !pItm->iRoleAssignmentsUninstallCount)
664 continue;
665
666 // action type
667 if (rmRollback == iRunMode)
668 iActionType = atCreate;
669 else
670 iActionType = atRemove;
671
672 // add to action data
673 hr = AddRoleAssignmentsToActionData(pItm, FALSE, iActionType, COST_ROLLASSIGNMENT_DELETE, ppwzActionData);
674 ExitOnFailure(hr, "Failed to add assembly to custom action data, key: %S", pItm->wzKey);
675
676 // add progress tics
677 if (piProgress)
678 *piProgress += COST_ROLLASSIGNMENT_DELETE * pItm->iRoleAssignmentsUninstallCount;
679 }
680
681 hr = S_OK;
682
683LExit:
684 return hr;
685}
686
687HRESULT CpiGetSubscriptionsCollForComponent(
688 CPI_ASSEMBLY* pAsm,
689 CPISCHED_COMPONENT* pComp,
690 ICatalogCollection** ppiSubsColl
691 )
692{
693 HRESULT hr = S_OK;
694
695 ICatalogCollection* piCompColl = NULL;
696 ICatalogObject* piCompObj = NULL;
697
698 // get applications collection
699 if (!pComp->piSubsColl)
700 {
701 // get components collection for application
702 hr = CpiGetComponentsCollForApplication(pAsm->pApplication, &piCompColl);
703 ExitOnFailure(hr, "Failed to get components collection for application");
704
705 if (S_FALSE == hr)
706 ExitFunction(); // exit with hr = S_FALSE
707
708 // find component object
709 hr = CpiFindCollectionObject(piCompColl, pComp->wzCLSID, NULL, &piCompObj);
710 ExitOnFailure(hr, "Failed to find component object");
711
712 if (S_FALSE == hr)
713 ExitFunction(); // exit with hr = S_FALSE
714
715 // get roles collection
716 hr = CpiSchedGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", &pComp->piSubsColl);
717 ExitOnFailure(hr, "Failed to get subscriptions collection");
718 }
719
720 // return value
721 *ppiSubsColl = pComp->piSubsColl;
722 (*ppiSubsColl)->AddRef();
723
724 hr = S_OK;
725
726LExit:
727 // clean up
728 ReleaseObject(piCompColl);
729 ReleaseObject(piCompObj);
730
731 return hr;
732}
733
734
735// helper function definitions
736
737static HRESULT GetAssemblyName(
738 LPCWSTR pwzComponent,
739 LPWSTR* ppwzAssemblyName
740 )
741{
742 HRESULT hr = S_OK;
743
744 PMSIHANDLE hView, hRecKey, hRec;
745
746 LPWSTR pwzKey = NULL;
747
748 LPWSTR pwzName = NULL;
749 LPWSTR pwzVersion = NULL;
750 LPWSTR pwzCulture = NULL;
751 LPWSTR pwzPublicKeyToken = NULL;
752
753 // create parameter record
754 hRecKey = ::MsiCreateRecord(1);
755 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
756 hr = WcaSetRecordString(hRecKey, 1, pwzComponent);
757 ExitOnFailure(hr, "Failed to set record string");
758
759 // open view
760 hr = WcaOpenView(vcsMsiAssemblyNameQuery, &hView);
761 ExitOnFailure(hr, "Failed to open view on MsiAssemblyName table");
762 hr = WcaExecuteView(hView, hRecKey);
763 ExitOnFailure(hr, "Failed to execute view on MsiAssemblyName table");
764
765 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
766 {
767 // read key
768 hr = WcaGetRecordString(hRec, manqName, &pwzKey);
769 ExitOnFailure(hr, "Failed to get name");
770
771 // read value
772 if (0 == lstrcmpiW(L"name", pwzKey))
773 hr = WcaGetRecordString(hRec, manqValue, &pwzName);
774 else if (0 == lstrcmpiW(L"version", pwzKey))
775 hr = WcaGetRecordString(hRec, manqValue, &pwzVersion);
776 else if (0 == lstrcmpiW(L"culture", pwzKey))
777 hr = WcaGetRecordString(hRec, manqValue, &pwzCulture);
778 else if (0 == lstrcmpiW(L"publicKeyToken", pwzKey))
779 hr = WcaGetRecordString(hRec, manqValue, &pwzPublicKeyToken);
780 else
781 {
782 WcaLog(LOGMSG_VERBOSE, "Unknown name in MsiAssemblyName table: %S, %S", pwzComponent, pwzKey);
783 hr = S_OK;
784 }
785
786 ExitOnFailure(hr, "Failed to get value");
787 }
788
789 if (E_NOMOREITEMS != hr)
790 ExitOnFailure(hr, "Failed to fetch record");
791
792 // verify
793 if (!(pwzName && *pwzName) || !(pwzVersion && *pwzVersion))
794 ExitOnFailure(hr = E_FAIL, "Incomplete assembly name");
795
796 // build name string
797 hr = StrAllocFormatted(ppwzAssemblyName, L"%s, Version=%s, Culture=%s, PublicKeyToken=%s",
798 pwzName, pwzVersion,
799 pwzCulture && *pwzCulture ? pwzCulture : L"Neutral",
800 pwzPublicKeyToken && *pwzPublicKeyToken ? pwzPublicKeyToken : L"null");
801 ExitOnFailure(hr, "Failed to build assembly name string");
802
803 hr = S_OK;
804
805LExit:
806 // clean up
807 ReleaseStr(pwzKey);
808 ReleaseStr(pwzName);
809 ReleaseStr(pwzVersion);
810 ReleaseStr(pwzCulture);
811 ReleaseStr(pwzPublicKeyToken);
812
813 return hr;
814}
815
816static HRESULT KeyPairsRead(
817 LPCWSTR pwzQuery,
818 CPI_KEY_PAIR** ppKeyPairList
819 )
820{
821 HRESULT hr = S_OK;
822
823 PMSIHANDLE hView, hRec;
824
825 CPI_KEY_PAIR* pItm = NULL;
826 LPWSTR pwzData = NULL;
827
828 // loop through all dependencies
829 hr = WcaOpenExecuteView(pwzQuery, &hView);
830 ExitOnFailure(hr, "Failed to execute view on table");
831
832 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
833 {
834 // create entry
835 pItm = (CPI_KEY_PAIR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_KEY_PAIR));
836 if (!pItm)
837 ExitFunction1(hr = E_OUTOFMEMORY);
838
839 // get key
840 hr = WcaGetRecordString(hRec, kpqFirstKey, &pwzData);
841 ExitOnFailure(hr, "Failed to get first key");
842 StringCchCopyW(pItm->wzFirstKey, countof(pItm->wzFirstKey), pwzData);
843
844 // get key
845 hr = WcaGetRecordString(hRec, kpqSecondKey, &pwzData);
846 ExitOnFailure(hr, "Failed to get second key");
847 StringCchCopyW(pItm->wzSecondKey, countof(pItm->wzSecondKey), pwzData);
848
849 // add entry
850 if (*ppKeyPairList)
851 pItm->pNext = *ppKeyPairList;
852 *ppKeyPairList = pItm;
853 pItm = NULL;
854 }
855
856 if (E_NOMOREITEMS == hr)
857 hr = S_OK;
858
859LExit:
860 // clean up
861 if (pItm)
862 KeyPairsFreeList(pItm);
863
864 ReleaseStr(pwzData);
865
866 return hr;
867}
868
869static HRESULT ModulesRead(
870 CPI_MODULE_LIST* pModList
871 )
872{
873 HRESULT hr = S_OK;
874
875 PMSIHANDLE hView, hRec;
876
877 CPI_MODULE* pItm = NULL;
878 LPWSTR pwzData = NULL;
879
880 // loop through all modules
881 hr = WcaOpenExecuteView(vcsModuleQuery, &hView);
882 ExitOnFailure(hr, "Failed to execute view on ModuleSignature table");
883
884 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
885 {
886 // create entry
887 pItm = (CPI_MODULE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_MODULE));
888 if (!pItm)
889 ExitFunction1(hr = E_OUTOFMEMORY);
890
891 // get key
892 hr = WcaGetRecordString(hRec, mqModule, &pwzData);
893 ExitOnFailure(hr, "Failed to get key");
894 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
895
896 // add entry
897 if (pModList->pLast)
898 {
899 pModList->pLast->pNext = pItm;
900 pItm->pPrev = pModList->pLast;
901 }
902 else
903 pModList->pFirst = pItm;
904 pModList->pLast = pItm;
905 pItm = NULL;
906 }
907
908 if (E_NOMOREITEMS == hr)
909 hr = S_OK;
910
911LExit:
912 // clean up
913 if (pItm)
914 ModuleFree(pItm);
915
916 ReleaseStr(pwzData);
917
918 return hr;
919}
920
921static HRESULT AssembliesRead(
922 CPI_KEY_PAIR* pModCompList,
923 CPI_APPLICATION_LIST* pAppList,
924 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
925 CPI_ASSEMBLY_LIST* pAsmList
926 )
927{
928 HRESULT hr = S_OK;
929 UINT er = ERROR_SUCCESS;
930
931 PMSIHANDLE hView, hRec;
932
933 CPI_ASSEMBLY* pItm = NULL;
934 CPI_KEY_PAIR* pModComp;
935 LPWSTR pwzData = NULL;
936 LPWSTR pwzComponent = NULL;
937 BOOL fMatchingArchitecture = FALSE;
938
939 // loop through all assemblies
940 hr = WcaOpenExecuteView(vcsAssemblyQuery, &hView);
941 ExitOnFailure(hr, "Failed to execute view on ComPlusAssembly table");
942
943 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
944 {
945 // get component
946 hr = WcaGetRecordString(hRec, aqComponent, &pwzComponent);
947 ExitOnFailure(hr, "Failed to get component");
948
949 // check if the component is our processor architecture
950 hr = CpiVerifyComponentArchitecure(pwzComponent, &fMatchingArchitecture);
951 ExitOnFailure(hr, "Failed to get component architecture.");
952
953 if (!fMatchingArchitecture)
954 {
955 continue; // not the same architecture, ignore
956 }
957
958 // create entry
959 pItm = (CPI_ASSEMBLY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ASSEMBLY));
960 if (!pItm)
961 ExitFunction1(hr = E_OUTOFMEMORY);
962
963 // get component install state
964 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &pItm->isInstalled, &pItm->isAction);
965 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
966
967 // get key
968 hr = WcaGetRecordString(hRec, aqAssembly, &pwzData);
969 ExitOnFailure(hr, "Failed to get key");
970 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
971
972 // get attributes
973 hr = WcaGetRecordInteger(hRec, aqAttributes, &pItm->iAttributes);
974 ExitOnFailure(hr, "Failed to get attributes");
975
976 // get assembly name
977 hr = WcaGetRecordFormattedString(hRec, aqAssemblyName, &pItm->pwzAssemblyName);
978 ExitOnFailure(hr, "Failed to get assembly name");
979
980 if (!*pItm->pwzAssemblyName && (pItm->iAttributes & aaPathFromGAC))
981 {
982 // get assembly name for component
983 hr = GetAssemblyName(pwzComponent, &pItm->pwzAssemblyName);
984 ExitOnFailure(hr, "Failed to get assembly name for component");
985 }
986
987 // get dll path
988 hr = WcaGetRecordFormattedString(hRec, aqDllPath, &pItm->pwzDllPath);
989 ExitOnFailure(hr, "Failed to get assembly dll path");
990
991 // get module
992 // TODO: if there is a very large number of components belonging to modules, this search might be slow
993 hr = KeyPairFindByFirstKey(pModCompList, pwzData, &pModComp);
994
995 if (S_OK == hr)
996 StringCchCopyW(pItm->wzModule, countof(pItm->wzModule), pModComp->wzSecondKey);
997
998 // get application
999 hr = WcaGetRecordString(hRec, aqApplication, &pwzData);
1000 ExitOnFailure(hr, "Failed to get application");
1001
1002 if (pwzData && *pwzData)
1003 {
1004 hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication);
1005 if (S_FALSE == hr)
1006 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1007 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1008 }
1009
1010 // get tlb path
1011 hr = WcaGetRecordFormattedString(hRec, aqTlbPath, &pItm->pwzTlbPath);
1012 ExitOnFailure(hr, "Failed to get assembly tlb path");
1013
1014 // get proxy-stub dll path
1015 hr = WcaGetRecordFormattedString(hRec, aqPSDllPath, &pItm->pwzPSDllPath);
1016 ExitOnFailure(hr, "Failed to get assembly proxy-stub DLL path");
1017
1018 // read components
1019 if (CpiTableExists(cptComPlusComponent))
1020 {
1021 hr = ComponentsRead(pItm->wzKey, pAppRoleList, pItm);
1022 ExitOnFailure(hr, "Failed to read components for assembly");
1023 }
1024
1025 // set references & increment counters
1026 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1027 {
1028 pAsmList->iInstallCount++;
1029 if (pItm->iAttributes & aaRunInCommit)
1030 pAsmList->iCommitCount++;
1031 }
1032 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1033 pAsmList->iUninstallCount++;
1034
1035 if (pItm->iRoleAssignmentsInstallCount)
1036 {
1037 pAsmList->iRoleInstallCount++;
1038 if (pItm->iAttributes & aaRunInCommit)
1039 pAsmList->iRoleCommitCount++;
1040 }
1041 if (pItm->iRoleAssignmentsUninstallCount)
1042 pAsmList->iRoleUninstallCount++;
1043
1044 if (pItm->pApplication)
1045 {
1046 if (pItm->iRoleAssignmentsInstallCount || WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1047 CpiApplicationAddReferenceInstall(pItm->pApplication);
1048 if (pItm->iRoleAssignmentsUninstallCount || WcaIsUninstalling(pItm->isInstalled, pItm->isAction) || WcaIsReInstalling(pItm->isInstalled, pItm->isAction))
1049 CpiApplicationAddReferenceUninstall(pItm->pApplication);
1050 }
1051
1052 // add entry
1053 if (pAsmList->pLast)
1054 {
1055 pAsmList->pLast->pNext = pItm;
1056 pItm->pPrev = pAsmList->pLast;
1057 }
1058 else
1059 pAsmList->pFirst = pItm;
1060 pAsmList->pLast = pItm;
1061 pItm = NULL;
1062 }
1063
1064 if (E_NOMOREITEMS == hr)
1065 hr = S_OK;
1066
1067LExit:
1068 // clean up
1069 if (pItm)
1070 AssemblyFree(pItm);
1071
1072 ReleaseStr(pwzData);
1073 ReleaseStr(pwzComponent);
1074
1075 return hr;
1076}
1077
1078static HRESULT TopSortModuleList(
1079 CPI_KEY_PAIR* pDepList,
1080 CPI_MODULE_LIST* pList
1081 )
1082{
1083 HRESULT hr = S_OK;
1084
1085 // top sort list
1086 for (CPI_MODULE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1087 {
1088 // append module
1089 hr = SwapDependentModules(NULL, pDepList, pList, pItm, pItm);
1090 ExitOnFailure(hr, "Failed to swap dependent modules");
1091 }
1092
1093 hr = S_OK;
1094
1095LExit:
1096 return hr;
1097}
1098
1099static HRESULT SwapDependentModules(
1100 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1101 CPI_KEY_PAIR* pDepList, // module dependency list
1102 CPI_MODULE_LIST* pList, // module list being sorted
1103 CPI_MODULE* pRoot, // first module in the chain
1104 CPI_MODULE* pItm // current module to test for dependencies
1105 )
1106{
1107 HRESULT hr = S_OK;
1108
1109 CPI_MODULE* pDepItm;
1110
1111 // find dependencies
1112 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1113 {
1114 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1115 {
1116 CPI_DEPENDENCY_CHAIN dcItm;
1117 dcItm.pwzKey = pItm->wzKey;
1118 dcItm.pPrev = pdcPrev;
1119
1120 // check for circular dependencies
1121 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1122 {
1123 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1124 {
1125 // circular dependency found
1126 ExitOnFailure(hr = E_FAIL, "Circular module dependency found, key: %S", pDep->wzSecondKey);
1127 }
1128 }
1129
1130 // make sure the item is not already in the list
1131 hr = ModuleFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1132
1133 if (S_OK == hr)
1134 continue; // item found, move on
1135
1136 // find item in the list
1137 hr = ModuleFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1138
1139 if (S_FALSE == hr)
1140 {
1141 // not found
1142 ExitOnFailure(hr = E_FAIL, "Module dependency not found, key: %S", pDep->wzSecondKey);
1143 }
1144
1145 // if this item in turn has dependencies, they have to be swaped first
1146 hr = SwapDependentModules(&dcItm, pDepList, pList, pRoot, pDepItm);
1147 ExitOnFailure(hr, "Failed to swap dependent module");
1148
1149 // remove item from its current position
1150 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1151 if (pDepItm->pNext)
1152 pDepItm->pNext->pPrev = pDepItm->pPrev;
1153 else
1154 {
1155 pList->pLast = pDepItm->pPrev;
1156 pList->pLast->pNext = NULL;
1157 }
1158
1159 // insert before the current item
1160 if (pRoot->pPrev)
1161 pRoot->pPrev->pNext = pDepItm;
1162 else
1163 pList->pFirst = pDepItm;
1164 pDepItm->pPrev = pRoot->pPrev;
1165 pRoot->pPrev = pDepItm;
1166 pDepItm->pNext = pRoot;
1167 }
1168 }
1169
1170 hr = S_OK;
1171
1172LExit:
1173 return hr;
1174}
1175
1176static HRESULT ModuleFindByKey(
1177 CPI_MODULE* pItm,
1178 LPCWSTR pwzKey,
1179 BOOL fReverse,
1180 CPI_MODULE** ppItm
1181 )
1182{
1183 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1184 {
1185 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1186 {
1187 *ppItm = pItm;
1188 return S_OK;
1189 }
1190 }
1191
1192 return S_FALSE;
1193}
1194
1195static void SortAssemblyListByModule(
1196 CPI_MODULE_LIST* pModList,
1197 CPI_ASSEMBLY_LIST* pAsmList
1198 )
1199{
1200 CPI_ASSEMBLY* pMoved = NULL; // first moved item
1201
1202 // loop modules in reverse order
1203 for (CPI_MODULE* pMod = pModList->pLast; pMod; pMod = pMod->pPrev)
1204 {
1205 // loop assemblies in forward order, starting with the first unmoved item
1206 CPI_ASSEMBLY* pAsm = pMoved ? pMoved->pNext : pAsmList->pFirst;
1207 while (pAsm)
1208 {
1209 CPI_ASSEMBLY* pNext = pAsm->pNext;
1210
1211 // check if assembly belongs to the current module
1212 if (0 == lstrcmpW(pMod->wzKey, pAsm->wzModule))
1213 {
1214 // if the item is not already first in the list
1215 if (pAsm->pPrev)
1216 {
1217 // remove item from it's current position
1218 pAsm->pPrev->pNext = pAsm->pNext;
1219 if (pAsm->pNext)
1220 pAsm->pNext->pPrev = pAsm->pPrev;
1221 else
1222 pAsmList->pLast = pAsm->pPrev;
1223
1224 // insert item first in the list
1225 pAsmList->pFirst->pPrev = pAsm;
1226 pAsm->pNext = pAsmList->pFirst;
1227 pAsm->pPrev = NULL;
1228 pAsmList->pFirst = pAsm;
1229 }
1230
1231 // if we haven't moved any items yet, this is the first moved item
1232 if (!pMoved)
1233 pMoved = pAsm;
1234 }
1235
1236 pAsm = pNext;
1237 }
1238 }
1239}
1240
1241static HRESULT TopSortAssemblyList(
1242 CPI_KEY_PAIR* pDepList,
1243 CPI_ASSEMBLY_LIST* pList
1244 )
1245{
1246 HRESULT hr = S_OK;
1247
1248 // top sort list
1249 for (CPI_ASSEMBLY* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
1250 {
1251 // append module
1252 hr = SwapDependentAssemblies(NULL, pDepList, pList, pItm, pItm);
1253 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1254 }
1255
1256 hr = S_OK;
1257
1258LExit:
1259 return hr;
1260}
1261
1262static HRESULT SwapDependentAssemblies(
1263 CPI_DEPENDENCY_CHAIN* pdcPrev, // list containing the entire dependency chain
1264 CPI_KEY_PAIR* pDepList, // assembly dependency list
1265 CPI_ASSEMBLY_LIST* pList, // assembly list being sorted
1266 CPI_ASSEMBLY* pRoot, // first assembly in the chain
1267 CPI_ASSEMBLY* pItm // current assembly to test for dependencies
1268 )
1269{
1270 HRESULT hr = S_OK;
1271
1272 CPI_ASSEMBLY* pDepItm;
1273
1274 // find dependencies
1275 for (CPI_KEY_PAIR* pDep = pDepList; pDep; pDep = pDep->pNext)
1276 {
1277 if (0 == lstrcmpW(pItm->wzKey, pDep->wzFirstKey))
1278 {
1279 CPI_DEPENDENCY_CHAIN dcItm;
1280 dcItm.pwzKey = pItm->wzKey;
1281 dcItm.pPrev = pdcPrev;
1282
1283 // check for circular dependencies
1284 for (CPI_DEPENDENCY_CHAIN* pdcItm = &dcItm; pdcItm; pdcItm = pdcItm->pPrev)
1285 {
1286 if (0 == lstrcmpW(pdcItm->pwzKey, pDep->wzSecondKey))
1287 {
1288 // circular dependency found
1289 ExitOnFailure(hr = E_FAIL, "Circular assembly dependency found, key: %S", pDep->wzSecondKey);
1290 }
1291 }
1292
1293 // make sure the item is not already in the list
1294 hr = AssemblyFindByKey(pRoot->pPrev, pDep->wzSecondKey, TRUE, &pDepItm); // find in reverse order
1295
1296 if (S_OK == hr)
1297 continue; // item found, move on
1298
1299 // find item in the list
1300 hr = AssemblyFindByKey(pRoot->pNext, pDep->wzSecondKey, FALSE, &pDepItm); // find in forward order
1301
1302 if (S_FALSE == hr)
1303 {
1304 // not found
1305 ExitOnFailure(hr = E_FAIL, "Assembly dependency not found, key: %S", pDep->wzSecondKey);
1306 }
1307
1308 // if the root item belongs to a module, this item must also belong to the same module
1309 if (*pItm->wzModule)
1310 {
1311 if (0 != lstrcmpW(pDepItm->wzModule, pItm->wzModule))
1312 ExitOnFailure(hr = E_FAIL, "An assembly dependency can only exist between two assemblies not belonging to modules, or belonging to the same module. assembly: %S, required assembly: %S", pItm->wzKey, pDepItm->wzKey);
1313 }
1314
1315 // if this item in turn has dependencies, they have to be swaped first
1316 hr = SwapDependentAssemblies(&dcItm, pDepList, pList, pRoot, pDepItm);
1317 ExitOnFailure(hr, "Failed to swap dependent assemblies");
1318
1319 // remove item from its current position
1320 pDepItm->pPrev->pNext = pDepItm->pNext; // pDepItm can never be the first item, no need to check pPrev
1321 if (pDepItm->pNext)
1322 pDepItm->pNext->pPrev = pDepItm->pPrev;
1323 else
1324 {
1325 pList->pLast = pDepItm->pPrev;
1326 pList->pLast->pNext = NULL;
1327 }
1328
1329 // insert before the current item
1330 if (pRoot->pPrev)
1331 pRoot->pPrev->pNext = pDepItm;
1332 else
1333 pList->pFirst = pDepItm;
1334 pDepItm->pPrev = pRoot->pPrev;
1335 pRoot->pPrev = pDepItm;
1336 pDepItm->pNext = pRoot;
1337 }
1338 }
1339
1340 hr = S_OK;
1341
1342LExit:
1343 return hr;
1344}
1345
1346static HRESULT AssemblyFindByKey(
1347 CPI_ASSEMBLY* pItm,
1348 LPCWSTR pwzKey,
1349 BOOL fReverse,
1350 CPI_ASSEMBLY** ppItm
1351 )
1352{
1353 for (; pItm; pItm = fReverse ? pItm->pPrev : pItm->pNext)
1354 {
1355 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
1356 {
1357 *ppItm = pItm;
1358 return S_OK;
1359 }
1360 }
1361
1362 return S_FALSE;
1363}
1364
1365static HRESULT ComponentsRead(
1366 LPCWSTR pwzAsmKey,
1367 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1368 CPI_ASSEMBLY* pAsm
1369 )
1370{
1371 HRESULT hr = S_OK;
1372 PMSIHANDLE hView;
1373 PMSIHANDLE hRec;
1374 PMSIHANDLE hRecKey;
1375 CPISCHED_COMPONENT* pItm = NULL;
1376 LPWSTR pwzData = NULL;
1377
1378 // create parameter record
1379 hRecKey = ::MsiCreateRecord(1);
1380 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1381 hr = WcaSetRecordString(hRecKey, 1, pwzAsmKey);
1382 ExitOnFailure(hr, "Failed to set record string");
1383
1384 // open view
1385 hr = WcaOpenView(vcsComponentQuery, &hView);
1386 ExitOnFailure(hr, "Failed to open view on ComPlusComponent table");
1387 hr = WcaExecuteView(hView, hRecKey);
1388 ExitOnFailure(hr, "Failed to execute view on ComPlusComponent table");
1389
1390 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1391 {
1392 // create entry
1393 pItm = (CPISCHED_COMPONENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_COMPONENT));
1394 if (!pItm)
1395 ExitFunction1(hr = E_OUTOFMEMORY);
1396
1397 // get key
1398 hr = WcaGetRecordString(hRec, cqComponent, &pwzData);
1399 ExitOnFailure(hr, "Failed to get key");
1400 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1401
1402 // get clsid
1403 hr = WcaGetRecordFormattedString(hRec, cqCLSID, &pwzData);
1404 ExitOnFailure(hr, "Failed to get clsid");
1405 StringCchCopyW(pItm->wzCLSID, countof(pItm->wzCLSID), pwzData);
1406
1407 // read properties
1408 if (CpiTableExists(cptComPlusComponentProperty))
1409 {
1410 hr = CpiPropertiesRead(vcsComponentPropertyQuery, pItm->wzKey, pdlComponentProperties, &pItm->pProperties, &pItm->iPropertyCount);
1411 ExitOnFailure(hr, "Failed to get component properties");
1412 }
1413
1414 // read roles
1415 if (CpiTableExists(cptComPlusRoleForComponent))
1416 {
1417 hr = RoleAssignmentsRead(vcsRoleForComponentQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1418 ExitOnFailure(hr, "Failed to get roles for component");
1419 }
1420
1421 if (pItm->iRoleInstallCount)
1422 pAsm->iRoleAssignmentsInstallCount++;
1423 if (pItm->iRoleUninstallCount)
1424 pAsm->iRoleAssignmentsUninstallCount++;
1425
1426 // read interfaces
1427 if (CpiTableExists(cptComPlusInterface))
1428 {
1429 hr = InterfacesRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1430 ExitOnFailure(hr, "Failed to get interfaces for component");
1431 }
1432
1433 // add entry
1434 pAsm->iComponentCount++;
1435 if (pAsm->pComponents)
1436 pItm->pNext = pAsm->pComponents;
1437 pAsm->pComponents = pItm;
1438 pItm = NULL;
1439 }
1440
1441 if (E_NOMOREITEMS == hr)
1442 hr = S_OK;
1443
1444LExit:
1445 // clean up
1446 if (pItm)
1447 ComponentsFreeList(pItm);
1448
1449 ReleaseStr(pwzData);
1450
1451 return hr;
1452}
1453
1454static HRESULT InterfacesRead(
1455 LPCWSTR pwzCompKey,
1456 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1457 CPI_ASSEMBLY* pAsm,
1458 CPISCHED_COMPONENT* pComp
1459 )
1460{
1461 HRESULT hr = S_OK;
1462 PMSIHANDLE hView;
1463 PMSIHANDLE hRec;
1464 PMSIHANDLE hRecKey;
1465 CPISCHED_INTERFACE* pItm = NULL;
1466 LPWSTR pwzData = NULL;
1467
1468 // create parameter record
1469 hRecKey = ::MsiCreateRecord(1);
1470 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1471 hr = WcaSetRecordString(hRecKey, 1, pwzCompKey);
1472 ExitOnFailure(hr, "Failed to set record string");
1473
1474 // open view
1475 hr = WcaOpenView(vcsInterfaceQuery, &hView);
1476 ExitOnFailure(hr, "Failed to open view on ComPlusInterface table");
1477 hr = WcaExecuteView(hView, hRecKey);
1478 ExitOnFailure(hr, "Failed to execute view on ComPlusInterface table");
1479
1480 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1481 {
1482 // create entry
1483 pItm = (CPISCHED_INTERFACE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_INTERFACE));
1484 if (!pItm)
1485 ExitFunction1(hr = E_OUTOFMEMORY);
1486
1487 // get key
1488 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1489 ExitOnFailure(hr, "Failed to get key");
1490 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1491
1492 // get iid
1493 hr = WcaGetRecordFormattedString(hRec, iqIID, &pwzData);
1494 ExitOnFailure(hr, "Failed to get iid");
1495 StringCchCopyW(pItm->wzIID, countof(pItm->wzIID), pwzData);
1496
1497 // read properties
1498 if (CpiTableExists(cptComPlusInterfaceProperty))
1499 {
1500 hr = CpiPropertiesRead(vcsInterfacePropertyQuery, pItm->wzKey, pdlInterfaceProperties, &pItm->pProperties, &pItm->iPropertyCount);
1501 ExitOnFailure(hr, "Failed to get interface properties");
1502 }
1503
1504 // read roles
1505 if (CpiTableExists(cptComPlusRoleForInterface))
1506 {
1507 hr = RoleAssignmentsRead(vcsRoleForInterfaceQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1508 ExitOnFailure(hr, "Failed to get roles for interface");
1509 }
1510
1511 if (pItm->iRoleInstallCount)
1512 pAsm->iRoleAssignmentsInstallCount++;
1513 if (pItm->iRoleUninstallCount)
1514 pAsm->iRoleAssignmentsUninstallCount++;
1515
1516 // read methods
1517 if (CpiTableExists(cptComPlusMethod))
1518 {
1519 hr = MethodsRead(pItm->wzKey, pAppRoleList, pAsm, pItm);
1520 ExitOnFailure(hr, "Failed to get methods for interface");
1521 }
1522
1523 // add entry
1524 pComp->iInterfaceCount++;
1525 if (pComp->pInterfaces)
1526 pItm->pNext = pComp->pInterfaces;
1527 pComp->pInterfaces = pItm;
1528 pItm = NULL;
1529 }
1530
1531 if (E_NOMOREITEMS == hr)
1532 hr = S_OK;
1533
1534LExit:
1535 // clean up
1536 if (pItm)
1537 InterfacesFreeList(pItm);
1538
1539 ReleaseStr(pwzData);
1540
1541 return hr;
1542}
1543
1544static HRESULT MethodsRead(
1545 LPCWSTR pwzIntfKey,
1546 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1547 CPI_ASSEMBLY* pAsm,
1548 CPISCHED_INTERFACE* pIntf
1549 )
1550{
1551 HRESULT hr = S_OK;
1552 PMSIHANDLE hView, hRec, hRecKey;
1553 CPISCHED_METHOD* pItm = NULL;
1554 LPWSTR pwzData = NULL;
1555
1556 // create parameter record
1557 hRecKey = ::MsiCreateRecord(1);
1558 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1559 hr = WcaSetRecordString(hRecKey, 1, pwzIntfKey);
1560 ExitOnFailure(hr, "Failed to set record string");
1561
1562 // open view
1563 hr = WcaOpenView(vcsMethodQuery, &hView);
1564 ExitOnFailure(hr, "Failed to open view on ComPlusMethod table");
1565 hr = WcaExecuteView(hView, hRecKey);
1566 ExitOnFailure(hr, "Failed to execute view on ComPlusMethod table");
1567
1568 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1569 {
1570 // create entry
1571 pItm = (CPISCHED_METHOD*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_METHOD));
1572 if (!pItm)
1573 ExitFunction1(hr = E_OUTOFMEMORY);
1574
1575 // get key
1576 hr = WcaGetRecordString(hRec, iqInterface, &pwzData);
1577 ExitOnFailure(hr, "Failed to get key");
1578 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1579
1580 // get index
1581 hr = WcaGetRecordFormattedString(hRec, mqIndex, &pwzData);
1582 ExitOnFailure(hr, "Failed to get index");
1583 StringCchCopyW(pItm->wzIndex, countof(pItm->wzIndex), pwzData);
1584
1585 // get name
1586 hr = WcaGetRecordFormattedString(hRec, mqName, &pwzData);
1587 ExitOnFailure(hr, "Failed to get name");
1588 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
1589
1590 // either an index or a name must be provided
1591 if (!*pItm->wzIndex && !*pItm->wzName)
1592 ExitOnFailure(hr = E_FAIL, "A method must have either an index or a name associated, key: %S", pItm->wzKey);
1593
1594 // read properties
1595 if (CpiTableExists(cptComPlusMethodProperty))
1596 {
1597 hr = CpiPropertiesRead(vcsMethodPropertyQuery, pItm->wzKey, pdlMethodProperties, &pItm->pProperties, &pItm->iPropertyCount);
1598 ExitOnFailure(hr, "Failed to get method properties");
1599 }
1600
1601 // read roles
1602 if (CpiTableExists(cptComPlusRoleForMethod))
1603 {
1604 hr = RoleAssignmentsRead(vcsRoleForMethodQuery, pItm->wzKey, pAppRoleList, &pItm->pRoles, &pItm->iRoleInstallCount, &pItm->iRoleUninstallCount);
1605 ExitOnFailure(hr, "Failed to get roles for method");
1606 }
1607
1608 if (pItm->iRoleInstallCount)
1609 pAsm->iRoleAssignmentsInstallCount++;
1610 if (pItm->iRoleUninstallCount)
1611 pAsm->iRoleAssignmentsUninstallCount++;
1612
1613 // add entry
1614 pIntf->iMethodCount++;
1615 if (pIntf->pMethods)
1616 pItm->pNext = pIntf->pMethods;
1617 pIntf->pMethods = pItm;
1618 pItm = NULL;
1619 }
1620
1621 if (E_NOMOREITEMS == hr)
1622 hr = S_OK;
1623
1624LExit:
1625 // clean up
1626 if (pItm)
1627 MethodsFreeList(pItm);
1628
1629 ReleaseStr(pwzData);
1630
1631 return hr;
1632}
1633
1634static HRESULT RoleAssignmentsRead(
1635 LPCWSTR pwzQuery,
1636 LPCWSTR pwzKey,
1637 CPI_APPLICATION_ROLE_LIST* pAppRoleList,
1638 CPISCHED_ROLE_ASSIGNMENT** ppRoleList,
1639 int* piInstallCount,
1640 int* piUninstallCount
1641 )
1642{
1643 HRESULT hr = S_OK;
1644 UINT er = ERROR_SUCCESS;
1645
1646 PMSIHANDLE hView, hRec, hRecKey;
1647
1648 CPISCHED_ROLE_ASSIGNMENT* pItm = NULL;
1649 LPWSTR pwzData = NULL;
1650 BOOL fMatchingArchitecture = FALSE;
1651
1652 // create parameter record
1653 hRecKey = ::MsiCreateRecord(1);
1654 ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
1655 hr = WcaSetRecordString(hRecKey, 1, pwzKey);
1656 ExitOnFailure(hr, "Failed to set record string");
1657
1658 // open view
1659 hr = WcaOpenView(pwzQuery, &hView);
1660 ExitOnFailure(hr, "Failed to open view on role assignment table");
1661 hr = WcaExecuteView(hView, hRecKey);
1662 ExitOnFailure(hr, "Failed to execute view on role assignment table");
1663
1664 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
1665 {
1666 // get component
1667 hr = WcaGetRecordString(hRec, raqComponent, &pwzData);
1668 ExitOnFailure(hr, "Failed to get assembly component");
1669
1670 // check if the component is our processor architecture
1671 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
1672 ExitOnFailure(hr, "Failed to get component architecture.");
1673
1674 if (!fMatchingArchitecture)
1675 {
1676 continue; // not the same architecture, ignore
1677 }
1678
1679 // create entry
1680 pItm = (CPISCHED_ROLE_ASSIGNMENT*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPISCHED_ROLE_ASSIGNMENT));
1681 if (!pItm)
1682 ExitFunction1(hr = E_OUTOFMEMORY);
1683
1684 // get component install state
1685 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
1686 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
1687
1688 // get key
1689 hr = WcaGetRecordString(hRec, raqKey, &pwzData);
1690 ExitOnFailure(hr, "Failed to get key");
1691 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
1692
1693 // get application role
1694 hr = WcaGetRecordString(hRec, raqApplicationRole, &pwzData);
1695 ExitOnFailure(hr, "Failed to get application role");
1696
1697 hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole);
1698 if (S_FALSE == hr)
1699 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
1700 ExitOnFailure(hr, "Failed to find application, key: %S", pwzData);
1701
1702 // set references & increment counters
1703 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
1704 {
1705 CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole);
1706 ++*piInstallCount;
1707 }
1708 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
1709 {
1710 CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole);
1711 ++*piUninstallCount;
1712 }
1713
1714 // add entry
1715 if (*ppRoleList)
1716 pItm->pNext = *ppRoleList;
1717 *ppRoleList = pItm;
1718 pItm = NULL;
1719 }
1720
1721 if (E_NOMOREITEMS == hr)
1722 hr = S_OK;
1723
1724LExit:
1725 // clean up
1726 if (pItm)
1727 RoleAssignmentsFreeList(pItm);
1728
1729 ReleaseStr(pwzData);
1730
1731 return hr;
1732}
1733
1734static HRESULT AddAssemblyToActionData(
1735 CPI_ASSEMBLY* pItm,
1736 BOOL fInstall,
1737 int iActionType,
1738 int iActionCost,
1739 LPWSTR* ppwzActionData
1740 )
1741{
1742 HRESULT hr = S_OK;
1743
1744 // add action information to custom action data
1745 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1746 ExitOnFailure(hr, "Failed to add action type to custom action data");
1747 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1748 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1749
1750 // add assembly information to custom action data
1751 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1752 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1753 hr = WcaWriteStringToCaData(pItm->pwzAssemblyName, ppwzActionData);
1754 ExitOnFailure(hr, "Failed to add assembly name to custom action data");
1755 hr = WcaWriteStringToCaData(pItm->pwzDllPath, ppwzActionData);
1756 ExitOnFailure(hr, "Failed to add assembly dll path to custom action data");
1757 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzTlbPath : L"", ppwzActionData);
1758 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
1759 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pwzPSDllPath : L"", ppwzActionData);
1760 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
1761 hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
1762 ExitOnFailure(hr, "Failed to add assembly attributes to custom action data");
1763
1764 // add application information to custom action data
1765 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1766 ExitOnFailure(hr, "Failed to add application id to custom action data");
1767
1768 // add partition information to custom action data
1769 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1770 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1771 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1772
1773 // add components to custom action data
1774 //
1775 // components are needed acording to the following table:
1776 //
1777 // Native .NET
1778 // --------------------------------------------
1779 // NoOp | No | No
1780 // Create | Yes | Yes
1781 // Remove | Yes | No
1782 //
1783 int iCompCount = (atCreate == iActionType || (atRemove == iActionType && 0 == (pItm->iAttributes & aaDotNetAssembly))) ? pItm->iComponentCount : 0;
1784 hr = WcaWriteIntegerToCaData(iCompCount, ppwzActionData);
1785 ExitOnFailure(hr, "Failed to add component count to custom action data, key: %S", pItm->wzKey);
1786
1787 if (iCompCount)
1788 {
1789 for (CPISCHED_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1790 {
1791 hr = AddComponentToActionData(pComp, fInstall, atCreate == iActionType, FALSE, ppwzActionData);
1792 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1793 }
1794 }
1795
1796 hr = S_OK;
1797
1798LExit:
1799 return hr;
1800}
1801
1802static HRESULT AddRoleAssignmentsToActionData(
1803 CPI_ASSEMBLY* pItm,
1804 BOOL fInstall,
1805 int iActionType,
1806 int iActionCost,
1807 LPWSTR* ppwzActionData
1808 )
1809{
1810 HRESULT hr = S_OK;
1811
1812 // add action information to custom action data
1813 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
1814 ExitOnFailure(hr, "Failed to add action type to custom action data");
1815 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
1816 ExitOnFailure(hr, "Failed to add action cost to custom action data");
1817
1818 // add assembly information to custom action data
1819 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
1820 ExitOnFailure(hr, "Failed to add assembly key to custom action data");
1821 hr = WcaWriteIntegerToCaData(fInstall ? pItm->iRoleAssignmentsInstallCount : pItm->iRoleAssignmentsUninstallCount, ppwzActionData);
1822 ExitOnFailure(hr, "Failed to add role assignments count to custom action data");
1823
1824 // add application information to custom action data
1825 hr = WcaWriteStringToCaData(pItm->pApplication ? pItm->pApplication->wzID : L"", ppwzActionData);
1826 ExitOnFailure(hr, "Failed to add application id to custom action data");
1827
1828 // add partition information to custom action data
1829 LPCWSTR pwzPartID = pItm->pApplication && pItm->pApplication->pPartition ? pItm->pApplication->pPartition->wzID : L"";
1830 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
1831 ExitOnFailure(hr, "Failed to add partition id to custom action data");
1832
1833 // add components to custom action data
1834 hr = WcaWriteIntegerToCaData(pItm->iComponentCount, ppwzActionData);
1835 ExitOnFailure(hr, "Failed to add component count to custom action data");
1836
1837 for (CPISCHED_COMPONENT* pComp = pItm->pComponents; pComp; pComp = pComp->pNext)
1838 {
1839 hr = AddComponentToActionData(pComp, fInstall, FALSE, TRUE, ppwzActionData);
1840 ExitOnFailure(hr, "Failed to add component to custom action data, component: %S", pComp->wzKey);
1841 }
1842
1843 hr = S_OK;
1844
1845LExit:
1846 return hr;
1847}
1848
1849static HRESULT AddComponentToActionData(
1850 CPISCHED_COMPONENT* pItm,
1851 BOOL fInstall,
1852 BOOL fProps,
1853 BOOL fRoles,
1854 LPWSTR* ppwzActionData
1855 )
1856{
1857 HRESULT hr = S_OK;
1858
1859 // add component information to custom action data
1860 hr = WcaWriteStringToCaData(pItm->wzCLSID, ppwzActionData);
1861 ExitOnFailure(hr, "Failed to add component CLSID to custom action data");
1862
1863 // add properties to custom action data
1864 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1865 ExitOnFailure(hr, "Failed to add properties to custom action data");
1866
1867 // add roles to custom action data
1868 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1869 ExitOnFailure(hr, "Failed to add roles to custom action data");
1870
1871 // add interfaces to custom action data
1872 int iIntfCount = (fProps || fRoles) ? pItm->iInterfaceCount : 0;
1873 hr = WcaWriteIntegerToCaData(iIntfCount, ppwzActionData);
1874 ExitOnFailure(hr, "Failed to add interface count to custom action data");
1875
1876 if (iIntfCount)
1877 {
1878 for (CPISCHED_INTERFACE* pIntf = pItm->pInterfaces; pIntf; pIntf = pIntf->pNext)
1879 {
1880 hr = AddInterfaceToActionData(pIntf, fInstall, fProps, fRoles, ppwzActionData);
1881 ExitOnFailure(hr, "Failed to add interface custom action data, interface: %S", pIntf->wzKey);
1882 }
1883 }
1884
1885 hr = S_OK;
1886
1887LExit:
1888 return hr;
1889}
1890
1891static HRESULT AddInterfaceToActionData(
1892 CPISCHED_INTERFACE* pItm,
1893 BOOL fInstall,
1894 BOOL fProps,
1895 BOOL fRoles,
1896 LPWSTR* ppwzActionData
1897 )
1898{
1899 HRESULT hr = S_OK;
1900
1901 // add interface information to custom action data
1902 hr = WcaWriteStringToCaData(pItm->wzIID, ppwzActionData);
1903 ExitOnFailure(hr, "Failed to add interface IID to custom action data");
1904
1905 // add properties to custom action data
1906 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1907 ExitOnFailure(hr, "Failed to add properties to custom action data");
1908
1909 // add roles to custom action data
1910 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1911 ExitOnFailure(hr, "Failed to add roles to custom action data");
1912
1913 // add methods to custom action data
1914 hr = WcaWriteIntegerToCaData(pItm->iMethodCount, ppwzActionData);
1915 ExitOnFailure(hr, "Failed to add method count to custom action data");
1916
1917 for (CPISCHED_METHOD* pMeth = pItm->pMethods; pMeth; pMeth = pMeth->pNext)
1918 {
1919 hr = AddMethodToActionData(pMeth, fInstall, fProps, fRoles, ppwzActionData);
1920 ExitOnFailure(hr, "Failed to add method custom action data, method: %S", pMeth->wzKey);
1921 }
1922
1923 hr = S_OK;
1924
1925LExit:
1926 return hr;
1927}
1928
1929static HRESULT AddMethodToActionData(
1930 CPISCHED_METHOD* pItm,
1931 BOOL fInstall,
1932 BOOL fProps,
1933 BOOL fRoles,
1934 LPWSTR* ppwzActionData
1935 )
1936{
1937 HRESULT hr = S_OK;
1938
1939 // add interface information to custom action data
1940 hr = WcaWriteStringToCaData(pItm->wzIndex, ppwzActionData);
1941 ExitOnFailure(hr, "Failed to add method index to custom action data");
1942
1943 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
1944 ExitOnFailure(hr, "Failed to add method name to custom action data");
1945
1946 // add properties to custom action data
1947 hr = CpiAddPropertiesToActionData(fProps ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
1948 ExitOnFailure(hr, "Failed to add properties to custom action data");
1949
1950 // add roles to custom action data
1951 hr = AddRolesToActionData(pItm->iRoleInstallCount, pItm->iRoleUninstallCount, pItm->pRoles, fInstall, fRoles, ppwzActionData);
1952 ExitOnFailure(hr, "Failed to add roles to custom action data");
1953
1954 hr = S_OK;
1955
1956LExit:
1957 return hr;
1958}
1959
1960static HRESULT AddRolesToActionData(
1961 int iRoleInstallCount,
1962 int iRoleUninstallCount,
1963 CPISCHED_ROLE_ASSIGNMENT* pRoleList,
1964 BOOL fInstall,
1965 BOOL fRoles,
1966 LPWSTR* ppwzActionData
1967 )
1968{
1969 HRESULT hr = S_OK;
1970
1971 int iRoleCount = fRoles ? (fInstall ? iRoleInstallCount : iRoleUninstallCount) : 0;
1972 hr = WcaWriteIntegerToCaData(iRoleCount, ppwzActionData);
1973 ExitOnFailure(hr, "Failed to add role count to custom action data");
1974
1975 if (iRoleCount)
1976 {
1977 for (CPISCHED_ROLE_ASSIGNMENT* pRole = pRoleList; pRole; pRole = pRole->pNext)
1978 {
1979 // make sure the install state matches the create flag
1980 if (fInstall ? !WcaIsInstalling(pRole->isInstalled, pRole->isAction) : !WcaIsUninstalling(pRole->isInstalled, pRole->isAction))
1981 continue;
1982
1983 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzKey, ppwzActionData);
1984 ExitOnFailure(hr, "Failed to add key to custom action data, role: %S", pRole->wzKey);
1985
1986 hr = WcaWriteStringToCaData(pRole->pApplicationRole->wzName, ppwzActionData);
1987 ExitOnFailure(hr, "Failed to add role name to custom action data, role: %S", pRole->wzKey);
1988 }
1989 }
1990
1991 hr = S_OK;
1992
1993LExit:
1994 return hr;
1995}
1996
1997static HRESULT KeyPairFindByFirstKey(
1998 CPI_KEY_PAIR* pList,
1999 LPCWSTR pwzKey,
2000 CPI_KEY_PAIR** ppItm
2001 )
2002{
2003 for (; pList; pList = pList->pNext)
2004 {
2005 if (0 == lstrcmpW(pList->wzFirstKey, pwzKey))
2006 {
2007 *ppItm = pList;
2008 return S_OK;
2009 }
2010 }
2011
2012 return S_FALSE;
2013}
2014
2015static void AssemblyFree(
2016 CPI_ASSEMBLY* pItm
2017 )
2018{
2019 ReleaseStr(pItm->pwzAssemblyName);
2020 ReleaseStr(pItm->pwzDllPath);
2021 ReleaseStr(pItm->pwzTlbPath);
2022 ReleaseStr(pItm->pwzPSDllPath);
2023
2024 if (pItm->pComponents)
2025 ComponentsFreeList(pItm->pComponents);
2026
2027 ::HeapFree(::GetProcessHeap(), 0, pItm);
2028}
2029
2030static void KeyPairsFreeList(
2031 CPI_KEY_PAIR* pList
2032 )
2033{
2034 while (pList)
2035 {
2036 CPI_KEY_PAIR* pDelete = pList;
2037 pList = pList->pNext;
2038 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2039 }
2040}
2041
2042void ModuleListFree(
2043 CPI_MODULE_LIST* pList
2044 )
2045{
2046 CPI_MODULE* pItm = pList->pFirst;
2047
2048 while (pItm)
2049 {
2050 CPI_MODULE* pDelete = pItm;
2051 pItm = pItm->pNext;
2052 ModuleFree(pDelete);
2053 }
2054}
2055
2056static void ModuleFree(
2057 CPI_MODULE* pItm
2058 )
2059{
2060 ::HeapFree(::GetProcessHeap(), 0, pItm);
2061}
2062
2063static void ComponentsFreeList(
2064 CPISCHED_COMPONENT* pList
2065 )
2066{
2067 while (pList)
2068 {
2069 if (pList->pProperties)
2070 CpiPropertiesFreeList(pList->pProperties);
2071
2072 if (pList->pRoles)
2073 RoleAssignmentsFreeList(pList->pRoles);
2074
2075 if (pList->pInterfaces)
2076 InterfacesFreeList(pList->pInterfaces);
2077
2078 ReleaseObject(pList->piSubsColl);
2079
2080 CPISCHED_COMPONENT* pDelete = pList;
2081 pList = pList->pNext;
2082 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2083 }
2084}
2085
2086static void InterfacesFreeList(
2087 CPISCHED_INTERFACE* pList
2088 )
2089{
2090 while (pList)
2091 {
2092 if (pList->pProperties)
2093 CpiPropertiesFreeList(pList->pProperties);
2094
2095 if (pList->pRoles)
2096 RoleAssignmentsFreeList(pList->pRoles);
2097
2098 if (pList->pMethods)
2099 MethodsFreeList(pList->pMethods);
2100
2101 CPISCHED_INTERFACE* pDelete = pList;
2102 pList = pList->pNext;
2103 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2104 }
2105}
2106
2107static void MethodsFreeList(
2108 CPISCHED_METHOD* pList
2109 )
2110{
2111 while (pList)
2112 {
2113 if (pList->pProperties)
2114 CpiPropertiesFreeList(pList->pProperties);
2115
2116 if (pList->pRoles)
2117 RoleAssignmentsFreeList(pList->pRoles);
2118
2119 CPISCHED_METHOD* pDelete = pList;
2120 pList = pList->pNext;
2121 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2122 }
2123}
2124
2125static void RoleAssignmentsFreeList(
2126 CPISCHED_ROLE_ASSIGNMENT* pList
2127 )
2128{
2129 while (pList)
2130 {
2131 CPISCHED_ROLE_ASSIGNMENT* pDelete = pList;
2132 pList = pList->pNext;
2133 ::HeapFree(::GetProcessHeap(), 0, pDelete);
2134 }
2135}