Example #1
0
static HRESULT ParseWxlControls(
    __in IXMLDOMElement* pElement,
    __in WIX_LOCALIZATION* pWixLoc
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNode* pixn = NULL;
    IXMLDOMNodeList* pixnl = NULL;
    DWORD dwIdx = 0;

    hr = XmlSelectNodes(pElement, L"UI|Control", &pixnl);
    ExitOnLastError(hr, "Failed to get UI child nodes of Wxl File.");

    hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocControls));
    ExitOnLastError(hr, "Failed to get number of UI child nodes in Wxl File.");

    if (0 < pWixLoc->cLocControls)
    {
        pWixLoc->rgLocControls = static_cast<LOC_CONTROL*>(MemAlloc(sizeof(LOC_CONTROL) * pWixLoc->cLocControls, TRUE));
        ExitOnNull(pWixLoc->rgLocControls, hr, E_OUTOFMEMORY, "Failed to allocate memory for localized controls.");

        while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
        {
            hr = ParseWxlControl(pixn, dwIdx, pWixLoc);
            ExitOnFailure(hr, "Failed to parse localized control.");

            ++dwIdx;
            ReleaseNullObject(pixn);
        }

        hr = S_OK;
        ExitOnFailure(hr, "Failed to enumerate all localized controls.");
    }

LExit:
    if (FAILED(hr) && pWixLoc->rgLocControls)
    {
        for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx)
        {
            ReleaseStr(pWixLoc->rgLocControls[idx].wzControl);
            ReleaseStr(pWixLoc->rgLocControls[idx].wzText);
        }

        ReleaseMem(pWixLoc->rgLocControls);
    }

    ReleaseObject(pixn);
    ReleaseObject(pixnl);

    return hr;
}
Example #2
0
HRESULT CpiSubscriptionsVerifyUninstall(
    CPI_SUBSCRIPTION_LIST* pList
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    ICatalogObject* piSubsObj = NULL;

    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
    {
        // subscriptions that are being installed
        if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
            continue;

        // find subscriptions with conflicting name
        hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj);
        ExitOnFailure(hr, "Failed to find collection object for subscription");

        // if the subscription was found
        if (S_OK == hr)
        {
            // if we don't have an id, copy id from object
            if (!*pItm->wzID)
            {
                hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
                ExitOnFailure(hr, "Failed to get id");
            }
        }

        // if the subscription was not found
        else
        {
            pItm->fObjectNotFound = TRUE;
            pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall
        }

        // clean up
        ReleaseNullObject(piSubsObj);
    }

    hr = S_OK;

LExit:
    // clean up
    ReleaseObject(piSubsObj);

    return hr;
}
Example #3
0
static HRESULT ParsePackagesFromXml(
    __in BAL_INFO_PACKAGES* pPackages,
    __in IXMLDOMDocument* pixdManifest
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pNodeList = NULL;
    IXMLDOMNode* pNode = NULL;
    BAL_INFO_PACKAGE* prgPackages = NULL;
    DWORD cPackages = 0;
    LPWSTR sczType = NULL;

    hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPackageProperties", &pNodeList);
    ExitOnFailure(hr, "Failed to select all packages.");

    hr = pNodeList->get_length(reinterpret_cast<long*>(&cPackages));
    ExitOnFailure(hr, "Failed to get the package count.");

    prgPackages = static_cast<BAL_INFO_PACKAGE*>(MemAlloc(sizeof(BAL_INFO_PACKAGE) * cPackages, TRUE));
    ExitOnNull(prgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for packages.");

    DWORD iPackage = 0;
    while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
    {
        hr = XmlGetAttributeEx(pNode, L"Package", &prgPackages[iPackage].sczId);
        ExitOnFailure(hr, "Failed to get package identifier for package.");

        hr = XmlGetAttributeEx(pNode, L"DisplayName", &prgPackages[iPackage].sczDisplayName);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get description for package.");
        }

        hr = XmlGetAttributeEx(pNode, L"Description", &prgPackages[iPackage].sczDescription);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get description for package.");
        }

        hr = XmlGetAttributeEx(pNode, L"PackageType", &sczType);
        ExitOnFailure(hr, "Failed to get description for package.");

        if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, sczType, -1))
        {
            prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msi", -1, sczType, -1))
        {
            prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSI;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msp", -1, sczType, -1))
        {
            prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSP;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msu", -1, sczType, -1))
        {
            prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSU;
        }

        hr = XmlGetYesNoAttribute(pNode, L"Permanent", &prgPackages[iPackage].fPermanent);
        ExitOnFailure(hr, "Failed to get permanent setting for package.");

        hr = XmlGetYesNoAttribute(pNode, L"Vital", &prgPackages[iPackage].fVital);
        ExitOnFailure(hr, "Failed to get vital setting for package.");

        hr = XmlGetYesNoAttribute(pNode, L"DisplayInternalUI", &prgPackages[iPackage].fDisplayInternalUI);
        ExitOnFailure(hr, "Failed to get DisplayInternalUI setting for package.");

        ++iPackage;
        ReleaseNullObject(pNode);
    }
    ExitOnFailure(hr, "Failed to parse all package property elements.");

    if (S_FALSE == hr)
    {
        hr = S_OK;
    }

    pPackages->cPackages = cPackages;
    pPackages->rgPackages = prgPackages;
    prgPackages = NULL;

LExit:
    ReleaseStr(sczType);
    ReleaseMem(prgPackages);
    ReleaseObject(pNode);
    ReleaseObject(pNodeList);

    return hr;
}
Example #4
0
DAPI_(HRESULT) BalConditionsParseFromXml(
    __in BAL_CONDITIONS* pConditions,
    __in IXMLDOMDocument* pixdManifest,
    __in_opt WIX_LOCALIZATION* pWixLoc
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pNodeList = NULL;
    IXMLDOMNode* pNode = NULL;
    BAL_CONDITION* prgConditions = NULL;
    DWORD cConditions = 0;

    hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixBalCondition", &pNodeList);
    ExitOnFailure(hr, "Failed to select all conditions.");

    hr = pNodeList->get_length(reinterpret_cast<long*>(&cConditions));
    ExitOnFailure(hr, "Failed to get the condition count.");

    if (!cConditions)
    {
        ExitFunction();
    }

    prgConditions = static_cast<BAL_CONDITION*>(MemAlloc(sizeof(BAL_CONDITION) * cConditions, TRUE));
    ExitOnNull(prgConditions, hr, E_OUTOFMEMORY, "Failed to allocate memory for conditions.");

    DWORD iCondition = 0;
    while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
    {
        hr = XmlGetAttributeEx(pNode, L"Condition", &prgConditions[iCondition].sczCondition);
        ExitOnFailure(hr, "Failed to get condition for condition.");

        hr = XmlGetAttributeEx(pNode, L"Message", &prgConditions[iCondition].sczMessage);
        ExitOnFailure(hr, "Failed to get message for condition.");

        if (pWixLoc && prgConditions[iCondition].sczMessage && *prgConditions[iCondition].sczMessage)
        {
            hr = LocLocalizeString(pWixLoc, &prgConditions[iCondition].sczMessage);
            ExitOnFailure(hr, "Failed to localize condition message.");
        }

        ++iCondition;
        ReleaseNullObject(pNode);
    }
    ExitOnFailure(hr, "Failed to parse all condition elements.");

    if (S_FALSE == hr)
    {
        hr = S_OK;
    }

    pConditions->cConditions = cConditions;
    pConditions->rgConditions = prgConditions;
    prgConditions = NULL;

LExit:
    ReleaseMem(prgConditions);
    ReleaseObject(pNode);
    ReleaseObject(pNodeList);

    return hr;
}
Example #5
0
HRESULT CpiApplicationRolesVerifyInstall(
    CPI_APPLICATION_ROLE_LIST* pList
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    ICatalogObject* piRoleObj = NULL;

    for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
    {
        // referenced locaters or roles that are being installed
        if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
            continue;

        // if the role is referensed and is not a locater, it must be installed
        if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
            MessageExitOnFailure1(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);

        // role is a locater
        if (!pItm->fHasComponent)
        {
            // get collection object for role
            hr = FindObjectForApplicationRole(pItm, &piRoleObj);
            ExitOnFailure(hr, "Failed to find collection object for role");

            // if the role was not found
            if (S_FALSE == hr)
                MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey);
        }

        // role is supposed to be created
        else if (!CpiIsInstalled(pItm->isInstalled))
        {
            do {
                // find roles with conflicting name or id
                hr = FindObjectForApplicationRole(pItm, NULL);
                ExitOnFailure(hr, "Failed to find collection object for role");

                if (S_OK == hr)
                {
                    er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
                    switch (er)
                    {
                    case IDABORT:
                        ExitOnFailure1(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey);
                        break;
                    case IDRETRY:
                        break;
                    case IDIGNORE:
                    default:
                        hr = S_FALSE; // indicate that this is not a conflict
                    }
                }
            } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts
        }

        // clean up
        ReleaseNullObject(piRoleObj);
    }

    hr = S_OK;

LExit:
    // clean up
    ReleaseObject(piRoleObj);

    return hr;
}
Example #6
0
HRESULT CpiFindCollectionObject(
    ICatalogCollection* piColl,
    LPCWSTR pwzID,
    LPCWSTR pwzName,
    ICatalogObject** ppiObj
    )
{
    HRESULT hr = S_OK;

    IDispatch* piDisp = NULL;
    ICatalogObject* piObj = NULL;

    VARIANT vtVal;
    ::VariantInit(&vtVal);

    long lCnt;
    hr = piColl->get_Count(&lCnt);
    ExitOnFailure(hr, "Failed to get to number of items in collection");

    for (long i = 0; i < lCnt; i++)
    {
        // get ICatalogObject interface
        hr = piColl->get_Item(i, &piDisp);
        ExitOnFailure(hr, "Failed to get object from collection");

        hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
        ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");

        // compare id
        if (pwzID && *pwzID)
        {
            hr = piObj->get_Key(&vtVal);
            ExitOnFailure(hr, "Failed to get key");

            hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
            ExitOnFailure(hr, "Failed to change variant type");

            if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
            {
                if (ppiObj)
                {
                    *ppiObj = piObj;
                    piObj = NULL;
                }
                ExitFunction1(hr = S_OK);
            }

            ::VariantClear(&vtVal);
        }

        // compare name
        if (pwzName && *pwzName)
        {
            hr = piObj->get_Name(&vtVal);
            ExitOnFailure(hr, "Failed to get name");

            hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
            ExitOnFailure(hr, "Failed to change variant type");

            if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
            {
                if (ppiObj)
                {
                    *ppiObj = piObj;
                    piObj = NULL;
                }
                ExitFunction1(hr = S_OK);
            }

            ::VariantClear(&vtVal);
        }

        // release interface pointers
        ReleaseNullObject(piDisp);
        ReleaseNullObject(piObj);
    }

    hr = S_FALSE;

LExit:
    // clean up
    ReleaseObject(piDisp);
    ReleaseObject(piObj);

    ::VariantClear(&vtVal);

    return hr;
}
Example #7
0
HRESULT CpiPartitionsVerifyInstall(
    CPI_PARTITION_LIST* pList
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    ICatalogCollection* piPartColl = NULL;
    ICatalogObject* piPartObj = NULL;

    for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
    {
        // referenced locaters or partitions that are being installed
        if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)))
            continue;

        // if the partition is referensed and is not a locater, it must be installed
        if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction))
            MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey);

        // get partitions collection
        if (!piPartColl)
        {
            hr = CpiGetPartitionsCollection(&piPartColl);
            ExitOnFailure(hr, "Failed to get partitions collection");
        }

        // partition is supposed to exist
        if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled))
        {
            // get collection object for partition
            hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj);
            ExitOnFailure(hr, "Failed to find collection object for partition");

            // if the partition was found
            if (S_OK == hr)
            {
                // if we don't have an id, copy id from object
                if (!*pItm->wzID)
                {
                    hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
                    ExitOnFailure(hr, "Failed to get id");
                }
            }

            // if the partition was not found
            else
            {
                // if the application is a locater, this is an error
                if (!pItm->fHasComponent)
                    MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey);

                // create a new id if one is missing
                if (!*pItm->wzID)
                {
                    hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
                    ExitOnFailure(hr, "Failed to create id");
                }
            }
        }

        // partition is supposed to be created
        else
        {
            // check for conflicts
            do {
                if (*pItm->wzID)
                {
                    // find partitions with conflicting id
                    hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj);
                    ExitOnFailure(hr, "Failed to find collection object for partition");

                    if (S_FALSE == hr)
                    {
                        // find partitions with conflicting name
                        hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
                        ExitOnFailure(hr, "Failed to find collection object for partition");

                        if (S_OK == hr)
                            // "A partition with a conflictiong name exists. retry cancel"
                            er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
                        else
                            break; // no conflicting entry found, break loop
                    }
                    else
                        // "A partition with a conflicting id exists. abort retry ignore"
                        er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
                }
                else
                {
                    // find partitions with conflicting name
                    hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj);
                    ExitOnFailure(hr, "Failed to find collection object for partition");

                    if (S_OK == hr)
                        // "A partition with a conflictiong name exists. abort retry ignore"
                        er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
                    else
                        break; // no conflicting entry found, break loop
                }

                switch (er)
                {
                case IDCANCEL:
                case IDABORT:
                    ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey);
                    break;
                case IDRETRY:
                    break;
                case IDIGNORE:
                default:
                    // if we don't have an id, copy id from object
                    if (!*pItm->wzID)
                    {
                        hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID));
                        ExitOnFailure(hr, "Failed to get id");
                    }
                    hr = S_FALSE; // indicate that this is not a conflict
                }
            } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts

            // create a new id if one is missing
            if (!*pItm->wzID)
            {
                hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
                ExitOnFailure(hr, "Failed to create id");
            }
        }

        // clean up
        ReleaseNullObject(piPartObj);
    }

    hr = S_OK;

LExit:
    // clean up
    ReleaseObject(piPartColl);
    ReleaseObject(piPartObj);

    return hr;
}
Example #8
0
static HRESULT FindUserCollectionObjectIndex(
	ICatalogCollection* piColl,
	PSID pSid,
	int* pi
	)
{
	HRESULT hr = S_OK;
	UINT er = ERROR_SUCCESS;
	NTSTATUS st = 0;

	long i = 0;
	long lCollCnt = 0;

	LSA_OBJECT_ATTRIBUTES loaAttributes;
	LSA_HANDLE lsahPolicy = NULL;
	PLSA_UNICODE_STRING plusNames = NULL;
	PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
	PLSA_TRANSLATED_SID pltsSids = NULL;

	IDispatch* piDisp = NULL;
	ICatalogObject* piObj = NULL;
	VARIANT vtVal;

	PSID pTmpSid = NULL;

	PLSA_TRANSLATED_SID pltsSid;

	::VariantInit(&vtVal);
	::ZeroMemory(&loaAttributes, sizeof(loaAttributes));

	// open policy handle
	st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
	er = ::LsaNtStatusToWinError(st);
	ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");

	// get number of elements in collection
	hr = piColl->get_Count(&lCollCnt);
	ExitOnFailure(hr, "Failed to get to number of objects in collection");

	if (0 == lCollCnt)
		ExitFunction1(hr = S_FALSE); // not found

	// allocate name buffer
	plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt);
	ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer");

	// get accounts in collection
	for (i = 0; i < lCollCnt; i++)
	{
		// get ICatalogObject interface
		hr = piColl->get_Item(i, &piDisp);
		ExitOnFailure(hr, "Failed to get object from collection");

		hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
		ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");

		// get value
		hr = piObj->get_Key(&vtVal);
		ExitOnFailure(hr, "Failed to get key");

		hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
		ExitOnFailure(hr, "Failed to change variant type");

		// copy account name string
		hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal));
		ExitOnFailure(hr, "Failed to initialize account name string");

		// clean up
		ReleaseNullObject(piDisp);
		ReleaseNullObject(piObj);
		::VariantClear(&vtVal);
	}

	// lookup names
	st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids);
	er = ::LsaNtStatusToWinError(st);
	if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er)
		ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");

	// compare SIDs
	for (i = 0; i < lCollCnt; i++)
	{
		// get SID
		pltsSid = &pltsSids[i];
		if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use)
			continue; // ignore...

		hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid);
		ExitOnFailure(hr, "Failed to convert SID");

		// compare SIDs
		if (::EqualSid(pSid, pTmpSid))
		{
			*pi = i;
			ExitFunction1(hr = S_OK);
		}
	}

	if (ERROR_NONE_MAPPED == er && ERROR_SOME_NOT_MAPPED == er)
		hr = HRESULT_FROM_WIN32(er);
	else
		hr = S_FALSE; // not found

LExit:
	// clean up
	ReleaseObject(piDisp);
	ReleaseObject(piObj);
	::VariantClear(&vtVal);

	if (plusNames)
	{
		for (i = 0; i < lCollCnt; i++)
			FreeLsaUnicodeString(&plusNames[i]);
		::HeapFree(::GetProcessHeap(), 0, plusNames);
	}

	if (lsahPolicy)
		::LsaClose(lsahPolicy);
	if (plrdsDomains)
		::LsaFreeMemory(plrdsDomains);
	if (pltsSids)
		::LsaFreeMemory(pltsSids);

	if (pTmpSid)
		::HeapFree(::GetProcessHeap(), 0, pTmpSid);

	return hr;
}
Example #9
0
HRESULT CpiLogCatalogErrorInfo()
{
	HRESULT hr = S_OK;

	ICOMAdminCatalog* piCatalog = NULL;
	ICatalogCollection* piErrColl = NULL;
	IDispatch* piDisp = NULL;
	ICatalogObject* piObj = NULL;

	LPWSTR pwzName = NULL;
	LPWSTR pwzErrorCode = NULL;
	LPWSTR pwzMajorRef = NULL;
	LPWSTR pwzMinorRef = NULL;

	// get catalog
	hr = CpiGetAdminCatalog(&piCatalog);
	ExitOnFailure(hr, "Failed to get COM+ admin catalog");

	// get error info collection
	hr = CpiGetCatalogCollection(L"ErrorInfo", &piErrColl);
	ExitOnFailure(hr, "Failed to get error info collection");

	// loop objects
	long lCnt;
	hr = piErrColl->get_Count(&lCnt);
	ExitOnFailure(hr, "Failed to get to number of items in collection");

	for (long i = 0; i < lCnt; i++)
	{
		// get ICatalogObject interface
		hr = piErrColl->get_Item(i, &piDisp);
		ExitOnFailure(hr, "Failed to get item from partitions collection");

		hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
		ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");

		// get properties
		hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName);
		ExitOnFailure(hr, "Failed to get name");
		hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode);
		ExitOnFailure(hr, "Failed to get error code");
		hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef);
		ExitOnFailure(hr, "Failed to get major ref");
		hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef);
		ExitOnFailure(hr, "Failed to get minor ref");

		// write to log
		WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'",
			pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef);

		// clean up
		ReleaseNullObject(piDisp);
		ReleaseNullObject(piObj);
	}

	hr = S_OK;

LExit:
	// clean up
	ReleaseObject(piCatalog);
	ReleaseObject(piErrColl);
	ReleaseObject(piDisp);
	ReleaseObject(piObj);

	ReleaseStr(pwzName);
	ReleaseStr(pwzErrorCode);
	ReleaseStr(pwzMajorRef);
	ReleaseStr(pwzMinorRef);

	return hr;
}
Example #10
0
DAPI_(void) BalUninitialize()
{
    ReleaseNullObject(vpEngine);
}
Example #11
0
/******************************************************************
 ExecXmlConfig - entry point for XmlConfig Custom Action

*******************************************************************/
extern "C" UINT __stdcall ExecXmlConfig(
    __in MSIHANDLE hInstall
    )
{
    //AssertSz(FALSE, "debug ExecXmlConfig");
    HRESULT hr = S_OK;
    HRESULT hrOpenFailure = S_OK;
    UINT er = ERROR_SUCCESS;

    BOOL fIsWow64Process = FALSE;
    BOOL fIsFSRedirectDisabled = FALSE;
    BOOL fPreserveDate = FALSE;

    LPWSTR pwzCustomActionData = NULL;
    LPWSTR pwzData = NULL;
    LPWSTR pwzFile = NULL;
    LPWSTR pwzElementPath = NULL;
    LPWSTR pwzVerifyPath = NULL;
    LPWSTR pwzName = NULL;
    LPWSTR pwzValue = NULL;
    LPWSTR pwz = NULL;
    int cAdditionalChanges = 0;

    IXMLDOMDocument* pixd = NULL;
    IXMLDOMNode* pixn = NULL;
    IXMLDOMNode* pixnVerify = NULL;
    IXMLDOMNode* pixnNewNode = NULL;
    IXMLDOMNode* pixnRemovedChild = NULL;

    IXMLDOMDocument* pixdNew = NULL;
    IXMLDOMElement* pixeNew = NULL;

    FILETIME ft;

    int id = IDRETRY;

    eXmlAction xa;
    eXmlPreserveDate xd;

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

    hr = XmlInitialize();
    ExitOnFailure(hr, "failed to initialize xml utilities");

    hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
    ExitOnFailure(hr, "failed to get CustomActionData");

    WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);

    pwz = pwzCustomActionData;

    hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
    ExitOnFailure(hr, "failed to process CustomActionData");

    // Initialize the Wow64 API - store the result in fWow64APIPresent
    // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases
    WcaInitializeWow64();
    fIsWow64Process = WcaIsWow64Process();

    if (xaOpenFile != xa && xaOpenFilex64 != xa)
    {
        ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data");
    }

    // loop through all the passed in data
    while (pwz && *pwz)
    {
        hr = WcaReadStringFromCaData(&pwz, &pwzFile);
        ExitOnFailure(hr, "failed to read file name from custom action data");

        // Default to not preserve date, preserve it if any modifications require us to
        fPreserveDate = FALSE;

        // Open the file
        ReleaseNullObject(pixd);

        if (xaOpenFilex64 == xa)
        {
            if (!fIsWow64Process)
            {
                hr = E_NOTIMPL;
                ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW.");
            }

            hr = WcaDisableWow64FSRedirection();
            ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API.");

            fIsFSRedirectDisabled = TRUE;
        }

        hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd);
        if (FAILED(hr))
        {
            // Ignore the return code for now.  If they try to add something, we'll fail the install.  If all they do is remove stuff then it doesn't matter.
            hrOpenFailure = hr;
            hr = S_OK;
        }
        else
        {
            hrOpenFailure = S_OK;
        }

        WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile);

        while (pwz && *pwz)
        {
            // If we skip past an element that has additional changes we need to strip them off the stream before
            // moving on to the next element. Do that now and then restart the outer loop.
            if (cAdditionalChanges > 0)
            {
                while (cAdditionalChanges > 0)
                {
                    hr = WcaReadStringFromCaData(&pwz, &pwzName);
                    ExitOnFailure(hr, "failed to process CustomActionData");
                    hr = WcaReadStringFromCaData(&pwz, &pwzValue);
                    ExitOnFailure(hr, "failed to process CustomActionData");

                    cAdditionalChanges--;
                }
                continue;
            }

            hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa);
            ExitOnFailure(hr, "failed to process CustomActionData");

            // Break if we need to move on to a different file
            if (xaOpenFile == xa || xaOpenFilex64 == xa)
            {
                break;
            }

            hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd);
            ExitOnFailure(hr, "failed to process CustomActionData");

            if (xdPreserve == xd)
            {
                fPreserveDate = TRUE;
            }

            // Get path, name, and value to be written
            hr = WcaReadStringFromCaData(&pwz, &pwzElementPath);
            ExitOnFailure(hr, "failed to process CustomActionData");
            hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath);
            ExitOnFailure(hr, "failed to process CustomActionData");
            hr = WcaReadStringFromCaData(&pwz, &pwzName);
            ExitOnFailure(hr, "failed to process CustomActionData");
            hr = WcaReadStringFromCaData(&pwz, &pwzValue);
            ExitOnFailure(hr, "failed to process CustomActionData");
            hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges);
            ExitOnFailure(hr, "failed to process CustomActionData");

            // If we failed to open the file and we're adding something to the file, we've got a problem.  Otherwise, just continue on since the file's already gone.
            if (FAILED(hrOpenFailure))
            {
                if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa)
                {
                    MessageExitOnFailure1(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile);
                }
                else
                {
                    continue;
                }
            }

            // Select the node we're about to modify
            ReleaseNullObject(pixn);

            hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn);

            // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone.
            if (S_FALSE == hr)
            {
                if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa)
                {
                    hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
                }
                else
                {
                    hr = S_OK;
                    continue;
                }
            }

            MessageExitOnFailure2(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile);

            // Make the modification
            switch (xa)
            {
            case xaWriteValue:
                if (pwzName && *pwzName)
                {
                    // We're setting an attribute
                    hr = XmlSetAttribute(pixn, pwzName, pwzValue);
                    ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);
                }
                else
                {
                    // We're setting the text of the node
                    hr = XmlSetText(pixn, pwzValue);
                    ExitOnFailure2(hr, "failed to set text to: %ls for element %ls.  Make sure that XPath points to an element.", pwzValue, pwzElementPath);
                }
                break;
            case xaWriteDocument:
                if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
                {
                    hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
                    if (S_OK == hr)
                    {
                        // We found the verify path which means we have no further work to do
                        continue;
                    }
                    ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath);
                }

                hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew);
                ExitOnFailure(hr, "Failed to load value as document.");

                hr = pixdNew->get_documentElement(&pixeNew);
                ExitOnFailure(hr, "Failed to get document element.");

                hr = pixn->appendChild(pixeNew, NULL);
                ExitOnFailure(hr, "Failed to append document element on to parent element.");

                ReleaseNullObject(pixeNew);
                ReleaseNullObject(pixdNew);
                break;

            case xaCreateElement:
                if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
                {
                    hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
                    if (S_OK == hr)
                    {
                        // We found the verify path which means we have no further work to do
                        continue;
                    }
                    ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath);
                }

                hr = XmlCreateChild(pixn, pwzName, &pixnNewNode);
                ExitOnFailure1(hr, "failed to create child element: %ls", pwzName);

                if (pwzValue && *pwzValue)
                {
                    hr = XmlSetText(pixnNewNode, pwzValue);
                    ExitOnFailure2(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName);
                }

                while (cAdditionalChanges > 0)
                {
                    hr = WcaReadStringFromCaData(&pwz, &pwzName);
                    ExitOnFailure(hr, "failed to process CustomActionData");
                    hr = WcaReadStringFromCaData(&pwz, &pwzValue);
                    ExitOnFailure(hr, "failed to process CustomActionData");

                    // Set the additional attribute
                    hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue);
                    ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue);

                    cAdditionalChanges--;
                }

                ReleaseNullObject(pixnNewNode);
                break;
            case xaDeleteValue:
                if (pwzName && *pwzName)
                {
                    // Delete the attribute
                    hr = XmlRemoveAttribute(pixn, pwzName);
                    ExitOnFailure1(hr, "failed to remove attribute: %ls", pwzName);
                }
                else
                {
                    // Clear the text value for the node
                    hr = XmlSetText(pixn, L"");
                    ExitOnFailure(hr, "failed to clear text value");
                }
                break;
            case xaDeleteElement:
                if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0])
                {
                    hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify);
                    if (S_OK == hr)
                    {
                        hr = pixn->removeChild(pixnVerify, &pixnRemovedChild);
                        ExitOnFailure(hr, "failed to remove created child element");

                        ReleaseNullObject(pixnRemovedChild);
                    }
                    else
                    {
                        WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting.  Skipping...", pwzVerifyPath);
                        hr = S_OK;
                    }
                }
                else
                {
                    // TODO: This requires a VerifyPath to delete an element.  Should we support not having one?
                    WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath);
                }
                break;
            default:
                ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data");
                break;
            }
        }


        // Now that we've made all of the changes to this file, save it and move on to the next
        if (S_OK == hrOpenFailure)
        {
            if (fPreserveDate)
            {
                hr = FileGetTime(pwzFile, NULL, NULL, &ft);
                ExitOnFailure1(hr, "failed to get modified time of file : %ls", pwzFile);
            }

            int iSaveAttempt = 0;

            do
            {
                hr = XmlSaveDocument(pixd, pwzFile);
                if (FAILED(hr))
                {
                    id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile);
                    switch (id)
                    {
                    case IDABORT:
                        ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile);
                    case IDRETRY:
                        hr = S_FALSE;   // hit me, baby, one more time
                        break;
                    case IDIGNORE:
                        hr = S_OK;  // pretend everything is okay and bail
                        break;
                    case 0: // No UI case, MsiProcessMessage returns 0
                        if (STIERR_SHARING_VIOLATION == hr)
                        {
                            // Only in case of sharing violation do we retry 30 times, once a second.
                            if (iSaveAttempt < 30)
                            {
                                hr = S_FALSE;
                                ++iSaveAttempt;
                                WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt);
                                Sleep(1000);
                            }
                            else
                            {
                                ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile);
                            }
                        }
                        break;
                    default: // Unknown error
                        ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile);
                    }
                }
            } while (S_FALSE == hr);

            if (fPreserveDate)
            {
                hr = FileSetTime(pwzFile, NULL, NULL, &ft);
                ExitOnFailure1(hr, "failed to set modified time of file : %ls", pwzFile);
            }

            if (fIsFSRedirectDisabled)
            {
                fIsFSRedirectDisabled = FALSE;
                WcaRevertWow64FSRedirection();
            }
        }
    }

LExit:
    // Make sure we revert FS Redirection if necessary before exiting
    if (fIsFSRedirectDisabled)
    {
        fIsFSRedirectDisabled = FALSE;
        WcaRevertWow64FSRedirection();
    }
    WcaFinalizeWow64();

    ReleaseStr(pwzCustomActionData);
    ReleaseStr(pwzData);
    ReleaseStr(pwzFile);
    ReleaseStr(pwzElementPath);
    ReleaseStr(pwzVerifyPath);
    ReleaseStr(pwzName);
    ReleaseStr(pwzValue);

    ReleaseObject(pixeNew);
    ReleaseObject(pixdNew);

    ReleaseObject(pixn);
    ReleaseObject(pixd);
    ReleaseObject(pixnNewNode);
    ReleaseObject(pixnRemovedChild);

    XmlUninitialize();

    if (FAILED(hr))
    {
        er = ERROR_INSTALL_FAILURE;
    }
    return WcaFinalize(er);
}
Example #12
0
HRESULT CpiSubscriptionsVerifyInstall(
    CPI_SUBSCRIPTION_LIST* pList
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    ICatalogObject* piSubsObj = NULL;

    for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
    {
        // subscriptions that are being installed
        if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
            continue;

        // subscription is supposed to exist
        if (CpiIsInstalled(pItm->isInstalled))
        {
            // if we don't have an id
            if (!*pItm->wzID)
            {
                // find subscriptions with conflicting name
                hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
                ExitOnFailure(hr, "Failed to find collection object for subscription");

                // if the subscription was found
                if (S_OK == hr)
                {
                    // get id from subscription object
                    hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
                    ExitOnFailure(hr, "Failed to get id");
                }

                // if the subscription was not found
                else
                {
                    // create a new id
                    hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
                    ExitOnFailure(hr, "Failed to create id");
                }
            }
        }

        // subscription is supposed to be created
        else
        {
            // check for conflicts
            do {
                if (*pItm->wzID)
                {
                    // find subscriptions with conflicting id
                    hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj);
                    ExitOnFailure(hr, "Failed to find collection object for subscription");

                    if (S_FALSE == hr)
                    {
                        // find subscriptions with conflicting name
                        hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
                        ExitOnFailure(hr, "Failed to find collection object for subscription");

                        if (S_OK == hr)
                            // "A subscription with a conflictiong name exists. retry cancel"
                            er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0);
                        else
                            break; // no conflicting entry found, break loop
                    }
                    else
                        // "A subscription with a conflicting id exists. abort retry ignore"
                        er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
                }
                else
                {
                    // find subscriptions with conflicting name
                    hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj);
                    ExitOnFailure(hr, "Failed to find collection object for subscription");

                    if (S_OK == hr)
                        // "A subscription with a conflictiong name exists. abort retry ignore"
                        er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
                    else
                        break; // no conflicting entry found, break loop
                }

                switch (er)
                {
                case IDCANCEL:
                case IDABORT:
                    ExitOnFailure1(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey);
                    break;
                case IDRETRY:
                    break;
                case IDIGNORE:
                default:
                    // if we don't have an id, copy id from object
                    if (!*pItm->wzID)
                    {
                        hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID));
                        ExitOnFailure(hr, "Failed to get id");
                    }
                    hr = S_FALSE; // indicate that this is not a conflict
                }
            } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts

            // create a new id if one is missing
            if (!*pItm->wzID)
            {
                hr = CpiCreateId(pItm->wzID, countof(pItm->wzID));
                ExitOnFailure(hr, "Failed to create id");
            }
        }

        // clean up
        ReleaseNullObject(piSubsObj);
    }

    hr = S_OK;

LExit:
    // clean up
    ReleaseObject(piSubsObj);

    return hr;
}
Example #13
0
extern "C" HRESULT ApprovedExesParseFromXml(
    __in BURN_APPROVED_EXES* pApprovedExes,
    __in IXMLDOMNode* pixnBundle
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pixnNodes = NULL;
    IXMLDOMNode* pixnNode = NULL;
    DWORD cNodes = 0;
    LPWSTR scz = NULL;

    // select approved exe nodes
    hr = XmlSelectNodes(pixnBundle, L"ApprovedExeForElevation", &pixnNodes);
    ExitOnFailure(hr, "Failed to select approved exe nodes.");

    // get approved exe node count
    hr = pixnNodes->get_length((long*)&cNodes);
    ExitOnFailure(hr, "Failed to get approved exe node count.");

    if (!cNodes)
    {
        ExitFunction();
    }

    // allocate memory for approved exes
    pApprovedExes->rgApprovedExes = (BURN_APPROVED_EXE*)MemAlloc(sizeof(BURN_APPROVED_EXE) * cNodes, TRUE);
    ExitOnNull(pApprovedExes->rgApprovedExes, hr, E_OUTOFMEMORY, "Failed to allocate memory for approved exe structs.");

    pApprovedExes->cApprovedExes = cNodes;

    // parse approved exe elements
    for (DWORD i = 0; i < cNodes; ++i)
    {
        BURN_APPROVED_EXE* pApprovedExe = &pApprovedExes->rgApprovedExes[i];

        hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
        ExitOnFailure(hr, "Failed to get next node.");

        // @Id
        hr = XmlGetAttributeEx(pixnNode, L"Id", &pApprovedExe->sczId);
        ExitOnFailure(hr, "Failed to get @Id.");

        // @Key
        hr = XmlGetAttributeEx(pixnNode, L"Key", &pApprovedExe->sczKey);
        ExitOnFailure(hr, "Failed to get @Key.");

        // @ValueName
        hr = XmlGetAttributeEx(pixnNode, L"ValueName", &pApprovedExe->sczValueName);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @ValueName.");
        }

        // @Win64
        hr = XmlGetYesNoAttribute(pixnNode, L"Win64", &pApprovedExe->fWin64);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @Win64.");
        }

        // prepare next iteration
        ReleaseNullObject(pixnNode);
        ReleaseNullStr(scz);
    }

    hr = S_OK;

LExit:
    ReleaseObject(pixnNodes);
    ReleaseObject(pixnNode);
    ReleaseStr(scz);
    return hr;
}
Example #14
0
extern "C" HRESULT PayloadsParseFromXml(
    __in BURN_PAYLOADS* pPayloads,
    __in_opt BURN_CONTAINERS* pContainers,
    __in_opt BURN_CATALOGS* pCatalogs,
    __in IXMLDOMNode* pixnBundle
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pixnNodes = NULL;
    IXMLDOMNode* pixnNode = NULL;
    DWORD cNodes = 0;
    LPWSTR scz = NULL;

    // select payload nodes
    hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes);
    ExitOnFailure(hr, "Failed to select payload nodes.");

    // get payload node count
    hr = pixnNodes->get_length((long*)&cNodes);
    ExitOnFailure(hr, "Failed to get payload node count.");

    if (!cNodes)
    {
        ExitFunction();
    }

    // allocate memory for payloads
    pPayloads->rgPayloads = (BURN_PAYLOAD*)MemAlloc(sizeof(BURN_PAYLOAD) * cNodes, TRUE);
    ExitOnNull(pPayloads->rgPayloads, hr, E_OUTOFMEMORY, "Failed to allocate memory for payload structs.");

    pPayloads->cPayloads = cNodes;

    // parse search elements
    for (DWORD i = 0; i < cNodes; ++i)
    {
        BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];

        hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
        ExitOnFailure(hr, "Failed to get next node.");

        // @Id
        hr = XmlGetAttributeEx(pixnNode, L"Id", &pPayload->sczKey);
        ExitOnFailure(hr, "Failed to get @Id.");

        // @FilePath
        hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath);
        ExitOnFailure(hr, "Failed to get @FilePath.");

        // @Packaging
        hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz);
        ExitOnFailure(hr, "Failed to get @Packaging.");

        if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"download", -1))
        {
            pPayload->packaging = BURN_PAYLOAD_PACKAGING_DOWNLOAD;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1))
        {
            pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1))
        {
            pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL;
        }
        else
        {
            hr = E_INVALIDARG;
            ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz);
        }

        // @Container
        if (pContainers)
        {
            hr = XmlGetAttributeEx(pixnNode, L"Container", &scz);
            if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
            {
                ExitOnFailure(hr, "Failed to get @Container.");

                // find container
                hr = ContainerFindById(pContainers, scz, &pPayload->pContainer);
                ExitOnFailure(hr, "Failed to to find container: %ls", scz);
            }
        }

        // @LayoutOnly
        hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @LayoutOnly.");
        }

        // @SourcePath
        hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath);
        if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_DOWNLOAD != pPayload->packaging)
        {
            ExitOnFailure(hr, "Failed to get @SourcePath.");
        }

        // @DownloadUrl
        hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl);
        if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_DOWNLOAD == pPayload->packaging)
        {
            ExitOnFailure(hr, "Failed to get @DownloadUrl.");
        }

        // @FileSize
        hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @FileSize.");

            hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize);
            ExitOnFailure(hr, "Failed to parse @FileSize.");
        }

        // @CertificateAuthorityKeyIdentifier
        hr = XmlGetAttributeEx(pixnNode, L"CertificateRootPublicKeyIdentifier", &scz);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @CertificateRootPublicKeyIdentifier.");

            hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootPublicKeyIdentifier, &pPayload->cbCertificateRootPublicKeyIdentifier);
            ExitOnFailure(hr, "Failed to hex decode @CertificateRootPublicKeyIdentifier.");
        }

        // @CertificateThumbprint
        hr = XmlGetAttributeEx(pixnNode, L"CertificateRootThumbprint", &scz);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @CertificateRootThumbprint.");

            hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootThumbprint, &pPayload->cbCertificateRootThumbprint);
            ExitOnFailure(hr, "Failed to hex decode @CertificateRootThumbprint.");
        }

        // @Hash
        hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz);
        ExitOnFailure(hr, "Failed to get @Hash.");

        hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash);
        ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash.");

        // @Catalog
        hr = XmlGetAttributeEx(pixnNode, L"Catalog", &scz);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get @Catalog.");

            hr = CatalogFindById(pCatalogs, scz, &pPayload->pCatalog);
            ExitOnFailure(hr, "Failed to find catalog.");
        }

        // prepare next iteration
        ReleaseNullObject(pixnNode);
    }

    hr = S_OK;

LExit:
    ReleaseObject(pixnNodes);
    ReleaseObject(pixnNode);
    ReleaseStr(scz);

    return hr;
}
Example #15
0
extern "C" HRESULT ExeEngineParsePackageFromXml(
    __in IXMLDOMNode* pixnExePackage,
    __in BURN_PACKAGE* pPackage
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pixnNodes = NULL;
    IXMLDOMNode* pixnNode = NULL;
    DWORD cNodes = 0;
    LPWSTR scz = NULL;

    // @DetectCondition
    hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition);
    ExitOnFailure(hr, "Failed to get @DetectCondition.");

    // @InstallArguments
    hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments);
    ExitOnFailure(hr, "Failed to get @InstallArguments.");

    // @UninstallArguments
    hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments);
    ExitOnFailure(hr, "Failed to get @UninstallArguments.");

    // @RepairArguments
    hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments);
    ExitOnFailure(hr, "Failed to get @RepairArguments.");

    // @Repairable
    hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable);
    if (E_NOTFOUND != hr)
    {
        ExitOnFailure(hr, "Failed to get @Repairable.");
    }

    // @Protocol
    hr = XmlGetAttributeEx(pixnExePackage, L"Protocol", &scz);
    if (SUCCEEDED(hr))
    {
        if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"burn", -1))
        {
            pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_BURN;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"netfx4", -1))
        {
            pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NETFX4;
        }
        else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1))
        {
            pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NONE;
        }
        else
        {
            hr = E_UNEXPECTED;
            ExitOnFailure1(hr, "Invalid protocol type: %ls", scz);
        }
    }
    else if (E_NOTFOUND != hr)
    {
        ExitOnFailure(hr, "Failed to get @Protocol.");
    }

    // select exit code nodes
    hr = XmlSelectNodes(pixnExePackage, L"ExitCode", &pixnNodes);
    ExitOnFailure(hr, "Failed to select exit code nodes.");

    // get exit code node count
    hr = pixnNodes->get_length((long*)&cNodes);
    ExitOnFailure(hr, "Failed to get exit code node count.");

    if (cNodes)
    {
        // allocate memory for exit codes
        pPackage->Exe.rgExitCodes = (BURN_EXE_EXIT_CODE*)MemAlloc(sizeof(BURN_EXE_EXIT_CODE) * cNodes, TRUE);
        ExitOnNull(pPackage->Exe.rgExitCodes, hr, E_OUTOFMEMORY, "Failed to allocate memory for exit code structs.");

        pPackage->Exe.cExitCodes = cNodes;

        // parse package elements
        for (DWORD i = 0; i < cNodes; ++i)
        {
            BURN_EXE_EXIT_CODE* pExitCode = &pPackage->Exe.rgExitCodes[i];

            hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
            ExitOnFailure(hr, "Failed to get next node.");

            // @Type
            hr = XmlGetAttributeEx(pixnNode, L"Type", &scz);
            ExitOnFailure(hr, "Failed to get @Type.");

            if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"success", -1))
            {
                pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_SUCCESS;
            }
            else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"error", -1))
            {
                pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_ERROR;
            }
            else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"scheduleReboot", -1))
            {
                pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_SCHEDULE_REBOOT;
            }
            else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"forceReboot", -1))
            {
                pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT;
            }
            else
            {
                hr = E_UNEXPECTED;
                ExitOnFailure1(hr, "Invalid exit code type: %ls", scz);
            }

            // @Code
            hr = XmlGetAttributeEx(pixnNode, L"Code", &scz);
            ExitOnFailure(hr, "Failed to get @Code.");

            if (L'*' == scz[0])
            {
                pExitCode->fWildcard = TRUE;
            }
            else
            {
                hr = StrStringToUInt32(scz, 0, (UINT*)&pExitCode->dwCode);
                ExitOnFailure1(hr, "Failed to parse @Code value: %ls", scz);
            }

            // prepare next iteration
            ReleaseNullObject(pixnNode);
        }
    }

    hr = S_OK;

LExit:
    ReleaseObject(pixnNodes);
    ReleaseObject(pixnNode);
    ReleaseStr(scz);

    return hr;
}
Example #16
0
HRESULT CpiRemoveCollectionObject(
	ICatalogCollection* piColl,
	LPCWSTR pwzID,
	LPCWSTR pwzName,
	BOOL fResetDeleteable
	)
{
	HRESULT hr = S_OK;

	IDispatch* piDisp = NULL;
	ICatalogObject* piObj = NULL;

	BOOL fMatch = FALSE;

	VARIANT vtVal;
	::VariantInit(&vtVal);

	long lCnt;
	hr = piColl->get_Count(&lCnt);
	ExitOnFailure(hr, "Failed to get to number of items in collection");

	for (long i = 0; i < lCnt; i++)
	{
		// get ICatalogObject interface
		hr = piColl->get_Item(i, &piDisp);
		ExitOnFailure(hr, "Failed to get object from collection");

		hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
		ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");

		// compare id
		if (pwzID && *pwzID)
		{
			hr = piObj->get_Key(&vtVal);
			ExitOnFailure(hr, "Failed to get key");

			hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
			ExitOnFailure(hr, "Failed to change variant type");

			if (0 == lstrcmpiW(vtVal.bstrVal, pwzID))
				fMatch = TRUE;

			::VariantClear(&vtVal);
		}

		// compare name
		if (pwzName && *pwzName)
		{
			hr = piObj->get_Name(&vtVal);
			ExitOnFailure(hr, "Failed to get name");

			hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR);
			ExitOnFailure(hr, "Failed to change variant type");

			if (0 == lstrcmpW(vtVal.bstrVal, pwzName))
				fMatch = TRUE;

			::VariantClear(&vtVal);
		}

		// if it's a match, remove it
		if (fMatch)
		{
			if (fResetDeleteable)
			{
				// reset deleteable property, if set
				hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable");
				ExitOnFailure(hr, "Failed to reset deleteable property");
			}

			hr = piColl->Remove(i);
			ExitOnFailure(hr, "Failed to remove item from collection");
			break;
		}

		// release interface pointers
		ReleaseNullObject(piDisp);
		ReleaseNullObject(piObj);
	}

	hr = S_OK;

LExit:
	// clean up
	ReleaseObject(piDisp);
	ReleaseObject(piObj);

	::VariantClear(&vtVal);

	return hr;
}
Example #17
0
extern "C" HRESULT DependencyParseProvidersFromXml(
    __in BURN_PACKAGE* pPackage,
    __in IXMLDOMNode* pixnPackage
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNodeList* pixnNodes = NULL;
    DWORD cNodes = 0;
    IXMLDOMNode* pixnNode = NULL;

    // Select dependency provider nodes.
    hr = XmlSelectNodes(pixnPackage, L"Provides", &pixnNodes);
    ExitOnFailure(hr, "Failed to select dependency provider nodes.");

    // Get dependency provider node count.
    hr = pixnNodes->get_length((long*)&cNodes);
    ExitOnFailure(hr, "Failed to get the dependency provider node count.");

    if (!cNodes)
    {
        ExitFunction1(hr = S_OK);
    }

    // Allocate memory for dependency provider pointers.
    pPackage->rgDependencyProviders = (BURN_DEPENDENCY_PROVIDER*)MemAlloc(sizeof(BURN_DEPENDENCY_PROVIDER) * cNodes, TRUE);
    ExitOnNull(pPackage->rgDependencyProviders, hr, E_OUTOFMEMORY, "Failed to allocate memory for dependency providers.");

    pPackage->cDependencyProviders = cNodes;

    // Parse dependency provider elements.
    for (DWORD i = 0; i < cNodes; i++)
    {
        BURN_DEPENDENCY_PROVIDER* pDependencyProvider = &pPackage->rgDependencyProviders[i];

        hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
        ExitOnFailure(hr, "Failed to get the next dependency provider node.");

        // @Key
        hr = XmlGetAttributeEx(pixnNode, L"Key", &pDependencyProvider->sczKey);
        ExitOnFailure(hr, "Failed to get the Key attribute.");

        // @Version
        hr = XmlGetAttributeEx(pixnNode, L"Version", &pDependencyProvider->sczVersion);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get the Version attribute.");
        }

        // @DisplayName
        hr = XmlGetAttributeEx(pixnNode, L"DisplayName", &pDependencyProvider->sczDisplayName);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get the DisplayName attribute.");
        }

        // @Imported
        hr = XmlGetYesNoAttribute(pixnNode, L"Imported", &pDependencyProvider->fImported);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to get the Imported attribute.");
        }
        else
        {
            pDependencyProvider->fImported = FALSE;
            hr = S_OK;
        }

        // Prepare next iteration.
        ReleaseNullObject(pixnNode);
    }

    hr = S_OK;

LExit:
    ReleaseObject(pixnNode);
    ReleaseObject(pixnNodes);

    return hr;
}
Example #18
0
HRESULT CpiFindCollectionObjectByIntegerKey(
	ICatalogCollection* piColl,
	long lKey,
	ICatalogObject** ppiObj
	)
{
	HRESULT hr = S_OK;

	IDispatch* piDisp = NULL;
	ICatalogObject* piObj = NULL;

	VARIANT vtVal;
	::VariantInit(&vtVal);

	long lCnt;
	hr = piColl->get_Count(&lCnt);
	ExitOnFailure(hr, "Failed to get to number of items in collection");

	for (long i = 0; i < lCnt; i++)
	{
		// get ICatalogObject interface
		hr = piColl->get_Item(i, &piDisp);
		ExitOnFailure(hr, "Failed to get object from collection");

		hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj);
		ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface");

		// compare key
		hr = piObj->get_Key(&vtVal);
		ExitOnFailure(hr, "Failed to get key");

		hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4);
		ExitOnFailure(hr, "Failed to change variant type");

		if (vtVal.lVal == lKey)
		{
			if (ppiObj)
			{
				*ppiObj = piObj;
				piObj = NULL;
			}
			ExitFunction1(hr = S_OK);
		}

		// clean up
		ReleaseNullObject(piDisp);
		ReleaseNullObject(piObj);

		::VariantClear(&vtVal);
	}

	hr = S_FALSE;

LExit:
	// clean up
	ReleaseObject(piDisp);
	ReleaseObject(piObj);

	::VariantClear(&vtVal);

	return hr;
}
Example #19
0
/********************************************************************
 SqlGetErrorInfo - gets error information from the last SQL function call

 NOTE: pbstrErrorSource and pbstrErrorDescription are optional
********************************************************************/
extern "C" HRESULT DAPI SqlGetErrorInfo(
    __in IUnknown* pObjectWithError,
    __in REFIID IID_InterfaceWithError,
    __in DWORD dwLocaleId,
    __out_opt BSTR* pbstrErrorSource,
    __out_opt BSTR* pbstrErrorDescription
    )
{
    HRESULT hr = S_OK;
    Assert(pObjectWithError);

    // interfaces needed to extract error information out
    ISupportErrorInfo* pISupportErrorInfo = NULL;
    IErrorInfo* pIErrorInfoAll = NULL;
    IErrorRecords* pIErrorRecords = NULL;
    IErrorInfo* pIErrorInfoRecord = NULL;

    // only ask for error information if the interface supports it.
    hr = pObjectWithError->QueryInterface(IID_ISupportErrorInfo,(void**)&pISupportErrorInfo);
    ExitOnFailure(hr, "No error information was found for object.");

    hr = pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError);
    ExitOnFailure(hr, "InterfaceWithError is not supported for object with error");

    // ignore the return of GetErrorInfo it can succeed and return a NULL pointer in pIErrorInfoAll anyway
    hr = ::GetErrorInfo(0, &pIErrorInfoAll);
    ExitOnFailure(hr, "failed to get error info");

    if (S_OK == hr && pIErrorInfoAll)
    {
        // see if it's a valid OLE DB IErrorInfo interface that exposes a list of records
        hr = pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords);
        if (SUCCEEDED(hr))
        {
            ULONG cErrors = 0;
            pIErrorRecords->GetRecordCount(&cErrors);

            // get the error information for each record
            for (ULONG i = 0; i < cErrors; ++i)
            {
                hr = pIErrorRecords->GetErrorInfo(i, dwLocaleId, &pIErrorInfoRecord);
                if (SUCCEEDED(hr))
                {
                    if (pbstrErrorSource)
                    {
                        pIErrorInfoRecord->GetSource(pbstrErrorSource);
                    }
                    if (pbstrErrorDescription)
                    {
                        pIErrorInfoRecord->GetDescription(pbstrErrorDescription);
                    }

                    ReleaseNullObject(pIErrorInfoRecord);

                    break; // TODO: return more than one error in the future!
                }
            }

            ReleaseNullObject(pIErrorRecords);
        }
        else // we have a simple error record
        {
            if (pbstrErrorSource)
            {
                pIErrorInfoAll->GetSource(pbstrErrorSource);
            }
            if (pbstrErrorDescription)
            {
                pIErrorInfoAll->GetDescription(pbstrErrorDescription);
            }
        }
    }
    else
    {
        hr = E_NOMOREITEMS;
    }

LExit:
    ReleaseObject(pIErrorInfoRecord);
    ReleaseObject(pIErrorRecords);
    ReleaseObject(pIErrorInfoAll);
    ReleaseObject(pISupportErrorInfo);

    return hr;
}
Example #20
0
HRESULT ScaWebSearch7(
    __in SCA_WEB7* psw,
    __deref_out_z_opt LPWSTR* pswWeb,
    __out_opt BOOL* pfFound
    )
{
    HRESULT hr = S_OK;
    BOOL fInitializedCom = FALSE;
    BSTR bstrSites = NULL;
    BSTR bstrAppHostRoot = NULL;
    IAppHostAdminManager *pAdminMgr = NULL;
    IAppHostElement *pSites = NULL;
    IAppHostElementCollection *pCollection = NULL;
    IAppHostElement *pSite = NULL;

    if (NULL != pswWeb)
    {
        ReleaseNullStr(*pswWeb);
    }

    if (NULL != pfFound)
    {
        *pfFound = FALSE;
    }

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

    hr = CoCreateInstance(__uuidof(AppHostAdminManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppHostAdminManager), reinterpret_cast<void**> (&pAdminMgr));
    if (REGDB_E_CLASSNOTREG == hr)
    {
        WcaLog(LOGMSG_VERBOSE, "AppHostAdminManager was not registered, cannot find site.");
        hr = S_OK;
        ExitFunction();
    }
    ExitOnFailure(hr, "Failed to CoCreate IAppHostAdminManager");

    bstrSites = ::SysAllocString(IIS_CONFIG_SITES_SECTION);
    ExitOnNull(bstrSites, hr, E_OUTOFMEMORY, "Failed to allocate sites string.");

    bstrAppHostRoot = ::SysAllocString(IIS_CONFIG_APPHOST_ROOT);
    ExitOnNull(bstrAppHostRoot, hr, E_OUTOFMEMORY, "Failed to allocate host root string.");

    hr = pAdminMgr->GetAdminSection(bstrSites, bstrAppHostRoot, &pSites);
    ExitOnFailure(hr, "Failed get sites section");
    ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object");

    hr = pSites->get_Collection(&pCollection);
    ExitOnFailure(hr, "Failed get sites collection");

    // not explicitly doing a Description search
    if (-1 != psw->iSiteId)
    {
        if (MSI_NULL_INTEGER == psw->iSiteId)
        {
            // Enumerate sites & determine if the binding matches
            hr = Iis7EnumAppHostElements(pCollection, EnumSiteCompareBinding, psw, &pSite, NULL);
            ExitOnFailure(hr, "Failed locate site by ID");
        }
        else
        {
            // Find a site with ID matches
            hr = Iis7FindAppHostElementInteger(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_ID, psw->iSiteId, &pSite, NULL);
            ExitOnFailure(hr, "Failed locate site by ID");
        }
    }

    if (NULL == pSite)
    {
        // Find a site with Name that matches
        hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, psw->wzDescription, &pSite, NULL);
        ExitOnFailure(hr, "Failed locate site by ID");
    }

    if (NULL != pSite)
    {
        if (NULL != pfFound)
        {
            *pfFound = TRUE;
        }

        if (NULL != pswWeb)
        {
            // We found a site, return its description
            hr = Iis7GetPropertyString(pSite, IIS_CONFIG_NAME, pswWeb);
            ExitOnFailure(hr, "Failed get site name");
        }
    }
LExit:
    ReleaseNullObject(pAdminMgr);
    ReleaseNullObject(pSites);
    ReleaseNullObject(pCollection);
    ReleaseNullObject(pSite);
    ReleaseBSTR(bstrAppHostRoot);
    ReleaseBSTR(bstrSites);

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