aboutsummaryrefslogtreecommitdiff
path: root/src/ext/ComPlus/ca/cpsubssched.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/cpsubssched.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/cpsubssched.cpp')
-rw-r--r--src/ext/ComPlus/ca/cpsubssched.cpp606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/ext/ComPlus/ca/cpsubssched.cpp b/src/ext/ComPlus/ca/cpsubssched.cpp
new file mode 100644
index 00000000..df15fd03
--- /dev/null
+++ b/src/ext/ComPlus/ca/cpsubssched.cpp
@@ -0,0 +1,606 @@
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 vcsSubscriptionQuery =
9 L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`";
10enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID };
11
12LPCWSTR vcsSubscriptionPropertyQuery =
13 L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?";
14
15
16// property definitions
17
18CPI_PROPERTY_DEFINITION pdlSubscriptionProperties[] =
19{
20 {L"Description", cpptString, 500},
21 {L"Enabled", cpptBoolean, 500},
22 {L"EventClassPartitionID", cpptString, 502},
23 {L"FilterCriteria", cpptString, 500},
24 {L"InterfaceID", cpptString, 500},
25 {L"MachineName", cpptString, 500},
26 {L"MethodName", cpptString, 500},
27 {L"PerUser", cpptBoolean, 500},
28 {L"Queued", cpptBoolean, 500},
29 {L"SubscriberMoniker", cpptString, 500},
30 {L"UserName", cpptUser, 500},
31 {NULL, cpptNone, 0}
32};
33
34
35// prototypes for private helper functions
36
37static void FreeSubscription(
38 CPI_SUBSCRIPTION* pItm
39 );
40static HRESULT FindObjectForSubscription(
41 CPI_SUBSCRIPTION* pItm,
42 BOOL fFindId,
43 BOOL fFindName,
44 ICatalogObject** ppiSubsObj
45 );
46static HRESULT AddSubscriptionToActionData(
47 CPI_SUBSCRIPTION* pItm,
48 int iActionType,
49 int iActionCost,
50 LPWSTR* ppwzActionData
51 );
52static HRESULT ComponentFindByKey(
53 CPI_ASSEMBLY_LIST* pAsmList,
54 LPCWSTR pwzKey,
55 CPI_ASSEMBLY** ppAsmItm,
56 CPISCHED_COMPONENT** ppCompItm
57 );
58
59
60// function definitions
61
62void CpiSubscriptionListFree(
63 CPI_SUBSCRIPTION_LIST* pList
64 )
65{
66 CPI_SUBSCRIPTION* pItm = pList->pFirst;
67
68 while (pItm)
69 {
70 CPI_SUBSCRIPTION* pDelete = pItm;
71 pItm = pItm->pNext;
72 FreeSubscription(pDelete);
73 }
74}
75
76HRESULT CpiSubscriptionsRead(
77 CPI_ASSEMBLY_LIST* pAsmList,
78 CPI_SUBSCRIPTION_LIST* pSubList
79 )
80{
81 HRESULT hr = S_OK;
82 UINT er = ERROR_SUCCESS;
83
84 PMSIHANDLE hView, hRec;
85
86 CPI_SUBSCRIPTION* pItm = NULL;
87 LPWSTR pwzData = NULL;
88 BOOL fMatchingArchitecture = FALSE;
89
90 // loop through all applications
91 hr = WcaOpenExecuteView(vcsSubscriptionQuery, &hView);
92 ExitOnFailure(hr, "Failed to execute view on ComPlusSubscription table");
93
94 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
95 {
96 // get component
97 hr = WcaGetRecordString(hRec, sqComponent, &pwzData);
98 ExitOnFailure(hr, "Failed to get component");
99
100 // check if the component is our processor architecture
101 hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
102 ExitOnFailure(hr, "Failed to get component architecture.");
103
104 if (!fMatchingArchitecture)
105 {
106 continue; // not the same architecture, ignore
107 }
108
109 // create entry
110 pItm = (CPI_SUBSCRIPTION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_SUBSCRIPTION));
111 if (!pItm)
112 ExitFunction1(hr = E_OUTOFMEMORY);
113
114 // get component install state
115 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
116 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
117
118 // get key
119 hr = WcaGetRecordString(hRec, sqSubscription, &pwzData);
120 ExitOnFailure(hr, "Failed to get key");
121 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
122
123 // get com+ component
124 hr = WcaGetRecordString(hRec, sqComPlusComponent, &pwzData);
125 ExitOnFailure(hr, "Failed to get COM+ component");
126
127 hr = ComponentFindByKey(pAsmList, pwzData, &pItm->pAssembly, &pItm->pComponent);
128
129 if (S_FALSE == hr)
130 {
131 // component not found
132 ExitOnFailure(hr = E_FAIL, "Failed to find component, key: %S", pwzData);
133 }
134
135 // get id
136 hr = WcaGetRecordFormattedString(hRec, sqID, &pwzData);
137 ExitOnFailure(hr, "Failed to get id");
138
139 if (pwzData && *pwzData)
140 {
141 hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
142 ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
143 }
144
145 // get name
146 hr = WcaGetRecordFormattedString(hRec, sqName, &pwzData);
147 ExitOnFailure(hr, "Failed to get name");
148 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
149
150 // get event clsid
151 hr = WcaGetRecordFormattedString(hRec, sqEventCLSID, &pwzData);
152 ExitOnFailure(hr, "Failed to get event clsid");
153 StringCchCopyW(pItm->wzEventCLSID, countof(pItm->wzEventCLSID), pwzData);
154
155 // get publisher id
156 hr = WcaGetRecordFormattedString(hRec, sqPublisherID, &pwzData);
157 ExitOnFailure(hr, "Failed to get publisher id");
158 StringCchCopyW(pItm->wzPublisherID, countof(pItm->wzPublisherID), pwzData);
159
160 // get properties
161 if (CpiTableExists(cptComPlusSubscriptionProperty))
162 {
163 hr = CpiPropertiesRead(vcsSubscriptionPropertyQuery, pItm->wzKey, pdlSubscriptionProperties, &pItm->pProperties, &pItm->iPropertyCount);
164 ExitOnFailure(hr, "Failed to get subscription properties");
165 }
166
167 // set references & increment counters
168 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
169 {
170 CpiApplicationAddReferenceInstall(pItm->pAssembly->pApplication);
171 pItm->pAssembly->fReferencedForInstall = TRUE;
172 pSubList->iInstallCount++;
173 if (pItm->pAssembly->iAttributes & aaRunInCommit)
174 pSubList->iCommitCount++;
175 }
176 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
177 {
178 CpiApplicationAddReferenceUninstall(pItm->pAssembly->pApplication);
179 pItm->pAssembly->fReferencedForUninstall = TRUE;
180 pSubList->iUninstallCount++;
181 }
182
183 // add entry
184 if (pSubList->pFirst)
185 pItm->pNext = pSubList->pFirst;
186 pSubList->pFirst = pItm;
187 pItm = NULL;
188 }
189
190 if (E_NOMOREITEMS == hr)
191 hr = S_OK;
192
193LExit:
194 // clean up
195 if (pItm)
196 FreeSubscription(pItm);
197
198 ReleaseStr(pwzData);
199
200 return hr;
201}
202
203HRESULT CpiSubscriptionsVerifyInstall(
204 CPI_SUBSCRIPTION_LIST* pList
205 )
206{
207 HRESULT hr = S_OK;
208 UINT er = ERROR_SUCCESS;
209
210 ICatalogObject* piSubsObj = NULL;
211
212 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
213 {
214 // subscriptions that are being installed
215 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
216 continue;
217
218 // subscription is supposed to exist
219 if (CpiIsInstalled(pItm->isInstalled))
220 {
221 // if we don't have an id
222 if (!*pItm->wzID)
223 {
224 // find subscriptions with conflicting name
225 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
226 ExitOnFailure(hr, "Failed to find collection object for subscription");
227
228 // if the subscription was found
229 if (S_OK == hr)
230 {
231 // get id from subscription object
232 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
233 ExitOnFailure(hr, "Failed to get id");
234 }
235
236 // if the subscription was not found
237 else
238 {
239 // create a new id
240 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
241 ExitOnFailure(hr, "Failed to create id");
242 }
243 }
244 }
245
246 // subscription is supposed to be created
247 else
248 {
249 // check for conflicts
250 do {
251 if (*pItm->wzID)
252 {
253 // find subscriptions with conflicting id
254 hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj);
255 ExitOnFailure(hr, "Failed to find collection object for subscription");
256
257 if (S_FALSE == hr)
258 {
259 // find subscriptions with conflicting name
260 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
261 ExitOnFailure(hr, "Failed to find collection object for subscription");
262
263 if (S_OK == hr)
264 // "A subscription with a conflictiong name exists. retry cancel"
265 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
266 else
267 break; // no conflicting entry found, break loop
268 }
269 else
270 // "A subscription with a conflicting id exists. abort retry ignore"
271 er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
272 }
273 else
274 {
275 // find subscriptions with conflicting name
276 hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
277 ExitOnFailure(hr, "Failed to find collection object for subscription");
278
279 if (S_OK == hr)
280 // "A subscription with a conflictiong name exists. abort retry ignore"
281 er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
282 else
283 break; // no conflicting entry found, break loop
284 }
285
286 switch (er)
287 {
288 case IDCANCEL:
289 case IDABORT:
290 ExitOnFailure(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey);
291 break;
292 case IDRETRY:
293 break;
294 case IDIGNORE:
295 default:
296 // if we don't have an id, copy id from object
297 if (!*pItm->wzID)
298 {
299 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
300 ExitOnFailure(hr, "Failed to get id");
301 }
302 hr = S_FALSE; // indicate that this is not a conflict
303 }
304 } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
305
306 // create a new id if one is missing
307 if (!*pItm->wzID)
308 {
309 hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
310 ExitOnFailure(hr, "Failed to create id");
311 }
312 }
313
314 // clean up
315 ReleaseNullObject(piSubsObj);
316 }
317
318 hr = S_OK;
319
320LExit:
321 // clean up
322 ReleaseObject(piSubsObj);
323
324 return hr;
325}
326
327HRESULT CpiSubscriptionsVerifyUninstall(
328 CPI_SUBSCRIPTION_LIST* pList
329 )
330{
331 HRESULT hr = S_OK;
332 ICatalogObject* piSubsObj = NULL;
333
334 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
335 {
336 // subscriptions that are being installed
337 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
338 continue;
339
340 // find subscriptions with conflicting name
341 hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj);
342 ExitOnFailure(hr, "Failed to find collection object for subscription");
343
344 // if the subscription was found
345 if (S_OK == hr)
346 {
347 // if we don't have an id, copy id from object
348 if (!*pItm->wzID)
349 {
350 hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
351 ExitOnFailure(hr, "Failed to get id");
352 }
353 }
354
355 // if the subscription was not found
356 else
357 {
358 pItm->fObjectNotFound = TRUE;
359 pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
360 }
361
362 // clean up
363 ReleaseNullObject(piSubsObj);
364 }
365
366 hr = S_OK;
367
368LExit:
369 // clean up
370 ReleaseObject(piSubsObj);
371
372 return hr;
373}
374
375HRESULT CpiSubscriptionsInstall(
376 CPI_SUBSCRIPTION_LIST* pList,
377 int iRunMode,
378 LPWSTR* ppwzActionData,
379 int* piProgress
380 )
381{
382 HRESULT hr = S_OK;
383
384 int iActionType;
385 int iCount = 0;
386
387 // add action text
388 hr = CpiAddActionTextToActionData(L"CreateSubscrComPlusComponents", ppwzActionData);
389 ExitOnFailure(hr, "Failed to add action text to custom action data");
390
391 // subscription count
392 switch (iRunMode)
393 {
394 case rmDeferred:
395 iCount = pList->iInstallCount - pList->iCommitCount;
396 break;
397 case rmCommit:
398 iCount = pList->iCommitCount;
399 break;
400 case rmRollback:
401 iCount = pList->iInstallCount;
402 break;
403 }
404
405 // add subscription count to action data
406 hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
407 ExitOnFailure(hr, "Failed to add count to custom action data");
408
409 // add assemblies to custom action data in forward order
410 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
411 {
412 // roles that are being installed only
413 if ((rmCommit == iRunMode && !(pItm->pAssembly->iAttributes & aaRunInCommit)) ||
414 (rmDeferred == iRunMode && (pItm->pAssembly->iAttributes & aaRunInCommit)) ||
415 !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
416 continue;
417
418 // action type
419 if (rmRollback == iRunMode)
420 {
421 if (CpiIsInstalled(pItm->isInstalled))
422 iActionType = atNoOp;
423 else
424 iActionType = atRemove;
425 }
426 else
427 iActionType = atCreate;
428
429 // add to action data
430 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_CREATE, ppwzActionData);
431 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
432 }
433
434 // add progress tics
435 if (piProgress)
436 *piProgress += COST_SUBSCRIPTION_CREATE * pList->iInstallCount;
437
438 hr = S_OK;
439
440LExit:
441 return hr;
442}
443
444HRESULT CpiSubscriptionsUninstall(
445 CPI_SUBSCRIPTION_LIST* pList,
446 int iRunMode,
447 LPWSTR* ppwzActionData,
448 int* piProgress
449 )
450{
451 HRESULT hr = S_OK;
452
453 int iActionType;
454
455 // add action text
456 hr = CpiAddActionTextToActionData(L"RemoveSubscrComPlusComponents", ppwzActionData);
457 ExitOnFailure(hr, "Failed to add action text to custom action data");
458
459 // add subscription count to action data
460 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add count to custom action data");
462
463 // add assemblies to custom action data in reverse order
464 for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
465 {
466 // roles that are being uninstalled only
467 if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
468 continue;
469
470 // action type
471 if (rmRollback == iRunMode)
472 iActionType = atCreate;
473 else
474 iActionType = atRemove;
475
476 // add to action data
477 hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_DELETE, ppwzActionData);
478 ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
479 }
480
481 // add progress tics
482 if (piProgress)
483 *piProgress += COST_SUBSCRIPTION_DELETE * pList->iUninstallCount;
484
485 hr = S_OK;
486
487LExit:
488 return hr;
489}
490
491
492// helper function definitions
493
494static void FreeSubscription(
495 CPI_SUBSCRIPTION* pItm
496 )
497{
498 if (pItm->pProperties)
499 CpiPropertiesFreeList(pItm->pProperties);
500
501 ::HeapFree(::GetProcessHeap(), 0, pItm);
502}
503
504static HRESULT FindObjectForSubscription(
505 CPI_SUBSCRIPTION* pItm,
506 BOOL fFindId,
507 BOOL fFindName,
508 ICatalogObject** ppiSubsObj
509 )
510{
511 HRESULT hr = S_OK;
512
513 ICatalogCollection* piSubsColl = NULL;
514
515 // get applications collection
516 hr = CpiGetSubscriptionsCollForComponent(pItm->pAssembly, pItm->pComponent, &piSubsColl);
517 ExitOnFailure(hr, "Failed to get collection");
518
519 if (S_FALSE == hr)
520 ExitFunction(); // exit with hr = S_FALSE
521
522 // find application object
523 hr = CpiFindCollectionObject(piSubsColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiSubsObj);
524 ExitOnFailure(hr, "Failed to find object");
525
526 // exit with hr from CpiFindCollectionObject()
527
528LExit:
529 // clean up
530 ReleaseObject(piSubsColl);
531
532 return hr;
533}
534
535static HRESULT AddSubscriptionToActionData(
536 CPI_SUBSCRIPTION* pItm,
537 int iActionType,
538 int iActionCost,
539 LPWSTR* ppwzActionData
540 )
541{
542 HRESULT hr = S_OK;
543
544 // add action information to custom action data
545 hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
546 ExitOnFailure(hr, "Failed to add action type to custom action data");
547 hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
548 ExitOnFailure(hr, "Failed to add action cost to custom action data");
549
550 // add application role information to custom action data
551 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
552 ExitOnFailure(hr, "Failed to add subscription key to custom action data");
553 hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
554 ExitOnFailure(hr, "Failed to add subscription id to custom action data");
555 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
556 ExitOnFailure(hr, "Failed to add subscription name to custom action data");
557 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzEventCLSID : L"", ppwzActionData);
558 ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
559 hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzPublisherID : L"", ppwzActionData);
560 ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
561
562 // add component information to custom action data
563 hr = WcaWriteStringToCaData(pItm->pComponent->wzCLSID, ppwzActionData);
564 ExitOnFailure(hr, "Failed to add application id to custom action data");
565
566 // add application information to custom action data
567 hr = WcaWriteStringToCaData(pItm->pAssembly->pApplication->wzID, ppwzActionData);
568 ExitOnFailure(hr, "Failed to add application id to custom action data");
569
570 // add partition information to custom action data
571 LPCWSTR pwzPartID = pItm->pAssembly->pApplication->pPartition ? pItm->pAssembly->pApplication->pPartition->wzID : L"";
572 hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
573 ExitOnFailure(hr, "Failed to add partition id to custom action data");
574
575 // add properties to custom action data
576 hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
577 ExitOnFailure(hr, "Failed to add properties to custom action data");
578
579 hr = S_OK;
580
581LExit:
582 return hr;
583}
584
585static HRESULT ComponentFindByKey(
586 CPI_ASSEMBLY_LIST* pAsmList,
587 LPCWSTR pwzKey,
588 CPI_ASSEMBLY** ppAsmItm,
589 CPISCHED_COMPONENT** ppCompItm
590 )
591{
592 for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext)
593 {
594 for (CPISCHED_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext)
595 {
596 if (0 == lstrcmpW(pCompItm->wzKey, pwzKey))
597 {
598 *ppAsmItm = pAsmItm;
599 *ppCompItm = pCompItm;
600 return S_OK;
601 }
602 }
603 }
604
605 return S_FALSE;
606}