Example #1
0
HRESULT ScaWebsRead(
    __in IMSAdminBase* piMetabase,
    __in SCA_MIMEMAP** ppsmmList,
    __in SCA_WEB** ppswList,
    __in SCA_HTTP_HEADER** ppshhList,
    __in SCA_WEB_ERROR** ppsweList,
    __in WCA_WRAPQUERY_HANDLE hUserQuery,
    __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
    __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
    __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
    __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
    __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
    __inout LPWSTR *ppwzCustomActionData
    )
{
    Assert(piMetabase && ppswList);

    HRESULT hr = S_OK;

    MSIHANDLE hRec;
    MSIHANDLE hRecAddresses;

    SCA_WEB* psw = NULL;
    LPWSTR pwzData = NULL;
    int iSiteId;

    DWORD dwLen = 0;
    WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL;
    WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL;

    hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData);
    ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");

    hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData);
    ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");

    if (0 == WcaGetQueryRecords(hQueryWebSite))
    {
        WcaLog(LOGMSG_VERBOSE, "Required tables not present");
        ExitFunction1(hr = S_FALSE);
    }

    // loop through all the webs
    while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec)))
    {
        psw = NewWeb();
        ExitOnNull(psw, hr, E_OUTOFMEMORY, "Failed to allocate memory for web object in memory");

        // get the darwin information
        hr = WcaGetRecordString(hRec, wqWeb, &pwzData);
        ExitOnFailure(hr, "Failed to get Web");
        hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData);
        ExitOnFailure(hr, "Failed to copy key string to web object");

        if (*pwzData && *ppsmmList)
        {
            hr = ScaGetMimeMap(mmptWeb, pwzData, ppsmmList, &psw->psmm);
            ExitOnFailure(hr, "Failed to get mimemap for VirtualDir");
        }

        // get component install state
        hr = WcaGetRecordString(hRec, wqComponent, &pwzData);
        ExitOnFailure(hr, "Failed to get Component for Web");
        hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData);
        ExitOnFailure(hr, "Failed to copy component string to web object");
        if (*(psw->wzComponent))
        {
            psw->fHasComponent = TRUE;

            hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled);
            ExitOnFailure(hr, "Failed to get web Component's installed state");

            WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction);
            ExitOnFailure(hr, "Failed to get web Component's action state");

            if (!WcaIsInstalling(psw->isInstalled, psw->isAction) && !WcaIsUninstalling(psw->isInstalled, psw->isAction)
                && !WcaIsReInstalling(psw->isInstalled, psw->isAction))
            {
                FreeWeb(psw);
                psw = NULL;

                continue; // If we aren't acting on this component, skip it
            }
        }

        hr = WcaGetRecordInteger(hRec, wqId, &iSiteId);
        ExitOnFailure(hr, "Failed to get SiteId for Web");

        // Get the web's key address.
        hr = WcaGetRecordString(hRec, wqAddress, &pwzData);
        ExitOnFailure(hr, "Failed to get Address for Web");
        hr = ::StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData);
        ExitOnFailure(hr, "Failed to copy key string to web object");

        hr = WcaGetRecordString(hRec, wqIP, &pwzData);
        ExitOnFailure(hr, "Failed to get IP for Web");
        hr = ::StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData);
        ExitOnFailure(hr, "Failed to copy IP string to web object");

        hr = WcaGetRecordString(hRec, wqPort, &pwzData);
        ExitOnFailure(hr, "Failed to get Web Address port");
        psw->swaKey.iPort = wcstol(pwzData, NULL, 10);

        hr = WcaGetRecordString(hRec, wqHeader, &pwzData);
        ExitOnFailure(hr, "Failed to get Header for Web");
        hr = ::StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData);
        ExitOnFailure(hr, "Failed to copy header string to web object");

        hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure);
        ExitOnFailure(hr, "Failed to get if Web is secure");
        if (S_FALSE == hr)
        {
            psw->swaKey.fSecure = FALSE;
        }

        // Get the web's description.
        hr = WcaGetRecordString(hRec, wqDescription, &pwzData);
        ExitOnFailure(hr, "Failed to get Description for Web");
        hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData);
        ExitOnFailure(hr, "Failed to copy description string to web object");

        // Try to find the web root in case it already exists.
        dwLen = METADATA_MAX_NAME_LEN;
        hr = ScaWebFindBase(piMetabase, *ppswList,
                            psw->wzKey,
                            iSiteId,
                            psw->swaKey.wzIP,
                            psw->swaKey.iPort,
                            psw->swaKey.wzHeader,
                            psw->swaKey.fSecure,
                            psw->wzDescription,
                            psw->wzWebBase, dwLen);
        if (S_OK == hr)
        {
            psw->fBaseExists = TRUE;
        }
        else if (S_FALSE == hr) // didn't find the web site.
        {
            psw->fBaseExists = FALSE;

            // If we're actually configuring the web site.
            if (psw->fHasComponent)
            {
                if (WcaIsInstalling(psw->isInstalled, psw->isAction))
                {
                    hr = ScaWebFindFreeBase(piMetabase, *ppswList, iSiteId, psw->wzDescription, psw->wzWebBase, countof(psw->wzWebBase));
                    ExitOnFailure(hr, "Failed to find free web root.");
                }
                else if (WcaIsUninstalling(psw->isInstalled, psw->isAction))
                {
                    WcaLog(LOGMSG_VERBOSE, "Web site: '%ls' was already removed, skipping.", psw->wzKey);

                    hr = S_OK;
                    continue;
                }
            }
        }
        ExitOnFailure(hr, "Failed to find web root");

        // get any extra web addresses
        WcaFetchWrappedReset(hQueryWebAddress);
        while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses)))
        {
            if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
                ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded.");
            }

            hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData);
            ExitOnFailure(hr, "Failed to get extra web Address");

            // if this isn't the key address add it
            if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey))
            {
                hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData);
                ExitOnFailure(hr, "Failed to copy extra addresses key string to web object");

                hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData);
                ExitOnFailure(hr, "Failed to get extra web IP");
                hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData);
                ExitOnFailure(hr, "Failed to copy extra addresses IP string to web object");

                hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData);
                ExitOnFailure(hr, "Failed to get port for extra web IP");
                psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10);

                hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData);
                ExitOnFailure(hr, "Failed to get header for extra web IP");
                hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData);
                ExitOnFailure(hr, "Failed to copy extra addresses header string to web object");

                hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure);
                ExitOnFailure(hr, "Failed to get if secure extra web IP");
                if (S_FALSE == hr)
                    psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE;

                ++psw->cExtraAddresses;
            }
        }

        if (E_NOMOREITEMS == hr)
            hr = S_OK;
        ExitOnFailure(hr, "Failure occured while getting extra web addresses");

        hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout);
        ExitOnFailure(hr, "Failed to get connection timeout for Web");

        if (psw->fHasComponent) // If we're installing it, it needs a dir
        {
            // get the web's directory
            if (INSTALLSTATE_SOURCE == psw->isAction)
            {
                hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData);
            }
            else
            {
                hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData);
            }
            ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");

            // remove trailing backslashes
            while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\')
            {
                pwzData[lstrlenW(pwzData)-1] = 0;
            }
            hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData);
            ExitOnFailure(hr, "Failed to copy directory string to web object");
        }

        hr = WcaGetRecordInteger(hRec, wqState, &psw->iState);
        ExitOnFailure(hr, "Failed to get state for Web");

        hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes);
        ExitOnFailure(hr, "Failed to get attributes for Web");

        // get the dir properties for this web
        hr = WcaGetRecordString(hRec, wqProperties, &pwzData);
        ExitOnFailure(hr, "Failed to get directory property record for Web");
        if (*pwzData)
        {
            hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp);
            ExitOnFailure(hr, "Failed to get directory properties for Web");

            psw->fHasProperties = TRUE;
        }

        // get the application information for this web
        hr = WcaGetRecordString(hRec, wqApplication, &pwzData);
        ExitOnFailure(hr, "Failed to get application identifier for Web");
        if (*pwzData)
        {
            hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp);
            ExitOnFailure(hr, "Failed to get application for Web");

            psw->fHasApplication = TRUE;
        }

        // get the SSL certificates
        hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList));
        ExitOnFailure(hr, "Failed to get SSL Certificates.");

        // get the custom headers
        if (*ppshhList)
        {
            hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList));
            ExitOnFailure(hr, "Failed to get Custom HTTP Headers");
        }

        // get the errors
        if (*ppsweList)
        {
            hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList));
            ExitOnFailure(hr, "Failed to get Custom Errors");
        }

        // get the log information for this web
        hr = WcaGetRecordString(hRec, wqLog, &pwzData);
        ExitOnFailure(hr, "Failed to get log identifier for Web");
        if (*pwzData)
        {
            hr = ScaGetWebLog(piMetabase, pwzData, hWebLogQuery, &psw->swl);
            ExitOnFailure(hr, "Failed to get Log for Web.");

            psw->fHasLog = TRUE;
        }

        *ppswList = AddWebToList(*ppswList, psw);
        psw = NULL; // set the web NULL so it doesn't accidentally get freed below
    }

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

LExit:
    // if anything was left over after an error clean it all up
    WcaFinishUnwrapQuery(hQueryWebSite);
    WcaFinishUnwrapQuery(hQueryWebAddress);

    if (psw)
    {
        ScaWebsFreeList(psw);
    }

    ReleaseStr(pwzData);

    return hr;
}
Example #2
0
HRESULT ScaWebsRead(
	__in IMSAdminBase* piMetabase,
	__in SCA_WEB** ppswList,
	__in SCA_HTTP_HEADER** ppshhList,
	__in SCA_WEB_ERROR** ppsweList
	)
{
	Assert(piMetabase && ppswList);

	HRESULT hr = S_OK;
	UINT er = ERROR_SUCCESS;

	BOOL fIIsWebSiteTable = FALSE;
	BOOL fIIsWebAddressTable = FALSE;
	BOOL fIIsWebApplicationTable = FALSE;

	PMSIHANDLE hView, hRec;
	PMSIHANDLE hViewAddresses, hRecAddresses;
	PMSIHANDLE hViewApplications, hRecApplications;

	SCA_WEB* psw = NULL;
	LPWSTR pwzData = NULL;

	DWORD dwLen = 0;

	// check to see what tables are available
	fIIsWebSiteTable = (S_OK == WcaTableExists(L"IIsWebSite"));
	fIIsWebAddressTable = (S_OK == WcaTableExists(L"IIsWebAddress"));
	fIIsWebApplicationTable = (S_OK == WcaTableExists(L"IIsWebApplication"));

	if (!fIIsWebSiteTable || !fIIsWebAddressTable)
	{
		WcaLog(LOGMSG_VERBOSE, "Required tables not present");
		hr = S_FALSE;
		goto LExit;
	}

	// open the view on webs' addresses
	hr = WcaOpenView(vcsWebAddressQuery, &hViewAddresses);
	ExitOnFailure(hr, "Failed to open view on IIsWebAddress table");

	// open the view on webs' applications
	if (fIIsWebApplicationTable)
	{
		hr = WcaOpenView(vcsWebApplicationQuery, &hViewApplications);
		ExitOnFailure(hr, "Failed to open view on IIsWebApplication table");
	}

	// loop through all the webs
	hr = WcaOpenExecuteView(vcsWebQuery, &hView);
	ExitOnFailure(hr, "Failed to execute view on IIsWebSite table");
	while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
	{
		psw = NewWeb();
		if (!psw)
		{
			hr = E_OUTOFMEMORY;
			break;
		}

		// get the darwin information
		hr = WcaGetRecordString(hRec, wqWeb, &pwzData);
		ExitOnFailure(hr, "Failed to get Web");
		StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData);

		// get component install state
		hr = WcaGetRecordString(hRec, wqComponent, &pwzData);
		ExitOnFailure(hr, "Failed to get Component for Web");
		StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData);
		if (*(psw->wzComponent))
		{
			psw->fHasComponent = TRUE;

			er = ::MsiGetComponentStateW(WcaGetInstallHandle(), psw->wzComponent, &psw->isInstalled, &psw->isAction);
			hr = HRESULT_FROM_WIN32(er);
			ExitOnFailure(hr, "Failed to get web Component state");
		}

		// get the web's key address
		hr = WcaGetRecordString(hRec, wqAddress, &pwzData);
		ExitOnFailure(hr, "Failed to get Address for Web");
		StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData);

		hr = WcaGetRecordFormattedString(hRec, wqIP, &pwzData);
		ExitOnFailure(hr, "Failed to get IP for Web");
		StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData);

		hr = WcaGetRecordFormattedString(hRec, wqPort, &pwzData);
		ExitOnFailure(hr, "Failed to get Web Address port");
		psw->swaKey.iPort = wcstol(pwzData, NULL, 10);
		if (0 == psw->swaKey.iPort)
			ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA), "invalid port provided for web site: %S", psw->wzDescription);

		hr = WcaGetRecordFormattedString(hRec, wqHeader, &pwzData);
		ExitOnFailure(hr, "Failed to get Header for Web");
		StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData);

		hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure);
		ExitOnFailure(hr, "Failed to get if Web is secure");
		if (S_FALSE == hr)
			psw->swaKey.fSecure = FALSE;

		// TODO: fix this to look for the description as well (or is address enough)?
		// find the web root
		dwLen = METADATA_MAX_NAME_LEN;
		hr = ScaWebFindBase(piMetabase, *ppswList,
							psw->wzKey,
							psw->swaKey.wzIP,
							psw->swaKey.iPort,
							psw->swaKey.wzHeader,
							psw->swaKey.fSecure,
							psw->wzWebBase, &dwLen);
		if (S_OK == hr)
		{
			psw->fBaseExists = TRUE;
		}
		else if (S_FALSE == hr && FALSE == psw->fHasComponent) // if we're not installing it, fail if it wasn't found
		{
			ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find web site: '%S'", psw->wzKey);
		}
		else if (S_FALSE == hr)
		{
			dwLen = METADATA_MAX_NAME_LEN;
			hr = ScaWebFindFreeBase(piMetabase, *ppswList, psw->wzWebBase, dwLen);
			psw->fBaseExists = FALSE;
		}
		ExitOnFailure(hr, "Failed to find web root");

		// get any extra web addresses
		hr = WcaExecuteView(hViewAddresses, hRec);
		ExitOnFailure(hr, "Failed to execute view on extra IIsWebAddress table");
		while (S_OK == (hr = WcaFetchRecord(hViewAddresses, &hRecAddresses)))
		{
			if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses)
			{
				hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
				ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded.");
			}

			hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData);
			ExitOnFailure(hr, "Failed to get extra web Address");

			// if this isn't the key address add it
			if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey))
			{
				StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey,
					countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData);

				hr = WcaGetRecordFormattedString(hRecAddresses, waqIP, &pwzData);
				ExitOnFailure(hr, "Failed to get extra web IP");
				StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData);

				hr = WcaGetRecordFormattedString(hRecAddresses, waqPort, &pwzData);
				ExitOnFailure(hr, "Failed to get port for extra web IP");
				psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10);

				hr = WcaGetRecordFormattedString(hRecAddresses, waqHeader, &pwzData);
				ExitOnFailure(hr, "Failed to get header for extra web IP");
				StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData);

				hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure);
				ExitOnFailure(hr, "Failed to get if secure extra web IP");
				if (S_FALSE == hr)
					psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE;

				psw->cExtraAddresses++;
			}
		}

		if (E_NOMOREITEMS == hr)
			hr = S_OK;
		ExitOnFailure(hr, "Failure occured while getting extra web addresses");

		// get the web's description
		hr = WcaGetRecordFormattedString(hRec, wqDescription, &pwzData);
		ExitOnFailure(hr, "Failed to get Description for Web");
		StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData);

		hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout);
		ExitOnFailure(hr, "Failed to get connection timeout for Web");

		if (psw->fHasComponent) // If we're installing it, it needs a dir
		{
			// get the web's directory
			hr = WcaGetRecordString(hRec, wqDirectory, &pwzData);
			ExitOnFailure(hr, "Failed to get Directory for Web");

			WCHAR wzPath[MAX_PATH];
			dwLen = countof(wzPath);
			if (INSTALLSTATE_SOURCE == psw->isAction)
				er = ::MsiGetSourcePathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
			else
				er = ::MsiGetTargetPathW(WcaGetInstallHandle(), pwzData, wzPath, &dwLen);
			hr = HRESULT_FROM_WIN32(er);
			ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");

			if (dwLen > countof(wzPath))
			{
				hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
				ExitOnFailure(hr, "Failed because Source/TargetPath for Directory was greater than MAX_PATH.");
			}

			// remove traling backslash
			if (dwLen > 0 && wzPath[dwLen-1] == L'\\')
				wzPath[dwLen-1] = 0;
			StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), wzPath);
		}

		hr = WcaGetRecordInteger(hRec, wqState, &psw->iState);
		ExitOnFailure(hr, "Failed to get state for Web");

		hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes);
		ExitOnFailure(hr, "Failed to get attributes for Web");

		// get the dir properties for this web
		hr = WcaGetRecordString(hRec, wqProperties, &pwzData);
		ExitOnFailure(hr, "Failed to get directory properties for Web");
		if (*pwzData)
		{
			hr = ScaGetWebDirProperties(pwzData, &psw->swp);
			ExitOnFailure(hr, "Failed to get directory properties for Web");

			psw->fHasProperties = TRUE;
		}

		// get the application information for this web
		hr = WcaGetRecordString(hRec, wqApplication, &pwzData);
		ExitOnFailure(hr, "Failed to get application identifier for Web");
		if (*pwzData)
		{
			hr = ScaGetWebApplication(NULL, pwzData, &psw->swapp);
			ExitOnFailure(hr, "Failed to get application for Web");

			psw->fHasApplication = TRUE;
		}

		// get the SSL certificates
		hr = ScaSslCertificateRead(psw->wzKey, &(psw->pswscList));
		ExitOnFailure(hr, "Failed to get SSL Certificates.");

		// get the custom headers
		if (*ppshhList)
		{
			hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList));
			ExitOnFailure(hr, "Failed to get Custom HTTP Headers");
		}

		// get the errors
		if (*ppsweList)
		{
			hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList));
			ExitOnFailure(hr, "Failed to get Custom Errors");
		}

		// get the log information for this web
		hr = WcaGetRecordString(hRec, wqLog, &pwzData);
		ExitOnFailure(hr, "Failed to get log identifier for Web");
		if (*pwzData)
		{
			hr = ScaGetWebLog(piMetabase, pwzData, &psw->swl);
			ExitOnFailure(hr, "Failed to get Log for Web.");

			psw->fHasLog = TRUE;
		}

		*ppswList = AddWebToList(*ppswList, psw);
		psw = NULL; // set the web NULL so it doesn't accidentally get freed below
	}

	if (E_NOMOREITEMS == hr)
		hr = S_OK;

LExit:
	// if anything was left over after an error clean it all up
	if (psw)
		ScaWebsFreeList(psw);

	ReleaseStr(pwzData);

	return hr;
}