Esempio n. 1
0
extern "C" HRESULT MspEngineParsePackageFromXml(
    __in IXMLDOMNode* pixnMspPackage,
    __in BURN_PACKAGE* pPackage
    )
{
    HRESULT hr = S_OK;

    // @PatchCode
    hr = XmlGetAttributeEx(pixnMspPackage, L"PatchCode", &pPackage->Msp.sczPatchCode);
    ExitOnFailure(hr, "Failed to get @PatchCode.");

    // @PatchXml
    hr = XmlGetAttributeEx(pixnMspPackage, L"PatchXml", &pPackage->Msp.sczApplicabilityXml);
    ExitOnFailure(hr, "Failed to get @PatchXml.");

    // @DisplayInternalUI
    hr = XmlGetYesNoAttribute(pixnMspPackage, L"DisplayInternalUI", &pPackage->Msp.fDisplayInternalUI);
    ExitOnFailure(hr, "Failed to get @DisplayInternalUI.");

    // Read properties.
    hr = MsiEngineParsePropertiesFromXml(pixnMspPackage, &pPackage->Msp.rgProperties, &pPackage->Msp.cProperties);
    ExitOnFailure(hr, "Failed to parse properties from XML.");

LExit:

    return hr;
}
Esempio n. 2
0
DAPI_(HRESULT) BalInfoParseFromXml(
    __in BAL_INFO_BUNDLE* pBundle,
    __in IXMLDOMDocument* pixdManifest
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNode* pNode = NULL;

    hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBundleProperties", &pNode);
    if (S_OK == hr)
    {
        hr = XmlGetYesNoAttribute(pNode, L"PerMachine", &pBundle->fPerMachine);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to read bundle information per-machine.");
        }

        hr = XmlGetAttributeEx(pNode, L"DisplayName", &pBundle->sczName);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to read bundle information display name.");
        }

        hr = XmlGetAttributeEx(pNode, L"LogPathVariable", &pBundle->sczLogVariable);
        if (E_NOTFOUND != hr)
        {
            ExitOnFailure(hr, "Failed to read bundle information log path variable.");
        }
    }
    ExitOnFailure(hr, "Failed to select bundle information.");

    hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest);
    BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data.");

LExit:
    ReleaseObject(pNode);

    return hr;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 7
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;
}