Example #1
0
static HRESULT AddPartitionToActionData(
    CPI_PARTITION* 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 partition information to custom action data
    hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition key to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzID, ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition id to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition name 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;
}
Example #2
0
HRESULT CpiAddPropertiesToActionData(
    int iPropCount,
    CPI_PROPERTY* pPropList,
    LPWSTR* ppwzActionData
    )
{
    HRESULT hr = S_OK;

    hr = WcaWriteIntegerToCaData(iPropCount, ppwzActionData);
    ExitOnFailure(hr, "Failed to add count to custom action data");

    if (iPropCount) // count might be 0 event thought there are elements in the list
    {
        for (CPI_PROPERTY* pProp = pPropList; pProp; pProp = pProp->pNext)
        {
            hr = WcaWriteStringToCaData(pProp->wzName, ppwzActionData);
            ExitOnFailure(hr, "Failed to add property name to custom action data, name: %S", pProp->wzName);

            hr = WcaWriteStringToCaData(pProp->pwzValue, ppwzActionData);
            ExitOnFailure(hr, "Failed to add property value to custom action data, name: %S", pProp->wzName);
        }
    }

    hr = S_OK;

LExit:
    return hr;
}
Example #3
0
static HRESULT AddPartitionUserToActionData(
    CPI_PARTITION_USER* 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 partition user information to custom action data
    hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition user key to custom action data");
    hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
    ExitOnFailure(hr, "Failed to add user account to custom action data");

    // add partition information to custom action data
    hr = WcaWriteStringToCaData(atCreate == iActionType ? pItm->pPartition->wzID : L"", ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition id to custom action data");

    hr = S_OK;

LExit:
    return hr;
}
Example #4
0
static HRESULT AddMessageQueueToActionData(
    MQI_MESSAGE_QUEUE* pItm,
    LPWSTR* ppwzActionData
    )
{
    HRESULT hr = S_OK;

    // add message queue information to custom action data
    hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
    ExitOnFailure(hr, "Failed to add key to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iBasePriority, ppwzActionData);
    ExitOnFailure(hr, "Failed to add base priority to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iJournalQuota, ppwzActionData);
    ExitOnFailure(hr, "Failed to add journal quota to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzLabel, ppwzActionData);
    ExitOnFailure(hr, "Failed to add label to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzMulticastAddress, ppwzActionData);
    ExitOnFailure(hr, "Failed to add multicast address to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzPathName, ppwzActionData);
    ExitOnFailure(hr, "Failed to add path name to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iPrivLevel, ppwzActionData);
    ExitOnFailure(hr, "Failed to add privacy level to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iQuota, ppwzActionData);
    ExitOnFailure(hr, "Failed to add quota to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzServiceTypeGuid, ppwzActionData);
    ExitOnFailure(hr, "Failed to add service type guid to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
    ExitOnFailure(hr, "Failed to add attributes to custom action data");

    hr = S_OK;

LExit:
    return hr;
}
Example #5
0
static HRESULT AddUserInPartitionRoleToActionData(
    CPI_USER_IN_PARTITION_ROLE* 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 key to custom action data");
    hr = WcaWriteStringToCaData(pItm->pPartitionRole->wzName, ppwzActionData);
    ExitOnFailure(hr, "Failed to add role name to custom action data");
    hr = WcaWriteStringToCaData(pItm->pwzAccount, ppwzActionData);
    ExitOnFailure(hr, "Failed to add user account to custom action data");

    // add partition information to custom action data
    hr = WcaWriteStringToCaData(pItm->pPartitionRole->pPartition->wzID, ppwzActionData);
    ExitOnFailure(hr, "Failed to add partition id to custom action data");

    hr = S_OK;

LExit:
    return hr;
}
Example #6
0
static HRESULT BeginChangeFile(
    __in LPCWSTR pwzFile,
    __in int iCompAttributes,
    __inout LPWSTR* ppwzCustomActionData
    )
{
    Assert(pwzFile && *pwzFile && ppwzCustomActionData);

    HRESULT hr = S_OK;
    BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;

    LPBYTE pbData = NULL;
    DWORD cbData = 0;

    LPWSTR pwzRollbackCustomActionData = NULL;

    if (fIs64Bit)
    {
        hr = WcaWriteIntegerToCaData((int)xaOpenFilex64, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write 64-bit file indicator to custom action data");
    }
    else
    {
        hr = WcaWriteIntegerToCaData((int)xaOpenFile, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write file indicator to custom action data");
    }

    hr = WcaWriteStringToCaData(pwzFile, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write file to custom action data: %ls", pwzFile);

    // If the file already exits, then we have to put it back the way it was on failure
    if (FileExistsEx(pwzFile, NULL))
    {
        hr = FileRead(&pbData, &cbData, pwzFile);
        ExitOnFailure1(hr, "failed to read file: %ls", pwzFile);

        // Set up the rollback for this file
        hr = WcaWriteIntegerToCaData((int)fIs64Bit, &pwzRollbackCustomActionData);
        ExitOnFailure(hr, "failed to write component bitness to rollback custom action data");

        hr = WcaWriteStringToCaData(pwzFile, &pwzRollbackCustomActionData);
        ExitOnFailure1(hr, "failed to write file name to rollback custom action data: %ls", pwzFile);

        hr = WcaWriteStreamToCaData(pbData, cbData, &pwzRollbackCustomActionData);
        ExitOnFailure(hr, "failed to write file contents to rollback custom action data.");

        hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecXmlConfigRollback"), pwzRollbackCustomActionData, COST_XMLFILE);
        ExitOnFailure1(hr, "failed to schedule ExecXmlConfigRollback for file: %ls", pwzFile);

        ReleaseStr(pwzRollbackCustomActionData);
    }
LExit:
    ReleaseMem(pbData);

    return hr;
}
Example #7
0
static HRESULT WriteGroupInfo(
    __in SCA_GROUP* psgList,
    __in LPWSTR *ppwzActionData
    )
{
    HRESULT hr = S_OK;

    for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
    {
        hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData);
        ExitOnFailure1(hr, "failed to add group name to custom action data: %ls", psg->wzName);

        hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData);
        ExitOnFailure1(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain);
    }

LExit:
    return hr;
}
Example #8
0
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;
}
Example #9
0
// Behaves like WriteGroupInfo, but it filters out groups the user is currently a member of,
// because we don't want to rollback those
static HRESULT WriteGroupRollbackInfo(
    __in LPCWSTR pwzName,
    __in LPCWSTR pwzDomain,
    __in SCA_GROUP* psgList,
    __in LPWSTR *ppwzActionData
    )
{
    HRESULT hr = S_OK;
    BOOL fIsMember = FALSE;

    for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
    {
        hr = UserCheckIsMember(pwzName, pwzDomain, psg->wzName, psg->wzDomain, &fIsMember);
        if (FAILED(hr))
        {
            WcaLog(LOGMSG_VERBOSE, "Failed to check if user: %ls (domain: %ls) is member of a group while collecting rollback information (error code 0x%x) - continuing", pwzName, pwzDomain, hr);
            hr = S_OK;
            continue;
        }

        // If the user is currently a member, we don't want to undo that on rollback, so skip adding
        // this group record to the list of groups to rollback
        if (fIsMember)
        {
            continue;
        }

        hr = WcaWriteStringToCaData(psg->wzName, ppwzActionData);
        ExitOnFailure1(hr, "failed to add group name to custom action data: %ls", psg->wzName);

        hr = WcaWriteStringToCaData(psg->wzDomain, ppwzActionData);
        ExitOnFailure1(hr, "failed to add group domain to custom action data: %ls", psg->wzDomain);
    }

LExit:
    return hr;
}
Example #10
0
static HRESULT AddMessageQueuePermissionToActionData(
    MQI_MESSAGE_QUEUE_PERMISSION* pItm,
    LPWSTR* ppwzActionData
    )
{
    HRESULT hr = S_OK;

    // add message queue information to custom action data
    hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
    ExitOnFailure(hr, "Failed to add key to custom action data");
    hr = WcaWriteStringToCaData(pItm->pMessageQueue->wzPathName, ppwzActionData);
    ExitOnFailure(hr, "Failed to add path name to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzDomain, ppwzActionData);
    ExitOnFailure(hr, "Failed to add domain to custom action data");
    hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
    ExitOnFailure(hr, "Failed to add name to custom action data");
    hr = WcaWriteIntegerToCaData(pItm->iPermissions, ppwzActionData);
    ExitOnFailure(hr, "Failed to add permissions to custom action data");

    hr = S_OK;

LExit:
    return hr;
}
Example #11
0
static HRESULT WriteChangeData(
    __in XML_CONFIG_CHANGE* pxfc,
    __in eXmlAction action,
    __inout LPWSTR* ppwzCustomActionData
    )
{
    Assert(pxfc && ppwzCustomActionData);

    HRESULT hr = S_OK;
    XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL;

    hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath);

    hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath);

    hr = WcaWriteStringToCaData(pxfc->wzName, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write Name to custom action data: %ls", pxfc->wzName);

    hr = WcaWriteStringToCaData(pxfc->pwzValue, ppwzCustomActionData);
    ExitOnFailure1(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue);

    if (pxfc->iXmlFlags & XMLCONFIG_CREATE && pxfc->iXmlFlags & XMLCONFIG_ELEMENT && xaCreateElement == action && pxfc->pxfcAdditionalChanges)
    {
        hr = WcaWriteIntegerToCaData(pxfc->cAdditionalChanges, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write additional changes value to custom action data");

        pxfcAdditionalChanges = pxfc->pxfcAdditionalChanges;
        while (pxfcAdditionalChanges)
        {
            Assert((0 == lstrcmpW(pxfcAdditionalChanges->wzComponent, pxfc->wzComponent)) && 0 == pxfcAdditionalChanges->iXmlFlags && (0 == lstrcmpW(pxfcAdditionalChanges->wzFile, pxfc->wzFile)));

            hr = WcaWriteStringToCaData(pxfcAdditionalChanges->wzName, ppwzCustomActionData);
            ExitOnFailure1(hr, "failed to write Name to custom action data: %ls", pxfc->wzName);

            hr = WcaWriteStringToCaData(pxfcAdditionalChanges->pwzValue, ppwzCustomActionData);
            ExitOnFailure1(hr, "failed to write Value to custom action data: %ls", pxfc->pwzValue);

            pxfcAdditionalChanges = pxfcAdditionalChanges->pxfcNext;
        }
    }
    else
    {
        hr = WcaWriteIntegerToCaData(0, ppwzCustomActionData);
        ExitOnFailure(hr, "failed to write additional changes value to custom action data");
    }

LExit:
    return hr;
}
Example #12
0
HRESULT SchedDropDatabase(
    __in LPCWSTR wzKey,
    __in LPCWSTR wzServer,
    __in LPCWSTR wzInstance,
    __in LPCWSTR wzDatabase,
    __in int iAttributes,
    __in BOOL fIntegratedAuth,
    __in LPCWSTR wzUser,
    __in LPCWSTR wzPassword
    )
{
    HRESULT hr = S_OK;
    WCHAR* pwzCustomActionData = NULL;

    hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
    ExitOnFailure(hr, "failed to add DBKey to CustomActionData");

    hr = WcaWriteStringToCaData(wzServer, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server name to CustomActionData");

    hr = WcaWriteStringToCaData(wzInstance, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server instance to CustomActionData");

    hr = WcaWriteStringToCaData(wzDatabase, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add database name to CustomActionData");

    hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server name to CustomActionData");

    hr = WcaWriteStringToCaData(fIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server name to CustomActionData");

    hr = WcaWriteStringToCaData(wzUser, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server user to CustomActionData");

    hr = WcaWriteStringToCaData(wzPassword, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add user password to CustomActionData");

    hr = WcaDoDeferredAction(L"DropDatabase", pwzCustomActionData, COST_SQL_DROPDB);
    ExitOnFailure(hr, "Failed to schedule DropDatabase action");

LExit:
    ReleaseStr(pwzCustomActionData);
    return hr;
}
Example #13
0
HRESULT CpiAddActionTextToActionData(
    LPCWSTR pwzAction,
    LPWSTR* ppwzActionData
    )
{
    HRESULT hr = S_OK;

    PMSIHANDLE hView, hRecKey, hRec;

    LPWSTR pwzDescription = NULL;
    LPWSTR pwzTemplate = NULL;

    if (S_OK == WcaTableExists(L"ActionText"))
    {
        // create parameter record
        hRecKey = ::MsiCreateRecord(1);
        ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record");
        hr = WcaSetRecordString(hRecKey, 1, pwzAction);
        ExitOnFailure(hr, "Failed to set record string");

        // open view
        hr = WcaOpenView(vcsActionTextQuery, &hView);
        ExitOnFailure(hr, "Failed to open view on ActionText table");
        hr = WcaExecuteView(hView, hRecKey);
        ExitOnFailure(hr, "Failed to execute view on ActionText table");

        // fetch record
        hr = WcaFetchSingleRecord(hView, &hRec);
        if (S_FALSE != hr)
        {
            ExitOnFailure(hr, "Failed to fetch action text record");

            // get description
            hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription);
            ExitOnFailure(hr, "Failed to get description");

            // get template
            hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate);
            ExitOnFailure(hr, "Failed to get template");
        }
    }

    // add action name to action data
    hr = WcaWriteStringToCaData(pwzAction, ppwzActionData);
    ExitOnFailure(hr, "Failed to add action name to custom action data");

    // add description to action data
    hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData);
    ExitOnFailure(hr, "Failed to add description to custom action data");

    // add template to action data
    hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData);
    ExitOnFailure(hr, "Failed to add template to custom action data");

    hr = S_OK;

LExit:
    // clean up
    ReleaseStr(pwzDescription);
    ReleaseStr(pwzTemplate);

    return hr;
}
Example #14
0
static HRESULT SchedCreateDatabase(
    __in SCA_DB* psd
    )
{
    HRESULT hr = S_OK;
    WCHAR* pwzCustomActionData = NULL;

    hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
    ExitOnFailure(hr, "failed to add DBKey to CustomActionData");

    hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server name to CustomActionData");

    hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server instance to CustomActionData");

    hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add database name to CustomActionData");

    hr = WcaWriteIntegerToCaData(psd->iAttributes, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add Sql attributes to CustomActionData");

    hr = WcaWriteStringToCaData(psd->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add if integrated connection to CustomActionData");

    hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add server user to CustomActionData");

    hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add user password to CustomActionData");

    // Check to see if the database exists, if it does not then schedule a rollback
    // so we clean up after ourselves if the creation of the database fails or is
    // aborted.  It is interesting to note that we can do this check here because the
    // deferred CustomActions are Impersonated.  That means this scheduling action and
    // the execution actions all run with the same user context, so it is safe to
    // to do the check.
    hr = SqlDatabaseExists(psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword, NULL);
    if (S_FALSE == hr)
    {
        hr = WcaDoDeferredAction(L"RollbackCreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB);
        ExitOnFailure(hr, "Failed to schedule RollbackCreateDatabase action");
    }

    // database filespec
    if (psd->fHasDbSpec)
    {
        hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
        ExitOnFailure(hr, "failed to specify that do have db.filespec to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfDb.wzName, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfDb.wzFilename, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfDb.wzSize, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfDb.wzMaxSize, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfDb.wzGrow, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
    }
    else
    {
        hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
        ExitOnFailure(hr, "failed to specify that do not have db.filespec to CustomActionData");
    }

    // log filespec
    if (psd->fHasLogSpec)
    {
        hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData);
        ExitOnFailure(hr, "failed to specify that do have log.filespec to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfLog.wzName, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfLog.wzFilename, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfLog.wzSize, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfLog.wzMaxSize, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData");

        hr = WcaWriteStringToCaData(psd->sfLog.wzGrow, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData");
    }
    else
    {
        hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData);
        ExitOnFailure(hr, "failed to specify that do not have log.filespec to CustomActionData");
    }

    // schedule the CreateDatabase action
    hr = WcaDoDeferredAction(L"CreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB);
    ExitOnFailure(hr, "Failed to schedule CreateDatabase action");

LExit:
    ReleaseStr(pwzCustomActionData);
    return hr;
}
Example #15
0
/******************************************************************
 SchedNetFx - entry point for NetFx Custom Action

********************************************************************/
extern "C" UINT __stdcall SchedNetFx(
    __in MSIHANDLE hInstall
    )
{
    // AssertSz(FALSE, "debug SchedNetFx");

    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    LPWSTR pwzInstallCustomActionData = NULL;
    LPWSTR pwzUninstallCustomActionData = NULL;
    UINT uiCost = 0;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;
    PMSIHANDLE hViewGac = NULL;
    PMSIHANDLE hRecGac = NULL;

    LPWSTR pwzId = NULL;
    LPWSTR pwzData = NULL;
    LPWSTR pwzTemp = NULL;
    LPWSTR pwzFile = NULL;
    int iPriority = 0;
    int iAssemblyCost = 0;
    int iAttributes = 0;
    LPWSTR pwzFileApp = NULL;
    LPWSTR pwzDirAppBase = NULL;
    LPWSTR pwzComponent = NULL;

    INSTALLSTATE isInstalled;
    INSTALLSTATE isAction;

    LPWSTR pwz32Ngen = NULL;
    LPWSTR pwz64Ngen = NULL;

    BOOL f32NgenExeExists = FALSE;
    BOOL f64NgenExeExists = FALSE;

    BOOL fNeedInstallUpdate32 = FALSE;
    BOOL fNeedUninstallUpdate32 = FALSE;
    BOOL fNeedInstallUpdate64 = FALSE;
    BOOL fNeedUninstallUpdate64 = FALSE;

    // initialize
    hr = WcaInitialize(hInstall, "SchedNetFx");
    ExitOnFailure(hr, "failed to initialize");

    hr = GetNgenPath(&pwz32Ngen, FALSE);
    f32NgenExeExists = SUCCEEDED(hr);
    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
    {
        hr = ERROR_SUCCESS;
        WcaLog(LOGMSG_STANDARD, "Failed to find 32bit ngen. No actions will be scheduled to create native images for 32bit.");
    }
    ExitOnFailure(hr, "failed to get 32bit ngen.exe path");

    hr = GetNgenPath(&pwz64Ngen, TRUE);
    f64NgenExeExists = SUCCEEDED(hr);
    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
    {
        hr = ERROR_SUCCESS;
        WcaLog(LOGMSG_STANDARD, "Failed to find 64bit ngen. No actions will be scheduled to create native images for 64bit.");
    }
    ExitOnFailure(hr, "failed to get 64bit ngen.exe path");

    // loop through all the NetFx records
    hr = WcaOpenExecuteView(vcsNgenQuery, &hView);
    ExitOnFailure(hr, "failed to open view on NetFxNativeImage table");

    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        // Get Id
        hr = WcaGetRecordString(hRec, ngqId, &pwzId);
        ExitOnFailure(hr, "failed to get NetFxNativeImage.NetFxNativeImage");

        // Get File
        hr = WcaGetRecordString(hRec, ngqFile, &pwzData);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_ for record: %ls", pwzId);
        hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData);
        ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData);
        hr = WcaGetFormattedString(pwzTemp, &pwzFile);
        ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData);

        // Get Priority
        hr = WcaGetRecordInteger(hRec, ngqPriority, &iPriority);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.Priority for record: %ls", pwzId);

        if (0 == iPriority)
            iAssemblyCost = COST_NGEN_BLOCKING;
        else
            iAssemblyCost = COST_NGEN_NONBLOCKING;

        // Get Attributes
        hr = WcaGetRecordInteger(hRec, ngqAttributes, &iAttributes);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.Attributes for record: %ls", pwzId);

        // Get File_Application or leave pwzFileApp NULL.
        hr = WcaGetRecordFormattedString(hRec, ngqFileApp, &pwzData);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_Application for record: %ls", pwzId);

        // Check if the value resolves to a valid file ID.
        if (S_OK == FileIdExists(pwzData))
        {
            // Resolve the file ID to a path.
            hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData);
            ExitOnFailure1(hr, "failed to format file application string for file: %ls", pwzData);

            hr = WcaGetFormattedString(pwzTemp, &pwzFileApp);
            ExitOnFailure1(hr, "failed to get formatted string for file application: %ls", pwzData);
        }
        else
        {
            // Assume record formatted to a path already.
            hr = StrAllocString(&pwzFileApp, pwzData, 0);
            ExitOnFailure1(hr, "failed to allocate string for file path: %ls", pwzData);

            hr = PathEnsureQuoted(&pwzFileApp, FALSE);
            ExitOnFailure1(hr, "failed to quote file path: %ls", pwzData);
        }

        // Get Directory_ApplicationBase or leave pwzDirAppBase NULL.
        hr = WcaGetRecordFormattedString(hRec, ngqDirAppBase, &pwzData);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId);

        if (WcaIsUnicodePropertySet(pwzData))
        {
            // Resolve the directory ID to a path.
            hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedDirectory, pwzData);
            ExitOnFailure1(hr, "failed to format directory application base string for property: %ls", pwzData);

            hr = WcaGetFormattedString(pwzTemp, &pwzDirAppBase);
            ExitOnFailure1(hr, "failed to get formatted string for directory application base: %ls", pwzData);
        }
        else
        {
            // Assume record formatted to a path already.
            hr = StrAllocString(&pwzDirAppBase, pwzData, 0);
            ExitOnFailure1(hr, "failed to allocate string for directory path: %ls", pwzData);

            hr = PathEnsureQuoted(&pwzDirAppBase, TRUE);
            ExitOnFailure1(hr, "failed to quote and backslashify directory: %ls", pwzData);
        }

        // Get Component
        hr = WcaGetRecordString(hRec, ngqComponent, &pwzComponent);
        ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId);
        er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction);
        ExitOnWin32Error1(er, hr, "failed to get install state for Component: %ls", pwzComponent);

        //
        // Figure out if it's going to be GAC'd.  The possibility exists that no assemblies are going to be GAC'd 
        // so we have to check for the MsiAssembly table first.
        //
        if (S_OK == WcaTableExists(L"MsiAssembly"))
        {
            hr = WcaOpenView(vcsNgenGac, &hViewGac);
            ExitOnFailure(hr, "failed to open view on File/MsiAssembly table");

            hr = WcaExecuteView(hViewGac, hRec);
            ExitOnFailure(hr, "failed to execute view on File/MsiAssembly table");

            hr = WcaFetchSingleRecord(hViewGac, &hRecGac);
            ExitOnFailure(hr, "failed to fetch File_Assembly from File/MsiAssembly table");

            if (S_FALSE != hr)
            {
                hr = WcaGetRecordString(hRecGac, nggApplication, &pwzData);
                ExitOnFailure(hr, "failed to get MsiAssembly.File_Application");

                // If it's in the GAC replace the file name with the strong name
                if (L'\0' == pwzData[0])
                {
                    hr = GetStrongName(&pwzFile, pwzComponent);
                    ExitOnFailure1(hr, "failed to get strong name for component: %ls", pwzData);
                }
            }
        }

        //
        // Schedule the work
        //
        if (!(iAttributes & NGEN_32BIT) && !(iAttributes & NGEN_64BIT))
            ExitOnFailure1(hr = E_INVALIDARG, "Neither 32bit nor 64bit is specified for NGEN of file: %ls", pwzFile);

        if (WcaIsInstalling(isInstalled, isAction) || WcaIsReInstalling(isInstalled, isAction))
        {
            if (iAttributes & NGEN_32BIT && f32NgenExeExists)
            {
                // Assemble the install command line
                hr = CreateInstallCommand(&pwzData, pwz32Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase);
                ExitOnFailure(hr, "failed to create install command line");

                hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData);
                ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData);

                hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData);
                ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData);

                uiCost += iAssemblyCost;

                fNeedInstallUpdate32 = TRUE;
            }

            if (iAttributes & NGEN_64BIT && f64NgenExeExists)
            {
                // Assemble the install command line
                hr = CreateInstallCommand(&pwzData, pwz64Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase);
                ExitOnFailure(hr, "failed to create install command line");

                hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command
                ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData);

                hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); // cost
                ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData);

                uiCost += iAssemblyCost;

                fNeedInstallUpdate64 = TRUE;
            }
        }
        else if (WcaIsUninstalling(isInstalled, isAction))
        {
            if (iAttributes & NGEN_32BIT && f32NgenExeExists)
            {
                hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz32Ngen, pwzFile);
                ExitOnFailure(hr, "failed to create update 32 command line");

                hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command
                ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData);

                hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost
                ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData);

                uiCost += COST_NGEN_NONBLOCKING;

                fNeedUninstallUpdate32 = TRUE;
            }

            if (iAttributes & NGEN_64BIT && f64NgenExeExists)
            {
                hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz64Ngen, pwzFile);
                ExitOnFailure(hr, "failed to create update 64 command line");

                hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command
                ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData);

                hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost
                ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData);

                uiCost += COST_NGEN_NONBLOCKING;

                fNeedUninstallUpdate64 = TRUE;
            }
        }
    }
    if (E_NOMOREITEMS == hr)
        hr = S_OK;
    ExitOnFailure(hr, "failed while looping through all files to create native images for");

    // If we need 32 bit install update
    if (fNeedInstallUpdate32)
    {
        hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen);
        ExitOnFailure(hr, "failed to create install update 32 command line");

        hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command
        ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData);

        hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost
        ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData);

        uiCost += COST_NGEN_NONBLOCKING;
    }

    // If we need 32 bit uninstall update
    if (fNeedUninstallUpdate32)
    {
        hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen);
        ExitOnFailure(hr, "failed to create uninstall update 32 command line");

        hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command
        ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData);

        hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost
        ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData);

        uiCost += COST_NGEN_NONBLOCKING;
    }

    // If we need 64 bit install update
    if (fNeedInstallUpdate64)
    {
        hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen);
        ExitOnFailure(hr, "failed to create install update 64 command line");

        hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command
        ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData);

        hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost
        ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData);

        uiCost += COST_NGEN_NONBLOCKING;
    }

    // If we need 64 bit install update
    if (fNeedUninstallUpdate64)
    {
        hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen);
        ExitOnFailure(hr, "failed to create uninstall update 64 command line");

        hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command
        ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData);

        hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost
        ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData);

        uiCost += COST_NGEN_NONBLOCKING;
    }

    // Add to progress bar
    if ((pwzInstallCustomActionData && *pwzInstallCustomActionData) || (pwzUninstallCustomActionData && *pwzUninstallCustomActionData))
    {
        hr = WcaProgressMessage(uiCost, TRUE);
        ExitOnFailure(hr, "failed to extend progress bar for NetFxExecuteNativeImage");
    }

    // Schedule the install custom action
    if (pwzInstallCustomActionData && *pwzInstallCustomActionData)
    {
        hr = WcaSetProperty(L"NetFxExecuteNativeImageInstall", pwzInstallCustomActionData);
        ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageInstall action");

        hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitInstall", pwzInstallCustomActionData);
        ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitInstall action");
    }

    // Schedule the uninstall custom action
    if (pwzUninstallCustomActionData && *pwzUninstallCustomActionData)
    {
        hr = WcaSetProperty(L"NetFxExecuteNativeImageUninstall", pwzUninstallCustomActionData);
        ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageUninstall action");

        hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitUninstall", pwzUninstallCustomActionData);
        ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitUninstall action");
    }


LExit:
    ReleaseStr(pwzInstallCustomActionData);
    ReleaseStr(pwzUninstallCustomActionData);
    ReleaseStr(pwzId);
    ReleaseStr(pwzData);
    ReleaseStr(pwzTemp);
    ReleaseStr(pwzFile);
    ReleaseStr(pwzFileApp);
    ReleaseStr(pwzDirAppBase);
    ReleaseStr(pwzComponent);
    ReleaseStr(pwz32Ngen);
    ReleaseStr(pwz64Ngen);

    if (FAILED(hr))
        er = ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}
Example #16
0
/******************************************************************
 SchedSecureObjects - entry point for SchedSecureObjects Custom Action

 called as Type 1 CustomAction (binary DLL) from Windows Installer 
 in InstallExecuteSequence, to schedule ExecSecureObjects
******************************************************************/
extern "C" UINT __stdcall SchedSecureObjects(
    __in MSIHANDLE hInstall
    )
{
//    AssertSz(FALSE, "debug SchedSecureObjects");
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    LPWSTR pwzSecureObject = NULL;
    LPWSTR pwzData = NULL;
    LPWSTR pwzTable = NULL;
    LPWSTR pwzTargetPath = NULL;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;

    INSTALLSTATE isInstalled;
    INSTALLSTATE isAction;

    LPWSTR pwzCustomActionData = NULL;

    DWORD cObjects = 0;
    eOBJECTTYPE eType = OT_UNKNOWN;

    //
    // initialize
    //
    hr = WcaInitialize(hInstall, "SchedSecureObjects");
    ExitOnFailure(hr, "failed to initialize");

    // anything to do?
    if (S_OK != WcaTableExists(L"SecureObjects"))
    {
        WcaLog(LOGMSG_STANDARD, "SecureObjects table doesn't exist, so there are no objects to secure.");
        ExitFunction();
    }

    //
    // loop through all the objects to be secured
    //
    hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView);
    ExitOnFailure(hr, "failed to open view on SecureObjects table");
    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable);
        ExitOnFailure(hr, "failed to get object table");

        eType = EObjectTypeFromString(pwzTable);

        if (OT_UNKNOWN == eType)
        {
            ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable);
        }

        int iCompAttributes = 0;
        hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes);
        ExitOnFailure(hr, "failed to get Component attributes for secure object");

        BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit;

        // Only process entries in the SecureObjects table whose components match the bitness of this CA
#ifdef _WIN64
        if (!fIs64Bit)
        {
            continue;
        }
#else
        if (fIs64Bit)
        {
            continue;
        }
#endif

        // Get the object to secure
        hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject);
        ExitOnFailure(hr, "failed to get name of object");

        hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
        ExitOnFailure1(hr, "failed to get target path of object '%ls'", pwzSecureObject);

        hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData);
        ExitOnFailure(hr, "failed to get Component name for secure object");

        //
        // if we are installing this Component
        //
        er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
        ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %ls", pwzData);

        if (WcaIsInstalling(isInstalled, isAction))
        {
            hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            // add the data to the CustomActionData
            hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData);
            ExitOnFailure(hr, "failed to get name of object");

            hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData);
            ExitOnFailure(hr, "failed to get domain for user to configure object");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData);
            ExitOnFailure(hr, "failed to get user to configure object");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData);
            ExitOnFailure(hr, "failed to get permission to configure object");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            ++cObjects;
        }
    }

    // if we looped through all records all is well
    if (E_NOMOREITEMS == hr)
        hr = S_OK;
    ExitOnFailure(hr, "failed while looping through all objects to secure");

    //
    // schedule the custom action and add to progress bar
    //
    if (pwzCustomActionData && *pwzCustomActionData)
    {
        Assert(0 < cObjects);

        hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT);
        ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
    }

LExit:
    ReleaseStr(pwzSecureObject);
    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzData);
    ReleaseStr(pwzTable);
    ReleaseStr(pwzTargetPath);

    if (FAILED(hr))
    {
        er = ERROR_INSTALL_FAILURE;
    }
    return WcaFinalize(er);
}
/******************************************************************
 SchedAddinRegistration - entry point for AddinRegistration Custom Action

********************************************************************/
HRESULT SchedAddinRegistration(MSIHANDLE hInstall, BOOL fInstall)
{
    // AssertSz(FALSE, "debug SchedRegisterAddins");

    HRESULT hr = S_OK;

    LPWSTR pwzCustomActionData = NULL;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;

    LPWSTR pwzData = NULL;
    LPWSTR pwzTemp = NULL;
    LPWSTR pwzComponent = NULL;

    LPWSTR pwzId = NULL;
    LPWSTR pwzFile = NULL;
	LPWSTR pwzFriendlyName = NULL;
	LPWSTR pwzDescription = NULL;

	int iBitness = 0;
	int iCommandLineSafe = 1;
	int iLoadBehavior = 0;

	LPWSTR pwzAllUsers = NULL;

    int nAddins = 0;

	hr = WcaGetProperty(L"ALLUSERS", &pwzAllUsers);
	ExitOnFailure(hr, "failed to read value of ALLUSERS property");

    // loop through all the RegisterAddin records
    hr = WcaOpenExecuteView(vcsRegisterAddinsQuery, &hView);
    ExitOnFailure(hr, "failed to open view on AddinRegistration table");

    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
		++nAddins;

        // Get Id
        hr = WcaGetRecordString(hRec, arqId, &pwzId);
        ExitOnFailure(hr, "failed to get AddinRegistration.AddinRegistration");

        // Get File
        hr = WcaGetRecordString(hRec, arqFile, &pwzData);
        ExitOnFailure1(hr, "failed to get AddinRegistration.File_ for record: %ls", pwzId);
        hr = StrAllocFormatted(&pwzTemp, L"[#%ls]", pwzData);
        ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData);
        hr = WcaGetFormattedString(pwzTemp, &pwzFile);
        ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData);

        // Get name
        hr = WcaGetRecordFormattedString(hRec, arqName, &pwzFriendlyName);
        ExitOnFailure1(hr, "failed to get AddinRegistration.Name for record: %ls", pwzId);

        // Get description
        hr = WcaGetRecordFormattedString(hRec, arqDescription, &pwzDescription);
        ExitOnFailure1(hr, "failed to get AddinRegistration.Description for record: %ls", pwzId);

        // Get description
        hr = WcaGetRecordInteger(hRec, arqBitness, &iBitness);
        ExitOnFailure1(hr, "failed to get AddinRegistration.Bitnesss for record: %ls", pwzId);

        // Get description
        hr = WcaGetRecordInteger(hRec, arqCommandLineSafe, &iCommandLineSafe);
        ExitOnFailure1(hr, "failed to get AddinRegistration.CommandLineSafe for record: %ls", pwzId);

        // Get description
        hr = WcaGetRecordInteger(hRec, arqLoadBehavior, &iLoadBehavior);
        ExitOnFailure1(hr, "failed to get AddinRegistration.LoadBehavior for record: %ls", pwzId);

		// get component and its install/action states
        hr = WcaGetRecordString(hRec, arqComponent, &pwzComponent);
        ExitOnFailure(hr, "failed to get addin component id");

        // we need to know if the component's being installed, uninstalled, or reinstalled
        WCA_TODO todo = WcaGetComponentToDo(pwzComponent);

        // skip this entry if this is the install CA and we are uninstalling the component
        if (fInstall && WCA_TODO_UNINSTALL == todo)
        {
            continue;
        }

        // skip this entry if this is an uninstall CA and we are not uninstalling the component
        if (!fInstall && WCA_TODO_UNINSTALL != todo)
        {
            continue;
        }

        // write custom action data: operation, instance guid, path, directory
        hr = WcaWriteIntegerToCaData(todo, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write operation to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteStringToCaData(pwzId, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write id to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteStringToCaData(pwzFile, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write custom action data for instance id: %ls", pwzId);

        hr = WcaWriteStringToCaData(pwzFriendlyName, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write addin name to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write addin description to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteIntegerToCaData(iBitness, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write Bitness to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteIntegerToCaData(iCommandLineSafe, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write CommandLineSafe to custom action data for instance id: %ls", pwzId);

        hr = WcaWriteIntegerToCaData(iLoadBehavior, &pwzCustomActionData);
        ExitOnFailure1(hr, "failed to write LoadBehavior to custom action data for instance id: %ls", pwzId);

		hr = WcaWriteStringToCaData(pwzAllUsers, &pwzCustomActionData);
		ExitOnFailure(hr,  "failed to write allusers property to custom action data for instance id: %ls", pwzId);
	}

    if (E_NOMOREITEMS == hr)
        hr = S_OK;

    ExitOnFailure(hr, "failed while looping through all files to create native images for");

    // Schedule the install custom action
    if (pwzCustomActionData && *pwzCustomActionData)
    {
        WcaLog(LOGMSG_STANDARD, "Scheduling Addin Registration (%ls)", pwzCustomActionData);

        hr = WcaDoDeferredAction(L"RollbackAddinRegistration", pwzCustomActionData, nAddins * COST_REGISTER_ADDIN);
        ExitOnFailure(hr, "Failed to schedule addin registration rollback");

        hr = WcaDoDeferredAction(L"ExecAddinRegistration", pwzCustomActionData, nAddins * COST_REGISTER_ADDIN);
        ExitOnFailure(hr, "Failed to schedule addin registration execution");
    }

LExit:
	ReleaseStr(pwzAllUsers);
    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzId);
    ReleaseStr(pwzData);
	ReleaseStr(pwzData);
    ReleaseStr(pwzTemp);
    ReleaseStr(pwzComponent);
    ReleaseStr(pwzFile);
	ReleaseStr(pwzFriendlyName);
	ReleaseStr(pwzDescription);

    return hr;
}
Example #18
0
/******************************************************************
 CaSchedServiceConfig - entry point for CaSchedServiceConfig Custom Action

 called as Type 1 CustomAction (binary DLL) from Windows Installer
 in InstallExecuteSequence before CaExecServiceConfig
********************************************************************/
extern "C" UINT __stdcall SchedServiceConfig(
	__in MSIHANDLE hInstall
	)
{
//	AssertSz(FALSE, "debug SchedServiceConfig");
	HRESULT hr = S_OK;
	UINT uiResult = ERROR_SUCCESS;
	DWORD dwError = 0;

	LPWSTR pwzData = NULL;
	int iData = 0;
	BOOL fExistingService = FALSE;

	PMSIHANDLE hView = NULL;
	PMSIHANDLE hRec = NULL;

	INSTALLSTATE isInstalled;
	INSTALLSTATE isAction;

	SC_HANDLE hSCM = NULL;
	SC_HANDLE hService = NULL;

	LPSERVICE_FAILURE_ACTIONSW psfa;

	LPWSTR pwzCustomActionData = NULL;
	LPWSTR pwzRollbackCustomActionData = NULL;

	DWORD cServices = 0;

	DWORD dwRestartDelay = 0;
	WCHAR wzActionName[32] = { 0 };

	DWORD dwSizeNeeded = 0;

	// initialize
	hr = WcaInitialize(hInstall, "SchedServiceConfig");
	ExitOnFailure(hr, "failed to initialize");

	//Get a handle to the service control manager
	hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
	if (hSCM == NULL)
		ExitOnLastError(hr, "failed to get handle to SCM");

	// loop through all the services to be configured
	hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView);
	ExitOnFailure(hr, "failed to open view on ServiceConfig table");

	while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
	{
		hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData);
		ExitOnFailure(hr, "failed to get object NewService");

		fExistingService = 1 != iData;

		// Get component name
		hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData);
		ExitOnFailure(hr, "failed to get component name");

		// check if we are installing this Component
		hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
		ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "failed to get install state for Component: %S", pwzData);

		// We want to configure either a service we're installing or one already on the box
		if (WcaIsInstalling(isInstalled, isAction))
		{
			// Check if we're configuring an existing service
			if (fExistingService)
			{
				// Confirm the service is actually on the box
				hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
				ExitOnFailure(hr, "failed to get object NewService");

				//Get a handle to the service
				hService = ::OpenServiceW(hSCM, pwzData, SERVICE_QUERY_CONFIG);
				if (hService == NULL)
				{
					dwError = ::GetLastError();
					hr = HRESULT_FROM_WIN32(dwError);
					if (hr == ERROR_SERVICE_DOES_NOT_EXIST)
					{
						ExitOnFailure1(hr, "Service \"%s\" does not exist on this system.", pwzData);
					}
					else
					{
						ExitOnFailure1(hr, "Failed to get handle to the service \"%S\".", pwzData);
					}
				}

				// Get Current Service Config info
				if(!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &dwSizeNeeded) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
				{
					ExitOnLastError(hr, "Failed to get current service config info.");
				}

				// Alloc space we were told we needed
				psfa = (LPSERVICE_FAILURE_ACTIONSW) MemAlloc(dwSizeNeeded, TRUE);
				ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions.");

				// Now do the real query
				if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, dwSizeNeeded, &dwSizeNeeded))
					ExitOnLastError(hr, "failed to Query Service.");

				// Build up rollback CA data so we can restore service state if necessary
				hr = WcaWriteStringToCaData(pwzData, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// If this service struct is empty, fill in defualt values
				if(psfa->cActions < 3)
				{
					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
				}
				else
				{
					// psfa actually had actions defined, so use them

					// action 1
					hr = GetSCActionTypeString(psfa->lpsaActions[0].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[0].Type)
						dwRestartDelay = psfa->lpsaActions[0].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					// action 2
					hr = GetSCActionTypeString(psfa->lpsaActions[1].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[1].Type)
						dwRestartDelay = psfa->lpsaActions[1].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					// action 3
					hr = GetSCActionTypeString(psfa->lpsaActions[2].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[2].Type)
						dwRestartDelay = psfa->lpsaActions[2].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
				}

				hr = WcaWriteIntegerToCaData(psfa->dwResetPeriod / (24 * 60 * 60), &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");

				hr = WcaWriteIntegerToCaData(dwRestartDelay, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");

				// check for value being null
				if(!psfa->lpCommand)
					psfa->lpCommand = L"";
				hr = WcaWriteStringToCaData(psfa->lpCommand, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// check for value being null
				if(!psfa->lpRebootMsg)
					psfa->lpRebootMsg = L"";
				hr = WcaWriteStringToCaData(psfa->lpRebootMsg, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// Clear up per-service values
				if(psfa)
					MemFree(psfa);
			}

			// add the data to the CustomActionData (for install)
			hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
			ExitOnFailure(hr, "failed to get name of service");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get first failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get second failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get third failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData);
			if (hr == S_FALSE) // deal w/ possible null value
				iData = 0;
			ExitOnFailure(hr, "failed to get reset period in days between service restart attempts.");
			hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData);
			if (hr == S_FALSE) // deal w/ possible null value
				iData = 0;
			ExitOnFailure(hr, "failed to get server restart delay value.");
			hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly
			ExitOnFailure(hr, "failed to get command line to run on service failure.");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly
			ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure.");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			cServices++;
			::CloseServiceHandle(hService);
			hService = NULL;
		}
	}

	// if we looped through all records all is well
	if (E_NOMOREITEMS == hr)
		hr = S_OK;
	ExitOnFailure(hr, "failed while looping through all objects to secure");

	// setup CustomActionData and add to progress bar for download
	if (pwzRollbackCustomActionData && *pwzRollbackCustomActionData)
	{
		Assert(0 < cServices);

		hr = WcaDoDeferredAction(L"ExecServiceConfigRollback", pwzRollbackCustomActionData, cServices * COST_SERVICECONFIG);
		ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
	}

	// schedule the custom action and add to progress bar
	if (pwzCustomActionData && *pwzCustomActionData)
	{
		Assert(0 < cServices);

		hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG);
		ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
	}

LExit:
	// Clean up handles
	if (hService != NULL)
		::CloseServiceHandle(hService);
	if (hSCM != NULL)
		::CloseServiceHandle(hSCM);

	ReleaseStr(pwzCustomActionData);
	ReleaseStr(pwzRollbackCustomActionData);
	ReleaseStr(pwzData);

	if (FAILED(hr))
		uiResult = ERROR_INSTALL_FAILURE;
	return WcaFinalize(uiResult);
}
Example #19
0
/******************************************************************
 CaSchedSecureObjects - entry point for CaReadSecureObjects Custom Action

 called as Type 1 CustomAction (binary DLL) from Windows Installer
 in InstallExecuteSequence before CaSecureObjects
******************************************************************/
extern "C" UINT __stdcall SchedSecureObjects(
	__in MSIHANDLE hInstall
	)
{
//	AssertSz(FALSE, "debug SchedSecureObjects");
	HRESULT hr = S_OK;
	UINT er = ERROR_SUCCESS;

	LPWSTR pwzData = NULL;
	LPWSTR pwzTable = NULL;
	LPWSTR pwzTargetPath = NULL;
	LPWSTR pwzFormattedString = NULL;

	int iRoot = 0;
	int iAllUsers = 0;
	LPWSTR pwzKey = NULL;

	PMSIHANDLE hView = NULL;
	PMSIHANDLE hRec = NULL;

	MSIHANDLE hViewObject = NULL; // Don't free this since it's always a copy of either hViewService or hViewCreateFolder
	PMSIHANDLE hViewService = NULL;
	PMSIHANDLE hViewCreateFolder = NULL;
	PMSIHANDLE hViewFile = NULL;
	PMSIHANDLE hViewRegistry = NULL;
	PMSIHANDLE hRecObject = NULL;

	INSTALLSTATE isInstalled;
	INSTALLSTATE isAction;

	LPWSTR pwzCustomActionData = NULL;
	DWORD cchCustomActionData = 0;

	DWORD cObjects = 0;
	eOBJECTTYPE eType = OT_UNKNOWN;

	//
	// initialize
	//
	hr = WcaInitialize(hInstall, "SchedSecureObjects");
	ExitOnFailure(hr, "failed to initialize");

	//
	// loop through all the objects to be secured
	//
	hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView);
	ExitOnFailure(hr, "failed to open view on SecureObjects table");
	while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
	{
		hViewObject = NULL;
		eType = OT_UNKNOWN;

		hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable);
		ExitOnFailure(hr, "failed to get object table");

		// ensure we're looking at a known table
		if (0 == lstrcmpW(L"ServiceInstall", pwzTable))
		{
			eType = OT_SERVICE;
		}
		else if (0 == lstrcmpW(L"CreateFolder", pwzTable))
		{
			eType = OT_FOLDER;
		}
		else if (0 == lstrcmpW(L"File", pwzTable))
		{
			eType = OT_FILE;
		}
		else if (0 == lstrcmpW(L"Registry", pwzTable))
		{
			eType = OT_REGISTRY;
		}
		else
		{
			ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %S", pwzTable);
		}

		// if we haven't opened a view on the ServiceInstall/CreateFolder table, do that now
		if (OT_SERVICE == eType)
		{
			if (!hViewService)
			{
				hr = WcaTableExists(pwzTable);
				if (S_FALSE == hr)
					hr = E_UNEXPECTED;
				ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable);

				hr = WcaOpenView(wzQUERY_SERVICECOMPONENT, &hViewService);
				ExitOnFailure(hr, "failed to open view on ServiceInstall table");
			}

			hViewObject = hViewService;
		}
		else if (OT_FOLDER == eType)
		{
			if (!hViewCreateFolder)
			{
				hr = WcaTableExists(pwzTable);
				if (S_FALSE == hr)
					hr = E_UNEXPECTED;
				ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable);

				hr = WcaOpenView(wzQUERY_CREATEFOLDERCOMPONENT, &hViewCreateFolder);
				ExitOnFailure(hr, "failed to open view on CreateFolder table");
			}

			hViewObject = hViewCreateFolder;
		}
		else if (OT_FILE== eType)
		{
			if (!hViewFile)
			{
				hr = WcaTableExists(pwzTable);
				if (S_FALSE == hr)
					hr = E_UNEXPECTED;
				ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable);

				hr = WcaOpenView(wzQUERY_FILECOMPONENT, &hViewFile);
				ExitOnFailure(hr, "failed to open view on CreateFolder table");
			}

			hViewObject = hViewFile;
		}
		else if (OT_REGISTRY== eType)
		{
			if (!hViewRegistry)
			{
				hr = WcaTableExists(pwzTable);
				if (S_FALSE == hr)
					hr = E_UNEXPECTED;
				ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable);

				hr = WcaOpenView(wzQUERY_REGISTRYCOMPONENT, &hViewRegistry);
				ExitOnFailure(hr, "failed to open view on CreateFolder table");
			}

			hViewObject = hViewRegistry;
		}

		Assert(hViewObject);

		// execute a view looking for the object's Component_
		hr = WcaExecuteView(hViewObject, hRec);
		ExitOnFailure1(hr, "failed to execute view on %S table", pwzData);
		hr = WcaFetchSingleRecord(hViewObject, &hRecObject);
		ExitOnFailure(hr, "failed to fetch Component for secure object");

		hr = WcaGetRecordString(hRecObject, QSOC_COMPONENT, &pwzData);
		ExitOnFailure(hr, "failed to get Component name for secure object");

		//
		// if we are installing this Component
		//
		er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
		ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %S", pwzData);

		if (WcaIsInstalling(isInstalled, isAction))
		{
			// add the data to the CustomActionData
			hr = WcaGetRecordString(hRecObject, QSOC_OBJECTNAME, &pwzData);
			ExitOnFailure(hr, "failed to get name of object");

			if (OT_SERVICE == eType)
			{
				hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");
			}
			else if (OT_FOLDER == eType)
			{
				hr = WcaGetTargetPath(pwzData, &pwzTargetPath);
				ExitOnFailure1(hr, "failed to get target path for directory id: %S", pwzData);
				hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");
			}
			else if (OT_FILE == eType)
			{
				hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzData);
				ExitOnFailure1(hr, "failed to create formatted string for securing file object: %S", pwzData);

				hr = WcaGetFormattedString(pwzFormattedString, &pwzTargetPath);
				ExitOnFailure2(hr, "failed to get file path from formatted string: %S for secure object: %S", pwzFormattedString, pwzData);

				hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");
			}
			else if (OT_REGISTRY == eType)
			{
				hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot);
				ExitOnFailure1(hr, "Failed to get reg key root for secure object: %S", pwzData);

				hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey);
				ExitOnFailure1(hr, "Failed to get reg key for secure object: %S", pwzData);

				// Decode the root value
				if (-1 == iRoot)
				{
					// They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property
					hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers);
					ExitOnFailure(hr, "failed to get value of ALLUSERS property");

					if (1 == iAllUsers)
					{
						hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0);
						ExitOnFailure(hr, "failed to allocate target registry string with HKLM root");
					}
					else
					{
						hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0);
						ExitOnFailure(hr, "failed to allocate target registry string with HKCU root");
					}
				}
				else if (/*msidbRegistryRootClassesRoot*/ 0 == iRoot)
				{
					hr = StrAllocString(&pwzTargetPath, L"CLASSES_ROOT\\", 0);
					ExitOnFailure(hr, "failed to allocate target registry string with HKCR root");
				}
				else if (/*msidbRegistryRootCurrentUser*/ 1 == iRoot)
				{
					hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0);
					ExitOnFailure(hr, "failed to allocate target registry string with HKCU root");
				}
				else if (/*msidbRegistryRootLocalMachine*/ 2 == iRoot)
				{
					hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0);
					ExitOnFailure(hr, "failed to allocate target registry string with HKLM root");
				}
				else if (/*msidbRegistryRootUsers*/ 3 == iRoot)
				{
					hr = StrAllocString(&pwzTargetPath, L"USERS\\", 0);
					ExitOnFailure(hr, "failed to allocate target registry string with HKU root");
				}
				else
				{
					ExitOnFailure2(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%S' root: %d", pwzData, iRoot);
				}

				hr = StrAllocConcat(&pwzTargetPath, pwzKey, 0);
				ExitOnFailure2(hr, "Failed to concat key: %S for secure object: %S", pwzKey, pwzData);

				hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");
			}
			else
			{
				AssertSz(FALSE, "How did you get here?");
			}

			hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData);
			ExitOnFailure(hr, "failed to get domain for user to configure object");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData);
			ExitOnFailure(hr, "failed to get user to configure object");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData);
			ExitOnFailure(hr, "failed to get domain for user to configure object");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			cObjects++;
		}
	}

	// if we looped through all records all is well
	if (E_NOMOREITEMS == hr)
		hr = S_OK;
	ExitOnFailure(hr, "failed while looping through all objects to secure");

	//
	// schedule the custom action and add to progress bar
	//
	if (pwzCustomActionData && *pwzCustomActionData)
	{
		Assert(0 < cObjects);

		hr = WcaDoDeferredAction(L"ExecSecureObjects", pwzCustomActionData, cObjects * COST_SECUREOBJECT);
		ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
	}

LExit:
	ReleaseStr(pwzCustomActionData);
	ReleaseStr(pwzData);
	ReleaseStr(pwzTable);
	ReleaseStr(pwzTargetPath);
	ReleaseStr(pwzFormattedString);
	ReleaseStr(pwzKey);

	if (FAILED(hr))
		er = ERROR_INSTALL_FAILURE;
	return WcaFinalize(er);
}
Example #20
0
/******************************************************************
 SchedFirewallExceptions - immediate custom action worker to 
   register and remove firewall exceptions.

********************************************************************/
static UINT SchedFirewallExceptions(
    __in MSIHANDLE hInstall,
    WCA_TODO todoSched
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;
    int cFirewallExceptions = 0;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;

    LPWSTR pwzCustomActionData = NULL;
    LPWSTR pwzName = NULL;
    LPWSTR pwzRemoteAddresses = NULL;
    LPWSTR pwzPort = NULL;
    int iProtocol = 0;
    int iAttributes = 0;
    int iProfile = 0;
    LPWSTR pwzProgram = NULL;
    LPWSTR pwzComponent = NULL;
    LPWSTR pwzFormattedFile = NULL;
    LPWSTR pwzDescription = NULL;

    // initialize
    hr = WcaInitialize(hInstall, "SchedFirewallExceptions");
    ExitOnFailure(hr, "failed to initialize");

    // anything to do?
    if (S_OK != WcaTableExists(L"WixFirewallException"))
    {
        WcaLog(LOGMSG_STANDARD, "WixFirewallException table doesn't exist, so there are no firewall exceptions to configure.");
        ExitFunction();
    }

    // query and loop through all the firewall exceptions
    hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView);
    ExitOnFailure(hr, "failed to open view on WixFirewallException table");

    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        hr = WcaGetRecordFormattedString(hRec, feqName, &pwzName);
        ExitOnFailure(hr, "failed to get firewall exception name");

        hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &pwzRemoteAddresses);
        ExitOnFailure(hr, "failed to get firewall exception remote addresses");

        hr = WcaGetRecordFormattedString(hRec, feqPort, &pwzPort);
        ExitOnFailure(hr, "failed to get firewall exception port");

        hr = WcaGetRecordInteger(hRec, feqProtocol, &iProtocol);
        ExitOnFailure(hr, "failed to get firewall exception protocol");

        hr = WcaGetRecordFormattedString(hRec, feqProgram, &pwzProgram);
        ExitOnFailure(hr, "failed to get firewall exception program");

        hr = WcaGetRecordInteger(hRec, feqAttributes, &iAttributes);
        ExitOnFailure(hr, "failed to get firewall exception attributes");
        
        hr = WcaGetRecordInteger(hRec, feqProfile, &iProfile);
        ExitOnFailure(hr, "failed to get firewall exception profile");

        hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent);
        ExitOnFailure(hr, "failed to get firewall exception component");

        hr = WcaGetRecordString(hRec, feqDescription, &pwzDescription);
        ExitOnFailure(hr, "failed to get firewall description");

        // figure out what we're doing for this exception, treating reinstall the same as install
        WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent);
        if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
        {
            WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d)", pwzComponent, todoComponent, todoSched);
            continue;
        }

        // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path}
        ++cFirewallExceptions;
        hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception action to custom action data");

        hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception name to custom action data");

        hr = WcaWriteIntegerToCaData(iProfile, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception profile to custom action data");

        hr = WcaWriteStringToCaData(pwzRemoteAddresses, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception remote addresses to custom action data");

        hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception attributes to custom action data");

        if (*pwzProgram)
        {
            // If program is defined, we have an application exception.
            hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write exception target (application) to custom action data");

            hr = WcaWriteStringToCaData(pwzProgram, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write application path to custom action data");
        }
        else
        {
            // we have a port-only exception
            hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write exception target (port) to custom action data");
        }

        hr = WcaWriteStringToCaData(pwzPort, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write application path to custom action data");

        hr = WcaWriteIntegerToCaData(iProtocol, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write exception protocol to custom action data");

        hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to write firewall rule description to custom action data");
    }

    // reaching the end of the list is actually a good thing, not an error
    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    } 
    ExitOnFailure(hr, "failure occured while processing WixFirewallException table");

    // schedule ExecFirewallExceptions if there's anything to do
    if (pwzCustomActionData && *pwzCustomActionData)
    {
        WcaLog(LOGMSG_STANDARD, "Scheduling firewall exception (%ls)", pwzCustomActionData);

        if (WCA_TODO_INSTALL == todoSched)
        {
            hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
            ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback");            
            hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
            ExitOnFailure(hr, "failed to schedule firewall install exceptions execution");
        }
        else
        {
            hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
            ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback");    
            hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
            ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution");
        }
    }
    else
    {
        WcaLog(LOGMSG_STANDARD, "No firewall exceptions scheduled");
    }

LExit:
    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzName);
    ReleaseStr(pwzRemoteAddresses);
    ReleaseStr(pwzPort);
    ReleaseStr(pwzProgram);
    ReleaseStr(pwzComponent);
    ReleaseStr(pwzDescription);
    ReleaseStr(pwzFormattedFile);

    return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
}
Example #21
0
static HRESULT StoreACLRollbackInfo(
    __in LPWSTR pwzObject,
    __in LPCWSTR pwzTable
    )
{
    HRESULT hr = S_OK;
    DWORD er = ERROR_SUCCESS;
    PSECURITY_DESCRIPTOR psd = NULL;
    SECURITY_DESCRIPTOR_CONTROL sdc = {0};
    DWORD dwRevision = 0;
    LPWSTR pwzCustomActionData = NULL;
    LPWSTR pwzSecurityInfo = NULL;
    
    Assert(pwzObject && pwzTable);

    SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable));

    if (SE_UNKNOWN_OBJECT_TYPE != objectType)
    {
        er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd);
        if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er))
        {
            // If the file, path or service doesn't exist yet, skip rollback without a message
            hr = HRESULT_FROM_WIN32(er);
            ExitFunction();
        }

        ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "Unable to schedule rollback for object: %ls", pwzObject);

        //Need to see if DACL is protected so getting Descriptor information
        if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
        {
            ExitOnLastError1(hr, "Unable to schedule rollback for object (failed to get security descriptor control): %ls", pwzObject);
        }

        // Convert the security information to a string, and write this to the custom action data
        if (!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL))
        {
            hr = E_UNEXPECTED;
            ExitOnFailure1(hr, "Unable to schedule rollback for object (failed to convert security descriptor to a valid security descriptor string): %ls", pwzObject);
        }

        hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add object data to rollback CustomActionData");

        hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add table name to rollback CustomActionData");

        hr = WcaWriteStringToCaData(pwzSecurityInfo, &pwzCustomActionData);
        ExitOnFailure(hr, "failed to add security info data to rollback CustomActionData");

        // Write a 1 if DACL is protected, 0 otherwise
        if (sdc & SE_DACL_PROTECTED)
        {
            hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to rollbackCustomActionData");
        }
        else
        {
            hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to rollback CustomActionData");
        }

        hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecSecureObjectsRollback"), pwzCustomActionData, COST_SECUREOBJECT);
        ExitOnFailure2(hr, "failed to schedule ExecSecureObjectsRollback for item: %ls of type: %ls", pwzObject, pwzTable);

        ReleaseStr(pwzCustomActionData);
        pwzCustomActionData = NULL;

    }
    else
    {
        MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable);
    }
LExit:
    ReleaseStr(pwzCustomActionData);

    if (psd)
    {
        ::LocalFree(psd);
    }

    return hr;
}
Example #22
0
/********************************************************************
ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings

********************************************************************/
extern "C" UINT __stdcall ConfigureIIs(
    __in MSIHANDLE hInstall
    )
{
    //AssertSz(FALSE, "debug ConfigureIIs here");
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;
    LPWSTR pwzScriptKey = NULL;
    LPWSTR pwzBackupId = NULL;
    LPWSTR pwzCustomActionData = NULL; // CustomActionData for ConfigureIIs custom action

    // initialize
    hr = WcaInitialize(hInstall, "ConfigureIIs");
    ExitOnFailure(hr, "Failed to initialize");

    // check for the prerequsite tables
    if (S_OK != WcaTableExists(L"IIsWebSite") && S_OK != WcaTableExists(L"IIsFilter") && S_OK != WcaTableExists(L"IIsProperty") && 
        S_OK != WcaTableExists(L"IIsWebServiceExtension") && S_OK != WcaTableExists(L"IIsAppPool"))
    {
        WcaLog(LOGMSG_VERBOSE, "skipping IIs CustomAction, no IIsWebSite table, no IIsFilter table, no IIsProperty table, no IIsWebServiceExtension, and no IIsAppPool table");
        ExitFunction1(hr = S_FALSE);
    }

    // Get a CaScript key
    hr = WcaCaScriptCreateKey(&pwzScriptKey);
    ExitOnFailure(hr, "Failed to get encoding key.");

    // Generate a unique string to be used for this product's transaction
    // This prevents a name collision when doing a major upgrade
    hr = WcaGetProperty(L"ProductCode", &pwzBackupId);
    ExitOnFailure(hr, "failed to get ProductCode");

    hr = StrAllocConcat(&pwzBackupId, L"ScaConfigureIIs", 0);
    ExitOnFailure(hr, "failed to concat ScaConfigureIIs");

    // make sure the operations below are wrapped in a "transaction"
    // use IIS7 transaction logic even if using Iis6 compat because Backup/Restore don't work with metabase compatibility
    if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, IIS7CONDITION))
    {
        hr = ScaIIS7ConfigTransaction(pwzBackupId);
        MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS7 transaction");
    }
    else
    {
        hr = ScaMetabaseTransaction(pwzBackupId);
        MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS transaction");
    }

    // Write the CaScript key to the ConfigureIIS custom action data
    hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add encoding key to CustomActionData.");

    // Wrap vcsUserDeferredQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"User"))
    {
        hr = WcaWrapQuery(vcsUserDeferredQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap User query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap User empty query");
    }

    // Wrap vcsWebSvcExtQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebServiceExtension"))
    {
        hr = WcaWrapQuery(vcsWebSvcExtQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4, 1, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension empty query");
    }

    // Wrap vcsAppPoolQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsAppPool"))
    {
        hr = WcaWrapQuery(vcsAppPoolQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn15 | efmcColumn16, 3, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsAppPool query");

        hr = WcaWrapQuery(vcsComponentAttrQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap Component query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsAppPool empty query");
    }

    // Wrap vcsMimeMapQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsMimeMap"))
    {
        hr = WcaWrapQuery(vcsMimeMapQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsMimeMap query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsMimeMap empty query");
    }

    // Wrap vcsHttpHeaderQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsHttpHeader"))
    {
        hr = WcaWrapQuery(vcsHttpHeaderQuery, &pwzCustomActionData, efmcColumn1 | efmcColumn4, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsHttpHeader query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsHttpHeader empty query");
    }

    // Wrap vcsWebErrorQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebError"))
    {
        hr = WcaWrapQuery(vcsWebErrorQuery, &pwzCustomActionData, efmcColumn5 | efmcColumn6, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebError query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebError empty query");
    }

    // Wrap vcsWebDirPropertiesQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebDirProperties"))
    {
        hr = WcaWrapQuery(vcsWebDirPropertiesQuery, &pwzCustomActionData, efmcColumn8 | efmcColumn10 | efmcColumn12 | efmcColumn15, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties empty query");
    }

    // Wrap vcsSslCertificateQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"Certificate") && S_OK == WcaTableExists(L"CertificateHash") && S_OK == WcaTableExists(L"IIsWebSiteCertificates"))
    {
        hr = WcaWrapQuery(vcsSslCertificateQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap SslCertificate query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap SslCertificate empty query");
    }

    // Wrap vcsWebLogQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebLog"))
    {
        hr = WcaWrapQuery(vcsWebLogQuery, &pwzCustomActionData, efmcColumn2, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebLog query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebLog empty query");
    }

    // Wrap vcsWebApplicationQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebApplication"))
    {
        hr = WcaWrapQuery(vcsWebApplicationQuery, &pwzCustomActionData, efmcColumn1, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebApplication query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebApplication empty query");
    }

    // Wrap vcsWebAppExtensionQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebApplicationExtension"))
    {
        hr = WcaWrapQuery(vcsWebAppExtensionQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension empty query");
    }

    // Wrap vcsWebQuery, vcsWebAddressQuery, and vcsWebBaseQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebAddress") && S_OK == WcaTableExists(L"IIsWebSite"))
    {
        hr = WcaWrapQuery(vcsWebQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn12 | efmcColumn13 | efmcColumn14, 2, 6);
        ExitOnFailure(hr, "Failed to wrap IIsWebSite query");

        hr = WcaWrapQuery(vcsWebAddressQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebAddress query");

        hr = WcaWrapQuery(vcsWebBaseQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4 | efmcColumn5 | efmcColumn7, 0xFFFFFFFF, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebBase query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebSite empty query");

        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebAddress empty query");

        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebBase empty query");
    }

    // Wrap vcsWebDirQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebDir"))
    {
        hr = WcaWrapQuery(vcsWebDirQuery, &pwzCustomActionData, efmcColumn4, 3, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsWebDir query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebDir empty query");
    }

    // Wrap vcsVDirQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsWebVirtualDir"))
    {
        hr = WcaWrapQuery(vcsVDirQuery, &pwzCustomActionData, efmcColumn4, 3, 5);
        ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir empty query");
    }

    // Wrap vcsFilterQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsFilter"))
    {
        hr = WcaWrapQuery(vcsFilterQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 3, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsFilter query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsFilter empty query");
    }

    // Wrap vcsPropertyQuery to send to deferred CA
    if (S_OK == WcaTableExists(L"IIsProperty"))
    {
        hr = WcaWrapQuery(vcsPropertyQuery, &pwzCustomActionData, efmcColumn4, 2, 0xFFFFFFFF);
        ExitOnFailure(hr, "Failed to wrap IIsProperty query");
    }
    else
    {
        hr = WcaWrapEmptyQuery(&pwzCustomActionData);
        ExitOnFailure(hr, "Failed to wrap IIsProperty empty query");
    }

    if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, USEIIS7CONDITION))
    {
        // This must remain trace only, CA data may contain password
        WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIIS7Exec will be: %ls", pwzCustomActionData);

        hr = WcaDoDeferredAction(L"ConfigureIIs7Exec", pwzCustomActionData, ConfigureIIsCost);
        ExitOnFailure(hr, "Failed to schedule ConfigureIIs7Exec custom action");

        ReleaseNullStr(pwzCustomActionData);

        // Write the CaScript key to the ConfigureIIS custom action data
        hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add script key to CustomActionData.");

        hr = WcaDoDeferredAction(L"WriteIIS7ConfigChanges", pwzCustomActionData, WriteIIS7ConfigChangesCost);
        ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action");
    }
    else
    {
        // This must remain trace only, CA data may contain password
        WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIISExec will be: %ls", pwzCustomActionData);

        hr = WcaDoDeferredAction(L"ConfigureIIsExec", pwzCustomActionData, ConfigureIIsCost);
        ExitOnFailure(hr, "Failed to schedule ConfigureIISExec custom action");

        ReleaseNullStr(pwzCustomActionData);

        // Write the CaScript key to the ConfigureIIS custom action data
        hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
        ExitOnFailure(hr, "Failed to add script key to CustomActionData.");

        hr = WcaDoDeferredAction(L"WriteMetabaseChanges", pwzCustomActionData, WriteMetabaseChangesCost);
        ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action");
    }

LExit:
    ReleaseStr(pwzScriptKey);
    ReleaseStr(pwzBackupId);
    ReleaseStr(pwzCustomActionData);

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}
Example #23
0
/* ****************************************************************
ScaUserExecute - Schedules user account creation or removal based on
component state.

******************************************************************/
HRESULT ScaUserExecute(
    __in SCA_USER *psuList
    )
{
    HRESULT hr = S_OK;
    DWORD er = 0;
    PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL;

    USER_INFO_0 *pUserInfo = NULL;
    LPWSTR pwzActionData = NULL;
    LPWSTR pwzRollbackData = NULL;

    for (SCA_USER *psu = psuList; psu; psu = psu->psuNext)
    {
        USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE;

        // Always put the User Name and Domain plus Attributes on the front of the CustomAction
        // data.  Sometimes we'll add more data.
        Assert(psu->wzName);
        hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData);
        ExitOnFailure1(hr, "Failed to add user name to custom action data: %ls", psu->wzName);
        hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData);
        ExitOnFailure1(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain);
        hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData);
        ExitOnFailure1(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey);

        // Check to see if the user already exists since we have to be very careful when adding
        // and removing users.  Note: MSDN says that it is safe to call these APIs from any
        // user, so we should be safe calling it during immediate mode.
        er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast<LPVOID*>(&pUserInfo));
        hr = HRESULT_FROM_WIN32(er);
        ExitOnFailure1(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName);

        LPCWSTR wzDomain = psu->wzDomain;
        if (wzDomain && *wzDomain)
        {
            er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo);
            if (HRESULT_FROM_WIN32(er) == RPC_S_SERVER_UNAVAILABLE)
            {
                // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag
                er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo);
            }
            if (ERROR_SUCCESS == er)
            {
                wzDomain = pDomainControllerInfo->DomainControllerName + 2;  //Add 2 so that we don't get the \\ prefix
            }
        }

        er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast<LPBYTE*>(pUserInfo));
        if (NERR_Success == er)
        {
            ueUserExists = USER_EXISTS_YES;
        }
        else if (NERR_UserNotFound == er)
        {
            ueUserExists = USER_EXISTS_NO;
        }
        else
        {
            ueUserExists = USER_EXISTS_INDETERMINATE;
            hr = HRESULT_FROM_WIN32(er);
            WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr);
        }

        if (WcaIsInstalling(psu->isInstalled, psu->isAction))
        {
            // If the user exists, check to see if we are supposed to fail if user the exists before
            // the install.
            if (USER_EXISTS_YES == ueUserExists)
            {
                // Reinstalls will always fail if we don't remove the check for "fail if exists".
                if (WcaIsReInstalling(psu->isInstalled, psu->isAction))
                {
                    psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS;
                }

                if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes)))
                {
                    hr = HRESULT_FROM_WIN32(NERR_UserExists);
                    MessageExitOnFailure1(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName);
                }
            }

            // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user
            if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER))
            {
                INT iRollbackUserAttributes = psu->iAttributes;

                // If the user already exists, ensure this is accounted for in rollback
                if (USER_EXISTS_YES == ueUserExists)
                {
                    iRollbackUserAttributes |= SCAU_DONT_CREATE_USER;
                }
                else
                {
                    iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER;
                }

                hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData);
                ExitOnFailure1(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName);
                hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData);
                ExitOnFailure1(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain);
                hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData);
                ExitOnFailure1(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey);

                // If the user already exists, add relevant group information to rollback data
                if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists)
                {
                    hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData);
                    ExitOnFailure(hr, "failed to add group information to rollback custom action data");
                }

                hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE);
                ExitOnFailure(hr, "failed to schedule CreateUserRollback");
            }

            //
            // Schedule the creation now.
            //
            hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData);
            ExitOnFailure1(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey);

            // Add user's group information to custom action data
            hr = WriteGroupInfo(psu->psgGroups, &pwzActionData);
            ExitOnFailure(hr, "failed to add group information to custom action data");

            hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD);
            ExitOnFailure(hr, "failed to schedule CreateUser");
        }
        else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL))
        {
            // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted
            hr = WriteGroupInfo(psu->psgGroups, &pwzActionData);
            ExitOnFailure(hr, "failed to add group information to custom action data");

            //
            // Schedule the removal because the user exists and we don't have any flags set
            // that say, don't remove the user on uninstall.
            //
            // Note: We can't rollback the removal of a user which is why RemoveUser is a commit 
            // CustomAction.
            hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE);
            ExitOnFailure(hr, "failed to schedule RemoveUser");
        }

        ReleaseNullStr(pwzActionData);
        ReleaseNullStr(pwzRollbackData);
        if (pUserInfo)
        {
            ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo));
            pUserInfo = NULL;
        }
        if (pDomainControllerInfo)
        {
            ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
            pDomainControllerInfo = NULL;
        }
    }

LExit:
    ReleaseStr(pwzActionData);
    ReleaseStr(pwzRollbackData);
    if (pUserInfo)
    {
        ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo));
    }
    if (pDomainControllerInfo)
    {
        ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo));
    }

    return hr;
}
Example #24
0
static HRESULT ExecuteStrings(
    __in SCA_DB* psdList,
    __in SCA_SQLSTR* psssList,
    __in BOOL fInstall
    )
{
    HRESULT hr = S_FALSE; // assume nothing will be done

    int iRollback = -1;
    int iOldRollback = iRollback;

    LPCWSTR wzOldDb = NULL;
    UINT uiCost = 0;
    WCHAR* pwzCustomActionData = NULL;
    WCHAR wzNumber[64];

    // loop through all sql strings
    for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext)
    {
        // if installing this component
        if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
            (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) ||
            (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction)))
        {
            // determine if this is a rollback scheduling or normal deferred scheduling
            if (psss->iAttributes & SCASQL_ROLLBACK)
            {
                iRollback = 1;
            }
            else
            {
                iRollback = 0;
            }

            // if we need to create a connection to a new server\database
            if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback)
            {
                const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList);
                if (!psd)
                {
                    ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb);
                }

                if (-1 == iOldRollback)
                {
                    iOldRollback = iRollback;
                }
                Assert(0 == iOldRollback || 1 == iOldRollback);

                // if there was custom action data before, schedule the action to write it
                if (pwzCustomActionData && *pwzCustomActionData)
                {
                    Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);

                    hr = WcaDoDeferredAction(1 == iOldRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost);
                    ExitOnFailure1(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback);
                    iOldRollback = iRollback;

                    *pwzCustomActionData = L'\0';
                    uiCost = 0;
                }

                Assert(!pwzCustomActionData  || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost);

                hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey);

                hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey);

                hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey);

                hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey);

                hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes);
                ExitOnFailure(hr, "Failed to format attributes integer value to string");
                hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey);

                hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth);
                ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string");
                hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey);

                hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey);

                hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData);
                ExitOnFailure1(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey);

                uiCost += COST_SQL_CONNECTDB;

                wzOldDb = psss->wzSqlDb;
            }

            WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql);

            hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData);
            ExitOnFailure1(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey);

            hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData);
            ExitOnFailure1(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey);

            hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData);
            ExitOnFailure1(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey);
            uiCost += COST_SQL_STRING;
        }
    }

    if (pwzCustomActionData && *pwzCustomActionData)
    {
        Assert(pwzCustomActionData && *pwzCustomActionData && uiCost);
        hr = WcaDoDeferredAction(1 == iRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost);
        ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action");

        *pwzCustomActionData = L'\0';
        uiCost = 0;
    }

LExit:
    ReleaseStr(pwzCustomActionData);

    return hr;
}
Example #25
0
/******************************************************************
SchedServiceConfig - entry point for SchedServiceConfig Custom Action

called as Type 1 CustomAction (binary DLL) from Windows Installer 
in InstallExecuteSequence before CaExecServiceConfig
********************************************************************/
extern "C" UINT __stdcall SchedServiceConfig(
    __in MSIHANDLE hInstall
    )
{
    //AssertSz(FALSE, "debug SchedServiceConfig");
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    LPWSTR pwzScriptKey = NULL;
    LPWSTR pwzCustomActionData = NULL;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;
    LPWSTR pwzData = NULL;
    int iData = 0;
    DWORD cServices = 0;

    // initialize
    hr = WcaInitialize(hInstall, "SchedServiceConfig");
    ExitOnFailure(hr, "Failed to initialize.");

    // Get the script key for this CustomAction and put it on the front of the
    // CustomActionData of the install action.
    hr = WcaCaScriptCreateKey(&pwzScriptKey);
    ExitOnFailure(hr, "Failed to get encoding key.");

    hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
    ExitOnFailure(hr, "Failed to add encoding key to CustomActionData.");

    // Loop through all the services to be configured.
    hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView);
    ExitOnFailure(hr, "Failed to open view on ServiceConfig table.");

    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
        INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;

        // Get component name to check if we are installing it. If so
        // then add the table data to the CustomActionData, otherwise
        // skip it.
        hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData);
        ExitOnFailure(hr, "Failed to get component name");

        hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
        ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData);

        if (WcaIsInstalling(isInstalled, isAction))
        {
            // Add the data to the CustomActionData (for install).
            hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
            ExitOnFailure(hr, "Failed to get name of service.");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "Failed to add name to CustomActionData.");

            hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData);
            ExitOnFailure(hr, "Failed to get ServiceConfig.NewService.");
            hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData);
            ExitOnFailure(hr, "Failed to add NewService data to CustomActionData");

            hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData);
            ExitOnFailure(hr, "failed to get first failure action type");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData);
            ExitOnFailure(hr, "failed to get second failure action type");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData);
            ExitOnFailure(hr, "failed to get third failure action type");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData);
            if (S_FALSE == hr) // deal w/ possible null value
            {
                iData = 0;
            }
            ExitOnFailure(hr, "failed to get reset period in days between service restart attempts.");
            hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData);
            if (S_FALSE == hr) // deal w/ possible null value
            {
                iData = 0;
            }
            ExitOnFailure(hr, "failed to get server restart delay value.");
            hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordFormattedString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly
            ExitOnFailure(hr, "failed to get command line to run on service failure.");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly
            ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure.");
            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to add data to CustomActionData");

            ++cServices;
        }
    }

    // if we looped through all records all is well
    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "failed while looping through all objects to secure");

    // setup CustomActionData and add to progress bar for download
    if (0 < cServices)
    {
        hr = WcaDoDeferredAction(L"RollbackServiceConfig", pwzScriptKey, cServices * COST_SERVICECONFIG);
        ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action");

        hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG);
        ExitOnFailure(hr, "failed to schedule ExecServiceConfig action");
    }

LExit:
    ReleaseStr(pwzData);
    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzScriptKey);

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}
Example #26
0
/******************************************************************
 WixSchedInternetShortcuts - entry point

********************************************************************/
extern "C" UINT __stdcall WixSchedInternetShortcuts(
    __in MSIHANDLE hInstall
)
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    UINT uiCost = 0;

    PMSIHANDLE hView = NULL;
    PMSIHANDLE hRec = NULL;

    MSIHANDLE hCreateFolderTable = NULL;
    MSIHANDLE hCreateFolderColumns = NULL;

    LPWSTR pwzCustomActionData = NULL;
    LPWSTR pwzComponent = NULL;
    LPWSTR pwzDirectory = NULL;
    LPWSTR pwzFilename = NULL;
    LPWSTR pwzTarget = NULL;
    LPWSTR pwzShortcutPath = NULL;
    int iAttr = 0;
    LPWSTR pwzIconFile = NULL;
    int iIconIndex = 0;
    IUniformResourceLocatorW* piURL = NULL;
    IShellLinkW* piShellLink = NULL;
    BOOL fInitializedCom = FALSE;

    hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts");
    ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts.");

    // anything to do?
    if (S_OK != WcaTableExists(L"WixInternetShortcut"))
    {
        WcaLog(LOGMSG_STANDARD, "WixInternetShortcut table doesn't exist, so there are no Internet shortcuts to process");
        goto LExit;
    }

    // check to see if we can create a shortcut - Server Core and others may not have a shell registered.  
    hr = ::CoInitialize(NULL);
    ExitOnFailure(hr, "failed to initialize COM");
    fInitializedCom = TRUE;

    hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
    if (S_OK != hr)
    {
        WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation");
        ExitFunction1(hr = S_OK);
    }

    hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink);
    if (S_OK != hr)
    {
        WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation");
        ExitFunction1(hr = S_OK);
    }

    // query and loop through all the shortcuts
    hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView);
    ExitOnFailure(hr, "failed to open view on WixInternetShortcut table");

    while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
    {
        // read column values
        hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent);
        ExitOnFailure(hr, "failed to get shortcut component");
        hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory);
        ExitOnFailure(hr, "failed to get shortcut directory");
        hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename);
        ExitOnFailure(hr, "failed to get shortcut filename");
        hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget);
        ExitOnFailure(hr, "failed to get shortcut target");
        hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr);
        ExitOnFailure(hr, "failed to get shortcut attributes");
        hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile);
        ExitOnFailure(hr, "failed to get shortcut icon file");
        hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex);
        ExitOnFailure(hr, "failed to get shortcut icon index");

        // skip processing this WixInternetShortcut row if the component isn't being configured
        WCA_TODO todo = WcaGetComponentToDo(pwzComponent);
        if (WCA_TODO_UNKNOWN == todo)
        {
            WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent);
            continue;
        }

        // we need to create the directory where the shortcut is supposed to live; rather
        // than doing so in our deferred custom action, use the CreateFolder table to have MSI 
        // make (and remove) them on our behalf (including the correct cleanup of parent directories).
        MSIDBERROR dbError = MSIDBERROR_NOERROR;
        WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent);
        hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent);
        if (MSIDBERROR_DUPLICATEKEY == dbError)
        {
            WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory);
            hr = S_OK;
        }
        ExitOnFailure(hr, "Couldn't add temporary CreateFolder row");

        // only if we're installing/reinstalling do we need to schedule the deferred CA
        // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows)
        if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo)
        {
            // turn the Directory_ id into a path
            hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath);
            ExitOnFailure(hr, "failed to allocate string for shortcut directory");

            // append the shortcut filename
            hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0);
            ExitOnFailure(hr, "failed to allocate string for shortcut filename");

            // write the shortcut path and target to custom action data for deferred CAs
            hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write shortcut path to custom action data");
            hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write shortcut target to custom action data");
            hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write shortcut attributes to custom action data");
            hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write icon file to custom action data");
            hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData);
            ExitOnFailure(hr, "failed to write icon index to custom action data");

            uiCost += COST_INTERNETSHORTCUT;
        }
    }

    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure occured while processing WixInternetShortcut table");

    // if we have any shortcuts to install
    if (pwzCustomActionData && *pwzCustomActionData)
    {
        // add cost to progress bar
        hr = WcaProgressMessage(uiCost, TRUE);
        ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts");

        // provide custom action data to deferred and rollback CAs
        hr = WcaSetProperty(PLATFORM_DECORATION(L"WixRollbackInternetShortcuts"), pwzCustomActionData);
        ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data");
        hr = WcaSetProperty(PLATFORM_DECORATION(L"WixCreateInternetShortcuts"), pwzCustomActionData);
        ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data");
    }

LExit:
    if (hCreateFolderTable)
    {
        ::MsiCloseHandle(hCreateFolderTable);
    }

    if (hCreateFolderColumns)
    {
        ::MsiCloseHandle(hCreateFolderColumns);
    }

    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzComponent);
    ReleaseStr(pwzDirectory);
    ReleaseStr(pwzFilename);
    ReleaseStr(pwzTarget);
    ReleaseStr(pwzShortcutPath);
    ReleaseObject(piShellLink);
    ReleaseObject(piURL);

    if (fInitializedCom)
    {
        ::CoUninitialize();
    }

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}
Example #27
0
/********************************************************************
 ConfigureComPlusInstall - CUSTOM ACTION ENTRY POINT for installing COM+ components

********************************************************************/
extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall)
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    BOOL fInitializedCom = FALSE;

    ICOMAdminCatalog* piCatalog = NULL;

    CPI_PARTITION_LIST partList;
    CPI_PARTITION_ROLE_LIST partRoleList;
    CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList;
    CPI_PARTITION_USER_LIST partUsrList;
    CPI_APPLICATION_LIST appList;
    CPI_APPLICATION_ROLE_LIST appRoleList;
    CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList;
    CPI_ASSEMBLY_LIST asmList;
    CPI_SUBSCRIPTION_LIST subList;

    LPWSTR pwzRollbackFileName = NULL;
    LPWSTR pwzActionData = NULL;
    LPWSTR pwzRollbackActionData = NULL;
    LPWSTR pwzCommitActionData = NULL;

    int iVersionNT = 0;
    int iProgress = 0;
    int iCommitProgress = 0;

    ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST));
    ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST));
    ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST));
    ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST));
    ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST));
    ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST));
    ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST));
    ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST));
    ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST));

    // initialize
    hr = WcaInitialize(hInstall, "ConfigureComPlusInstall");
    ExitOnFailure(hr, "Failed to initialize");

    hr = ::CoInitialize(NULL);
    ExitOnFailure(hr, "Failed to initialize COM");
    fInitializedCom = TRUE;

    CpiInitialize();

    // check for the prerequsite tables
    if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly))
    {
        WcaLog(LOGMSG_VERBOSE, "skipping install COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present");
        ExitFunction1(hr = S_FALSE);
    }

    // make sure we can access the COM+ admin catalog
    do {
        hr = CpiGetAdminCatalog(&piCatalog);
        if (FAILED(hr))
        {
            WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog");
            er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
            switch (er)
            {
            case IDABORT:
                ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback
            case IDRETRY:
                hr = S_FALSE;
                break;
            case IDIGNORE:
            default:
                ExitFunction1(hr = S_OK); // pretend everything is okay and bail
            }
        }
    } while (S_FALSE == hr);

    // get NT version
    hr = WcaGetIntProperty(L"VersionNT", &iVersionNT);
    ExitOnFailure(hr, "Failed to get VersionNT property");

    // read elements
    if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition))
    {
        hr = CpiPartitionsRead(&partList);
        MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table");
    }

    if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole))
    {
        hr = CpiPartitionRolesRead(&partList, &partRoleList);
        MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table");
    }

    if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole)))
    {
        hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList);
        MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table");
    }

    if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser))
    {
        hr = CpiPartitionUsersRead(&partList, &partUsrList);
        MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table");
    }

    if (CpiTableExists(cptComPlusApplication))
    {
        hr = CpiApplicationsRead(&partList, &appList);
        MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table");
    }

    if (CpiTableExists(cptComPlusApplicationRole))
    {
        hr = CpiApplicationRolesRead(&appList, &appRoleList);
        MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table");
    }

    if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole))
    {
        hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList);
        MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table");
    }

    if (CpiTableExists(cptComPlusAssembly))
    {
        hr = CpiAssembliesRead(&appList, &appRoleList, &asmList);
        MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table");
    }

    if (CpiTableExists(cptComPlusSubscription))
    {
        hr = CpiSubscriptionsRead(&asmList, &subList);
        MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table");
    }

    // verify elements
    hr = CpiPartitionsVerifyInstall(&partList);
    ExitOnFailure(hr, "Failed to verify partitions");

    hr = CpiApplicationsVerifyInstall(&appList);
    ExitOnFailure(hr, "Failed to verify applications");

    hr = CpiApplicationRolesVerifyInstall(&appRoleList);
    ExitOnFailure(hr, "Failed to verify application roles");

    hr = CpiAssembliesVerifyInstall(&asmList);
    ExitOnFailure(hr, "Failed to verify assemblies");

    if (subList.iInstallCount)
    {
        hr = CpiSubscriptionsVerifyInstall(&subList);
        ExitOnFailure(hr, "Failed to verify subscriptions");
    }

    // schedule
    if (partList.iInstallCount || appList.iInstallCount || usrInAppRoleList.iInstallCount ||
        appRoleList.iInstallCount || asmList.iInstallCount || asmList.iRoleInstallCount || subList.iInstallCount)
    {
        // create rollback file name
        hr = CpiGetTempFileName(&pwzRollbackFileName);
        ExitOnFailure(hr, "Failed to get rollback file name");

        // schedule rollback prepare custom action
        hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0);
        ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare");

        // schedule prepare custom action
        hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0);
        ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare");

        // schedule rollback custom action
        hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData);
        ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data");

        hr = CpiSubscriptionsInstall(&subList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install subscriptions");
        hr = CpiRoleAssignmentsInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiAssembliesInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install users in application roles");
        hr = CpiApplicationRolesInstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install application roles");
        hr = CpiApplicationsInstall(&appList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install applications");
        hr = CpiPartitionUsersInstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install partition users");
        hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install users in partition roles");
        hr = CpiPartitionsInstall(&partList, rmRollback, &pwzRollbackActionData, NULL);
        ExitOnFailure(hr, "Failed to install partitions");

        hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLEXECUTE, pwzRollbackActionData, 0);
        ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallExecute");

        // schedule install custom action
        hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData);
        ExitOnFailure(hr, "Failed to add rollback file name to custom action data");

        hr = CpiPartitionsInstall(&partList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install partitions");
        hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install users in partition roles");
        hr = CpiPartitionUsersInstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install partition users");
        hr = CpiApplicationsInstall(&appList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install applications");
        hr = CpiApplicationRolesInstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install application roles");
        hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install users in application roles");
        hr = CpiAssembliesInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiRoleAssignmentsInstall(&asmList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiSubscriptionsInstall(&subList, rmDeferred, &pwzActionData, &iProgress);
        ExitOnFailure(hr, "Failed to install subscriptions");

        hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTE, pwzActionData, iProgress);
        ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecute");

        // schedule install commit custom action
        hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzCommitActionData);
        ExitOnFailure(hr, "Failed to add rollback file name to commit custom action data");

        hr = CpiAssembliesInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiRoleAssignmentsInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress);
        ExitOnFailure(hr, "Failed to install assemblies");
        hr = CpiSubscriptionsInstall(&subList, rmCommit, &pwzCommitActionData, &iCommitProgress);
        ExitOnFailure(hr, "Failed to install subscriptions");

        hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTECOMMIT, pwzCommitActionData, iCommitProgress);
        ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecuteCommit");

        // schedule commit custom action
        hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0);
        ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit");
    }

    hr = S_OK;

LExit:
    // clean up
    ReleaseObject(piCatalog);

    ReleaseStr(pwzRollbackFileName);
    ReleaseStr(pwzActionData);
    ReleaseStr(pwzRollbackActionData);
    ReleaseStr(pwzCommitActionData);

    CpiPartitionListFree(&partList);
    CpiPartitionRoleListFree(&partRoleList);
    CpiUserInPartitionRoleListFree(&usrInPartRoleList);
    CpiPartitionUserListFree(&partUsrList);
    CpiApplicationListFree(&appList);
    CpiApplicationRoleListFree(&appRoleList);
    CpiUserInApplicationRoleListFree(&usrInAppRoleList);
    CpiAssemblyListFree(&asmList);
    CpiSubscriptionListFree(&subList);

    // unitialize
    CpiFinalize();

    if (fInitializedCom)
        ::CoUninitialize();

    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}