From 337124bed6a57b40fca11c5c2f5b554f570522a6 Mon Sep 17 00:00:00 2001
From: Rob Mensching <rob@firegiant.com>
Date: Tue, 4 May 2021 11:41:55 -0700
Subject: Move ComPlus.wixext into ext

---
 src/ext/ComPlus/ca/cpsubssched.cpp | 606 +++++++++++++++++++++++++++++++++++++
 1 file changed, 606 insertions(+)
 create mode 100644 src/ext/ComPlus/ca/cpsubssched.cpp

(limited to 'src/ext/ComPlus/ca/cpsubssched.cpp')

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 @@
+// 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.
+
+#include "precomp.h"
+
+
+// sql queries
+
+LPCWSTR vcsSubscriptionQuery =
+    L"SELECT `Subscription`, `ComPlusComponent_`, `Component_`, `Id`, `Name`, `EventCLSID`, `PublisherID` FROM `ComPlusSubscription`";
+enum eSubscriptionQuery { sqSubscription = 1, sqComPlusComponent, sqComponent, sqID, sqName, sqEventCLSID, sqPublisherID };
+
+LPCWSTR vcsSubscriptionPropertyQuery =
+    L"SELECT `Name`, `Value` FROM `ComPlusSubscriptionProperty` WHERE `Subscription_` = ?";
+
+
+// property definitions
+
+CPI_PROPERTY_DEFINITION pdlSubscriptionProperties[] =
+{
+    {L"Description",           cpptString,  500},
+    {L"Enabled",               cpptBoolean, 500},
+    {L"EventClassPartitionID", cpptString,  502},
+    {L"FilterCriteria",        cpptString,  500},
+    {L"InterfaceID",           cpptString,  500},
+    {L"MachineName",           cpptString,  500},
+    {L"MethodName",            cpptString,  500},
+    {L"PerUser",               cpptBoolean, 500},
+    {L"Queued",                cpptBoolean, 500},
+    {L"SubscriberMoniker",     cpptString,  500},
+    {L"UserName",              cpptUser,    500},
+    {NULL,                     cpptNone,    0}
+};
+
+
+// prototypes for private helper functions
+
+static void FreeSubscription(
+    CPI_SUBSCRIPTION* pItm
+    );
+static HRESULT FindObjectForSubscription(
+    CPI_SUBSCRIPTION* pItm,
+    BOOL fFindId,
+    BOOL fFindName,
+    ICatalogObject** ppiSubsObj
+    );
+static HRESULT AddSubscriptionToActionData(
+    CPI_SUBSCRIPTION* pItm,
+    int iActionType,
+    int iActionCost,
+    LPWSTR* ppwzActionData
+    );
+static HRESULT ComponentFindByKey(
+    CPI_ASSEMBLY_LIST* pAsmList,
+    LPCWSTR pwzKey,
+    CPI_ASSEMBLY** ppAsmItm,
+    CPISCHED_COMPONENT** ppCompItm
+    );
+
+
+// function definitions
+
+void CpiSubscriptionListFree(
+    CPI_SUBSCRIPTION_LIST* pList
+    )
+{
+    CPI_SUBSCRIPTION* pItm = pList->pFirst;
+
+    while (pItm)
+    {
+        CPI_SUBSCRIPTION* pDelete = pItm;
+        pItm = pItm->pNext;
+        FreeSubscription(pDelete);
+    }
+}
+
+HRESULT CpiSubscriptionsRead(
+    CPI_ASSEMBLY_LIST* pAsmList,
+    CPI_SUBSCRIPTION_LIST* pSubList
+    )
+{
+    HRESULT hr = S_OK;
+    UINT er = ERROR_SUCCESS;
+
+    PMSIHANDLE hView, hRec;
+
+    CPI_SUBSCRIPTION* pItm = NULL;
+    LPWSTR pwzData = NULL;
+    BOOL fMatchingArchitecture = FALSE;
+
+    // loop through all applications
+    hr = WcaOpenExecuteView(vcsSubscriptionQuery, &hView);
+    ExitOnFailure(hr, "Failed to execute view on ComPlusSubscription table");
+
+    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
+    {
+        // get component
+        hr = WcaGetRecordString(hRec, sqComponent, &pwzData);
+        ExitOnFailure(hr, "Failed to get component");
+
+        // check if the component is our processor architecture
+        hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture);
+        ExitOnFailure(hr, "Failed to get component architecture.");
+
+        if (!fMatchingArchitecture)
+        {
+            continue; // not the same architecture, ignore
+        }
+
+        // create entry
+        pItm = (CPI_SUBSCRIPTION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_SUBSCRIPTION));
+        if (!pItm)
+            ExitFunction1(hr = E_OUTOFMEMORY);
+
+        // get component install state
+        er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
+        ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
+
+        // get key
+        hr = WcaGetRecordString(hRec, sqSubscription, &pwzData);
+        ExitOnFailure(hr, "Failed to get key");
+        StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
+
+        // get com+ component
+        hr = WcaGetRecordString(hRec, sqComPlusComponent, &pwzData);
+        ExitOnFailure(hr, "Failed to get COM+ component");
+
+        hr = ComponentFindByKey(pAsmList, pwzData, &pItm->pAssembly, &pItm->pComponent);
+
+        if (S_FALSE == hr)
+        {
+            // component not found
+            ExitOnFailure(hr = E_FAIL, "Failed to find component, key: %S", pwzData);
+        }
+
+        // get id
+        hr = WcaGetRecordFormattedString(hRec, sqID, &pwzData);
+        ExitOnFailure(hr, "Failed to get id");
+
+        if (pwzData && *pwzData)
+        {
+            hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID));
+            ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData);
+        }
+
+        // get name
+        hr = WcaGetRecordFormattedString(hRec, sqName, &pwzData);
+        ExitOnFailure(hr, "Failed to get name");
+        StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
+
+        // get event clsid
+        hr = WcaGetRecordFormattedString(hRec, sqEventCLSID, &pwzData);
+        ExitOnFailure(hr, "Failed to get event clsid");
+        StringCchCopyW(pItm->wzEventCLSID, countof(pItm->wzEventCLSID), pwzData);
+
+        // get publisher id
+        hr = WcaGetRecordFormattedString(hRec, sqPublisherID, &pwzData);
+        ExitOnFailure(hr, "Failed to get publisher id");
+        StringCchCopyW(pItm->wzPublisherID, countof(pItm->wzPublisherID), pwzData);
+
+        // get properties
+        if (CpiTableExists(cptComPlusSubscriptionProperty))
+        {
+            hr = CpiPropertiesRead(vcsSubscriptionPropertyQuery, pItm->wzKey, pdlSubscriptionProperties, &pItm->pProperties, &pItm->iPropertyCount);
+            ExitOnFailure(hr, "Failed to get subscription properties");
+        }
+
+        // set references & increment counters
+        if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
+        {
+            CpiApplicationAddReferenceInstall(pItm->pAssembly->pApplication);
+            pItm->pAssembly->fReferencedForInstall = TRUE;
+            pSubList->iInstallCount++;
+            if (pItm->pAssembly->iAttributes & aaRunInCommit)
+                pSubList->iCommitCount++;
+        }
+        if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
+        {
+            CpiApplicationAddReferenceUninstall(pItm->pAssembly->pApplication);
+            pItm->pAssembly->fReferencedForUninstall = TRUE;
+            pSubList->iUninstallCount++;
+        }
+
+        // add entry
+        if (pSubList->pFirst)
+            pItm->pNext = pSubList->pFirst;
+        pSubList->pFirst = pItm;
+        pItm = NULL;
+    }
+
+    if (E_NOMOREITEMS == hr)
+        hr = S_OK;
+
+LExit:
+    // clean up
+    if (pItm)
+        FreeSubscription(pItm);
+
+    ReleaseStr(pwzData);
+
+    return hr;
+}
+
+HRESULT CpiSubscriptionsVerifyInstall(
+    CPI_SUBSCRIPTION_LIST* pList
+    )
+{
+    HRESULT hr = S_OK;
+    UINT er = ERROR_SUCCESS;
+
+    ICatalogObject* piSubsObj = NULL;
+
+    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
+    {
+        // subscriptions that are being installed
+        if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
+            continue;
+
+        // subscription is supposed to exist
+        if (CpiIsInstalled(pItm->isInstalled))
+        {
+            // if we don't have an id
+            if (!*pItm->wzID)
+            {
+                // find subscriptions with conflicting name
+                hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
+                ExitOnFailure(hr, "Failed to find collection object for subscription");
+
+                // if the subscription was found
+                if (S_OK == hr)
+                {
+                    // get id from subscription object
+                    hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
+                    ExitOnFailure(hr, "Failed to get id");
+                }
+
+                // if the subscription was not found
+                else
+                {
+                    // create a new id
+                    hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
+                    ExitOnFailure(hr, "Failed to create id");
+                }
+            }
+        }
+
+        // subscription is supposed to be created
+        else
+        {
+            // check for conflicts
+            do {
+                if (*pItm->wzID)
+                {
+                    // find subscriptions with conflicting id
+                    hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj);
+                    ExitOnFailure(hr, "Failed to find collection object for subscription");
+
+                    if (S_FALSE == hr)
+                    {
+                        // find subscriptions with conflicting name
+                        hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
+                        ExitOnFailure(hr, "Failed to find collection object for subscription");
+
+                        if (S_OK == hr)
+                            // "A subscription with a conflictiong name exists. retry cancel"
+                            er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
+                        else
+                            break; // no conflicting entry found, break loop
+                    }
+                    else
+                        // "A subscription with a conflicting id exists. abort retry ignore"
+                        er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
+                }
+                else
+                {
+                    // find subscriptions with conflicting name
+                    hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
+                    ExitOnFailure(hr, "Failed to find collection object for subscription");
+
+                    if (S_OK == hr)
+                        // "A subscription with a conflictiong name exists. abort retry ignore"
+                        er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
+                    else
+                        break; // no conflicting entry found, break loop
+                }
+
+                switch (er)
+                {
+                case IDCANCEL:
+                case IDABORT:
+                    ExitOnFailure(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey);
+                    break;
+                case IDRETRY:
+                    break;
+                case IDIGNORE:
+                default:
+                    // if we don't have an id, copy id from object
+                    if (!*pItm->wzID)
+                    {
+                        hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
+                        ExitOnFailure(hr, "Failed to get id");
+                    }
+                    hr = S_FALSE; // indicate that this is not a conflict
+                }
+            } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
+
+            // create a new id if one is missing
+            if (!*pItm->wzID)
+            {
+                hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
+                ExitOnFailure(hr, "Failed to create id");
+            }
+        }
+
+        // clean up
+        ReleaseNullObject(piSubsObj);
+    }
+
+    hr = S_OK;
+
+LExit:
+    // clean up
+    ReleaseObject(piSubsObj);
+
+    return hr;
+}
+
+HRESULT CpiSubscriptionsVerifyUninstall(
+    CPI_SUBSCRIPTION_LIST* pList
+    )
+{
+    HRESULT hr = S_OK;
+    ICatalogObject* piSubsObj = NULL;
+
+    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
+    {
+        // subscriptions that are being installed
+        if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
+            continue;
+
+        // find subscriptions with conflicting name
+        hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj);
+        ExitOnFailure(hr, "Failed to find collection object for subscription");
+
+        // if the subscription was found
+        if (S_OK == hr)
+        {
+            // if we don't have an id, copy id from object
+            if (!*pItm->wzID)
+            {
+                hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
+                ExitOnFailure(hr, "Failed to get id");
+            }
+        }
+
+        // if the subscription was not found
+        else
+        {
+            pItm->fObjectNotFound = TRUE;
+            pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
+        }
+
+        // clean up
+        ReleaseNullObject(piSubsObj);
+    }
+
+    hr = S_OK;
+
+LExit:
+    // clean up
+    ReleaseObject(piSubsObj);
+
+    return hr;
+}
+
+HRESULT CpiSubscriptionsInstall(
+    CPI_SUBSCRIPTION_LIST* pList,
+    int iRunMode,
+    LPWSTR* ppwzActionData,
+    int* piProgress
+    )
+{
+    HRESULT hr = S_OK;
+
+    int iActionType;
+    int iCount = 0;
+
+    // add action text
+    hr = CpiAddActionTextToActionData(L"CreateSubscrComPlusComponents", ppwzActionData);
+    ExitOnFailure(hr, "Failed to add action text to custom action data");
+
+    // subscription count
+    switch (iRunMode)
+    {
+    case rmDeferred:
+        iCount = pList->iInstallCount - pList->iCommitCount;
+        break;
+    case rmCommit:
+        iCount = pList->iCommitCount;
+        break;
+    case rmRollback:
+        iCount = pList->iInstallCount;
+        break;
+    }
+
+    // add subscription count to action data
+    hr = WcaWriteIntegerToCaData(iCount, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add count to custom action data");
+
+    // add assemblies to custom action data in forward order
+    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
+    {
+        // roles that are being installed only
+        if ((rmCommit == iRunMode && !(pItm->pAssembly->iAttributes & aaRunInCommit)) ||
+            (rmDeferred == iRunMode && (pItm->pAssembly->iAttributes & aaRunInCommit)) ||
+            !WcaIsInstalling(pItm->isInstalled, pItm->isAction))
+            continue;
+
+        // action type
+        if (rmRollback == iRunMode)
+        {
+            if (CpiIsInstalled(pItm->isInstalled))
+                iActionType = atNoOp;
+            else
+                iActionType = atRemove;
+        }
+        else
+            iActionType = atCreate;
+
+        // add to action data
+        hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_CREATE, ppwzActionData);
+        ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
+    }
+
+    // add progress tics
+    if (piProgress)
+        *piProgress += COST_SUBSCRIPTION_CREATE * pList->iInstallCount;
+
+    hr = S_OK;
+
+LExit:
+    return hr;
+}
+
+HRESULT CpiSubscriptionsUninstall(
+    CPI_SUBSCRIPTION_LIST* pList,
+    int iRunMode,
+    LPWSTR* ppwzActionData,
+    int* piProgress
+    )
+{
+    HRESULT hr = S_OK;
+
+    int iActionType;
+
+    // add action text
+    hr = CpiAddActionTextToActionData(L"RemoveSubscrComPlusComponents", ppwzActionData);
+    ExitOnFailure(hr, "Failed to add action text to custom action data");
+
+    // add subscription count to action data
+    hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add count to custom action data");
+
+    // add assemblies to custom action data in reverse order
+    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
+    {
+        // roles that are being uninstalled only
+        if (pItm->fObjectNotFound || !WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
+            continue;
+
+        // action type
+        if (rmRollback == iRunMode)
+            iActionType = atCreate;
+        else
+            iActionType = atRemove;
+
+        // add to action data
+        hr = AddSubscriptionToActionData(pItm, iActionType, COST_SUBSCRIPTION_DELETE, ppwzActionData);
+        ExitOnFailure(hr, "Failed to add subscription to custom action data, key: %S", pItm->wzKey);
+    }
+
+    // add progress tics
+    if (piProgress)
+        *piProgress += COST_SUBSCRIPTION_DELETE * pList->iUninstallCount;
+
+    hr = S_OK;
+
+LExit:
+    return hr;
+}
+
+
+// helper function definitions
+
+static void FreeSubscription(
+    CPI_SUBSCRIPTION* pItm
+    )
+{
+    if (pItm->pProperties)
+        CpiPropertiesFreeList(pItm->pProperties);
+
+    ::HeapFree(::GetProcessHeap(), 0, pItm);
+}
+
+static HRESULT FindObjectForSubscription(
+    CPI_SUBSCRIPTION* pItm,
+    BOOL fFindId,
+    BOOL fFindName,
+    ICatalogObject** ppiSubsObj
+    )
+{
+    HRESULT hr = S_OK;
+
+    ICatalogCollection* piSubsColl = NULL;
+
+    // get applications collection
+    hr = CpiGetSubscriptionsCollForComponent(pItm->pAssembly, pItm->pComponent, &piSubsColl);
+    ExitOnFailure(hr, "Failed to get collection");
+
+    if (S_FALSE == hr)
+        ExitFunction(); // exit with hr = S_FALSE
+
+    // find application object
+    hr = CpiFindCollectionObject(piSubsColl, fFindId ? pItm->wzID : NULL, fFindName ? pItm->wzName : NULL, ppiSubsObj);
+    ExitOnFailure(hr, "Failed to find object");
+
+    // exit with hr from CpiFindCollectionObject()
+
+LExit:
+    // clean up
+    ReleaseObject(piSubsColl);
+
+    return hr;
+}
+
+static HRESULT AddSubscriptionToActionData(
+    CPI_SUBSCRIPTION* pItm,
+    int iActionType,
+    int iActionCost,
+    LPWSTR* ppwzActionData
+    )
+{
+    HRESULT hr = S_OK;
+
+    // add action information to custom action data
+    hr = WcaWriteIntegerToCaData(iActionType, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add action type to custom action data");
+    hr = WcaWriteIntegerToCaData(iActionCost, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add action cost to custom action data");
+
+    // add application role information to custom action data
+    hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add subscription key to custom action data");
+    hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add subscription id to custom action data");
+    hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add subscription name to custom action data");
+    hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzEventCLSID : L"", ppwzActionData);
+    ExitOnFailure(hr, "Failed to add assembly tlb path to custom action data");
+    hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->wzPublisherID : L"", ppwzActionData);
+    ExitOnFailure(hr, "Failed to add assembly proxy-stub dll path to custom action data");
+
+    // add component information to custom action data
+    hr = WcaWriteStringToCaData(pItm->pComponent->wzCLSID, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add application id to custom action data");
+
+    // add application information to custom action data
+    hr = WcaWriteStringToCaData(pItm->pAssembly->pApplication->wzID, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add application id to custom action data");
+
+    // add partition information to custom action data
+    LPCWSTR pwzPartID = pItm->pAssembly->pApplication->pPartition ? pItm->pAssembly->pApplication->pPartition->wzID : L"";
+    hr = WcaWriteStringToCaData(pwzPartID, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add partition id to custom action data");
+
+    // add properties to custom action data
+    hr = CpiAddPropertiesToActionData(atCreate == iActionType ? pItm->iPropertyCount : 0, pItm->pProperties, ppwzActionData);
+    ExitOnFailure(hr, "Failed to add properties to custom action data");
+
+    hr = S_OK;
+
+LExit:
+    return hr;
+}
+
+static HRESULT ComponentFindByKey(
+    CPI_ASSEMBLY_LIST* pAsmList,
+    LPCWSTR pwzKey,
+    CPI_ASSEMBLY** ppAsmItm,
+    CPISCHED_COMPONENT** ppCompItm
+    )
+{
+    for (CPI_ASSEMBLY* pAsmItm = pAsmList->pFirst; pAsmItm; pAsmItm = pAsmItm->pNext)
+    {
+        for (CPISCHED_COMPONENT* pCompItm = pAsmItm->pComponents; pCompItm; pCompItm = pCompItm->pNext)
+        {
+            if (0 == lstrcmpW(pCompItm->wzKey, pwzKey))
+            {
+                *ppAsmItm = pAsmItm;
+                *ppCompItm = pCompItm;
+                return S_OK;
+            }
+        }
+    }
+
+    return S_FALSE;
+}
-- 
cgit v1.2.3-55-g6feb