Sample Code

Windows Driver Samples/ XPSDrv Driver and Filter Sample/ C++/ src/ common/ pshndlr.cpp/

/*++

Copyright (c) 2005 Microsoft Corporation

All rights reserved.

File Name:

    pshndlr.cpp

Abstract:

    Base PrintSchema Document handler class implementation.
    This class provides common PrintTicket / PrintCapabilities handling functionality.
    A class can derive from this base class to get PrintTicket/PrintCapabilities
    unspecific XML handling functionality.

    Note: The PrintSchema handler code is only intended to work with the sdtandard
    public PrintSchema keywords.

--*/


//
// Note on handling missing DOM nodes:
//
// Convert MSXML's S_FALSE to E_ELEMENT_NOT_FOUND. This allows clients to
// use the SUCCEEDED macro more effectively.
//
// E_ELEMENT_NOT_FOUND should not be propogated as an error to the
// filter pipeline or config module - treat as though the requested feature
// has not been enabled.
//

#include "precomp.h"
#include "debug.h"
#include "globals.h"
#include "xdstring.h"
#include "pshndlr.h"

using XDPrintSchema::FRAMEWORK_URI;
using XDPrintSchema::KEYWORDS_URI;
using XDPrintSchema::SCHEMA_INST_URI;
using XDPrintSchema::SCHEMA_DEF_URI;
using XDPrintSchema::PROPERTY_ELEMENT_NAME;
using XDPrintSchema::NAME_ATTRIBUTE_NAME;
using XDPrintSchema::VALUE_ELEMENT_NAME;
using XDPrintSchema::SCHEMA_TYPE;
using XDPrintSchema::SCORED_PROP_ELEMENT_NAME;
using XDPrintSchema::SCHEMA_STRING;
using XDPrintSchema::SCHEMA_INTEGER;
using XDPrintSchema::SCHEMA_DECIMAL;
using XDPrintSchema::PARAM_REF_ELEMENT_NAME;
using XDPrintSchema::PARAM_INIT_ELEMENT_NAME;
using XDPrintSchema::SCHEMA_INST_URI;

static LPCWSTR szSelectNS               = L"SelectionNamespaces";
static LPCWSTR szTmpNS                  = L"psf";
static LPCWSTR szNSSelection            = L"xmlns:%s='%s'";
static LPCWSTR szSelectLang             = L"SelectionLanguage";
static LPCWSTR szLangSection            = L"XPath";

static LPCWSTR szPTRootQuery            = L"//%s:%s";

/*++

Routine Name:

    CPSHandler::CPSHandler

Routine Description:

    CPSHandler class constructor

Arguments:

    pDOMDocument - Pointer to the DOM document representation of the PrintTicket/PrintCapabilities

Return Value:

    None
    Throws CXDException(HRESULT) on an error

--*/
CPSHandler::CPSHandler(
    _In_z_ BSTR bstrDocumentType,
    _In_ IXMLDOMDocument2 *pPrintDocument
    ) :
    m_bstrDocumentType(bstrDocumentType),
    m_pPrintDocument(pPrintDocument)
{
    ASSERTMSG(m_pPrintDocument != NULL, "NULL PrintDocument passed to PS manager.\n");

    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(m_pPrintDocument, E_PENDING)))
    {
        try
        {
            //
            // Make sure XPath selection language is set
            //
            if (SUCCEEDED(hr = m_pPrintDocument->setProperty(CComBSTR(szSelectLang), CComVariant(szLangSection))))
            {
                //
                // Construct the alias namespace string
                //
                CStringXDW cstrNamespaces;
                cstrNamespaces.Format(szNSSelection, szTmpNS, FRAMEWORK_URI);

                //
                // Specify an alias PrintSchema namespace prefix to allow us to find the real ones
                //
                if (SUCCEEDED(hr = m_pPrintDocument->setProperty(CComBSTR(szSelectNS), CComVariant(cstrNamespaces))))
                {
                    if (SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(FRAMEWORK_URI), &m_bstrFrameworkPrefix)) &&
                        SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(KEYWORDS_URI), &m_bstrKeywordsPrefix)) &&
                        SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(SCHEMA_INST_URI), &m_bstrSchemaInstPrefix)) &&
                        SUCCEEDED(hr = GetPrefixFromURI(CComBSTR(SCHEMA_DEF_URI), &m_bstrSchemaPrefix)))
                    {
                        CStringXDW cstrNSUserPrefix(L"ns0000:");
                        m_bstrUserKeywordsPrefix.Empty();
                        m_bstrUserKeywordsPrefix.Attach(cstrNSUserPrefix.AllocSysString());

                        //
                        // Restore the original namespace prefix for the PrintSchema framework
                        //
                        CComBSTR bstrOrgNamespaces;
                        CStringXDW cstrNSPrefix(m_bstrFrameworkPrefix);

                        INT iIndex = cstrNSPrefix.Find(L":");
                        if (iIndex != -1 &&
                            cstrNSPrefix.Delete(iIndex, 1) > 0)
                        {
                            CStringXDW cstrOrgNamespaces;
                            cstrOrgNamespaces.Format(szNSSelection, cstrNSPrefix, FRAMEWORK_URI);

                            hr = m_pPrintDocument->setProperty(CComBSTR(szSelectNS), CComVariant(cstrOrgNamespaces));
                        }
                        else
                        {
                             RIP("Could not create namespace prefix correctly\n");
                             hr = E_FAIL;
                        }
                    }
                }
                else
                {
                    ERR("Failed to set SelectionNamespaces.\n");
                }
            }
            else
            {
                RIP("Failed to set SelectionLanguage.\n");
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    if (FAILED(hr))
    {
        throw CXDException(hr);
    }
}

/*++

Routine Name:

    CPSHandler::~CPSHandler

Routine Description:

    CPSHandler class destructor

Arguments:

    None

Return Value:

    None

--*/
CPSHandler::~CPSHandler()
{
}

/*++

Routine Name:

    CPSHandler::DeleteNode

Routine Description:

    This routine deletes the given node from the PrintDocument

Arguments:

    pNode - Pointer to the DOM node to be deleted

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::DeleteNode(
    _In_ IXMLDOMNode* pNode
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pNode, E_POINTER)))
    {
        CComPtr<IXMLDOMNode> pParentNode(NULL);
        CComPtr<IXMLDOMNode> pDeletedNode(NULL);

        if (SUCCEEDED(hr = pNode->get_parentNode(&pParentNode)) &&
            hr != S_FALSE &&
            SUCCEEDED(hr = pParentNode->removeChild(pNode, &pDeletedNode)) &&
            pDeletedNode == NULL)
        {
            hr = E_FAIL;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::GetNode

Routine Description:

    This routine retrieves a node given an XPath query

Arguments:

    bstrNodeQuery - The XPath query for a node
    ppNode        - Pointer to an IXMLDOMNode pointer that recieves the node retrieved

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::GetNode(
    _In_z_      BSTR          bstrNodeQuery,
    _Outptr_ IXMLDOMNode** ppNode
    )
{
    //
    // We should have the PrintDocment in place
    //
    ASSERTMSG(m_pPrintDocument != NULL, "NULL PS detected whilst retrieving node.\n");

    //
    // Method which takes a query string and returns the first node that matches
    //
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppNode, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(m_pPrintDocument, E_PENDING)))
    {
        *ppNode = NULL;
        if (SysStringLen(bstrNodeQuery) == 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // Get the node from the PrintDocument
        //
        hr = m_pPrintDocument->selectSingleNode(bstrNodeQuery, ppNode);
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::DeletePrivateFeatures

Routine Description:

    This routine finds and deletes features with values defined in the
    private namespace passed in

Arguments:

    bstrPrivateNS - the private namespace

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::DeletePrivateFeatures(
    _In_z_ BSTR bstrPrivateNS
    )
{
    HRESULT hr = S_OK;

    if (SysStringLen(bstrPrivateNS) > 0)
    {
        CComBSTR bstrNSPrefix;
        if (SUCCEEDED(hr = GetPrefixFromURI(bstrPrivateNS, &bstrNSPrefix)))
        {
            //
            // Find all root feature elements in the namespace
            //
            CComPtr<IXMLDOMNodeList> pNodeList(NULL);

            CComBSTR bstrFeatureQuery(L"//");
            bstrFeatureQuery += m_bstrFrameworkPrefix;
            bstrFeatureQuery += L"Feature";

            if (SUCCEEDED(hr) &&
                SUCCEEDED(hr = m_pPrintDocument->selectNodes(bstrFeatureQuery, &pNodeList)) &&
                SUCCEEDED(hr = pNodeList->reset()))
            {
                //
                // Delete all the feature with name attributes using the private namespace
                //
                CComPtr<IXMLDOMNode> pDeleteNode(NULL);

                while (SUCCEEDED(hr) &&
                       SUCCEEDED(hr = pNodeList->nextNode(&pDeleteNode)) &&
                       hr != S_FALSE)
                {
                    CComPtr<IXMLDOMNamedNodeMap> pDeleteNodeAtts(NULL);
                    CComPtr<IXMLDOMNode>         pNameNode(NULL);
                    CComVariant                  varNameValue;

                    if (SUCCEEDED(hr = pDeleteNode->get_attributes(&pDeleteNodeAtts)) &&
                        hr != S_FALSE &&
                        SUCCEEDED(hr = pDeleteNodeAtts->getNamedItem(CComBSTR(L"name"), &pNameNode)) &&
                        hr != S_FALSE &&
                        SUCCEEDED(hr = pNameNode->get_nodeValue(&varNameValue)) &&
                        hr != S_FALSE)
                    {
                        try
                        {
                            CStringXDW cstrNameValue(varNameValue.bstrVal);

                            if (cstrNameValue.Find(bstrNSPrefix) == 0)
                            {
                                hr = DeleteNode(pDeleteNode);
                            }
                        }
                        catch (CXDException& e)
                        {
                            hr = e;
                        }
                    }

                    pDeleteNode = NULL;
                }
            }
        }
    }
    else
    {
        hr = E_INVALIDARG;
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateProperty

Routine Description:

    This routine creates a property element of the given name. Note: this
    method only creates the property element; it is up to the caller to
    set the property value

Arguments:

    bstrPropName  - The name of the property
    ppPropElement - Pointer to a IXMLDOMElement pointer that recieves the newly created Property element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateProperty(
    _In_        CONST BSTR       bstrPropName,
    _Outptr_ IXMLDOMElement** ppPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER)))
    {
        *ppPropElement = NULL;

        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        CComBSTR bstrTagName(m_bstrFrameworkPrefix);
        bstrTagName += PROPERTY_ELEMENT_NAME;

        CComBSTR bstrAttribName(szTmpNS);
        bstrAttribName += L":";
        bstrAttribName += bstrPropName;

        hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppPropElement);

        if (SUCCEEDED(hr))
        {
            if (*ppPropElement != NULL)
            {
                hr = CreateXMLAttribute(*ppPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName );
            }
            else
            {
                hr = E_FAIL;
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateProperty

Routine Description:

    This routine creates a property element of the given name.

Arguments:

    bstrPropName  - The name of the property to be created
    bstrType      - The type of the property value (integer, string etc.)
    bstrValue     - The value of the property
    ppPropElement - Pointer to an IXMLDOMElement pointer that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST BSTR       bstrType,
    _In_        CONST BSTR       bstrValue,
    _Outptr_ IXMLDOMElement** ppPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0 ||
            SysStringLen(bstrType) <= 0 ||
            SysStringLen(bstrValue) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // Create the scored property and value node
        //
        if (SUCCEEDED(hr = CreateProperty(bstrPropName, ppPropElement)))
        {
            CComPtr<IXMLDOMElement> pValue(NULL);

            CComBSTR bstrValueElement(m_bstrFrameworkPrefix);
            bstrValueElement += VALUE_ELEMENT_NAME;

            CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix);
            bstrTypeAttribName += SCHEMA_TYPE;

            CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix);
            bstrTypeAttribValue += bstrType;

            hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue);

            if(SUCCEEDED(hr))
            {
                if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) &&
                    SUCCEEDED(hr = pValue->put_text(bstrValue)))
                {
                    hr = (*ppPropElement)->appendChild(pValue, NULL);
                }
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateFWProperty

Routine Description:

    This routine creates a property element of the given name. Note: this
    method only creates the property element; it is up to the caller to
    set the property value

Arguments:

    bstrPropName  - The name of the property
    ppPropElement - Pointer to a IXMLDOMElement pointer that recieves the newly created Property element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateFWProperty(
    _In_        CONST BSTR       bstrPropName,
    _Outptr_ IXMLDOMElement** ppPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER)))
    {
        *ppPropElement = NULL;

        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        CComBSTR bstrTagName(m_bstrFrameworkPrefix);
        bstrTagName += PROPERTY_ELEMENT_NAME;

        CComBSTR bstrAttribName(m_bstrFrameworkPrefix);
        bstrAttribName += bstrPropName;

        hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppPropElement);

        if (SUCCEEDED(hr))
        {
            if (*ppPropElement != NULL)
            {
                hr = CreateXMLAttribute(*ppPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName );
            }
            else
            {
                hr = E_FAIL;
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateFWProperty

Routine Description:

    This routine creates a property element of the given name.

Arguments:

    bstrPropName  - The name of the property to be created
    bstrType      - The type of the property value (integer, string etc.)
    bstrValue     - The value of the property
    ppPropElement - Pointer to an IXMLDOMElement pointer that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateFWProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST BSTR       bstrType,
    _In_        CONST BSTR       bstrValue,
    _Outptr_ IXMLDOMElement** ppPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0 ||
            SysStringLen(bstrType) <= 0 ||
            SysStringLen(bstrValue) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // Create the scored property and value node
        //
        if (SUCCEEDED(hr = CreateFWProperty(bstrPropName, ppPropElement)))
        {
            CComPtr<IXMLDOMElement> pValue(NULL);

            CComBSTR bstrValueElement(m_bstrFrameworkPrefix);
            bstrValueElement += VALUE_ELEMENT_NAME;

            CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix);
            bstrTypeAttribName += SCHEMA_TYPE;

            CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix);
            bstrTypeAttribValue += bstrType;

            hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue);

            if(SUCCEEDED(hr))
            {
                if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) &&
                    SUCCEEDED(hr = pValue->put_text(bstrValue)))
                {
                    hr = (*ppPropElement)->appendChild(pValue, NULL);
                }
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property. Note: this does not intialise
    the scored property value - this is the responsibility of the caller

Arguments:

    bstrPropName        - The name of the property element to be created
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        *ppScoredPropElement = NULL;

        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        CComBSTR bstrTagName(m_bstrFrameworkPrefix);
        bstrTagName += SCORED_PROP_ELEMENT_NAME;

        CComBSTR bstrAttribName(m_bstrKeywordsPrefix);
        bstrAttribName += bstrPropName;

        hr = CreateXMLElement(bstrTagName, FRAMEWORK_URI, ppScoredPropElement);

        if (SUCCEEDED(hr))
        {
            if (*ppScoredPropElement != NULL)
            {
                hr = CreateXMLAttribute(*ppScoredPropElement, NAME_ATTRIBUTE_NAME, NULL, bstrAttribName );
            }
            else
            {
                hr = E_FAIL;
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property.

Arguments:

    bstrPropName        - The name of the property element to be created
    bstrType            - The type of the value to be created (integer, string etc.)
    bstrValue           - The value to be set as a string
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST BSTR       bstrType,
    _In_        CONST BSTR       bstrValue,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0 ||
            SysStringLen(bstrType) <= 0 ||
            SysStringLen(bstrValue) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        //
        // Create the scored property and value node
        //
        if (SUCCEEDED(hr = CreateScoredProperty(bstrPropName, ppScoredPropElement)))
        {
            CComPtr<IXMLDOMElement> pValue(NULL);

            CComBSTR bstrValueElement(m_bstrFrameworkPrefix);
            bstrValueElement += VALUE_ELEMENT_NAME;

            CComBSTR bstrTypeAttribName(m_bstrSchemaInstPrefix);
            bstrTypeAttribName += SCHEMA_TYPE;

            CComBSTR bstrTypeAttribValue(m_bstrSchemaPrefix);
            bstrTypeAttribValue += bstrType;

            hr = CreateXMLElement(bstrValueElement, FRAMEWORK_URI, &pValue);

            if(SUCCEEDED(hr))
            {
                if (SUCCEEDED(hr = CreateXMLAttribute(pValue, bstrTypeAttribName, SCHEMA_INST_URI, bstrTypeAttribValue )) &&
                    SUCCEEDED(hr = pValue->put_text(bstrValue)))
                {
                    hr = (*ppScoredPropElement)->appendChild(pValue, NULL);
                }
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property of type string.

Arguments:

    bstrPropName        - The name of the property element to be created
    bstrValue           - The string value to be set
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST BSTR       bstrValue,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) > 0 &&
            SysStringLen(bstrValue) > 0)
        {
            //
            // Create the scored property and value node
            //
            hr = CreateScoredProperty(bstrPropName, CComBSTR(SCHEMA_STRING), bstrValue, ppScoredPropElement);
        }
        else
        {
            hr = E_INVALIDARG;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property of type INT.

Arguments:

    bstrPropName        - The name of the property element to be created
    intValue            - The INT value to be set
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST INT        intValue,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        try
        {
            //
            // Construct the value string
            //
            CStringXDW cstrValue;
            cstrValue.Format(L"%i", intValue);

            //
            // Create the scored property and value node
            //
            hr = CreateScoredProperty(bstrPropName,
                                      CComBSTR(SCHEMA_INTEGER),
                                      CComBSTR(cstrValue.AllocSysString()),
                                      ppScoredPropElement);
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property of type REAL.

Arguments:

    bstrPropName        - The name of the property element to be created
    realValue           - The REAL value to be set
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        CONST REAL       realValue,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        try
        {
            //
            // Construct the value string
            //
            CStringXDW cstrValue;
            cstrValue.Format(L"%.2f", realValue);

            //
            // Create the scored property and value node
            //
            hr = CreateScoredProperty(bstrPropName,
                                      CComBSTR(SCHEMA_DECIMAL),
                                      CComBSTR(cstrValue.AllocSysString()),
                                      ppScoredPropElement);
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::QueryNode

Routine Description:

    This routine checks for the existence of a node given the XPath
    query passed in

Arguments:

    bstrQuery - The XPath query defining the node or nodes to be located

Return Value:

    HRESULT
    S_OK                - On success
    E_ELEMENT_NOT_FOUND - If node does not exist
    E_*                 - On error

--*/
HRESULT
CPSHandler::QueryNode(
    _In_z_ BSTR  bstrQuery
    )
{
    HRESULT hr = S_OK;

    //
    // Validate input parameters
    //
    if (SysStringLen(bstrQuery) > 0)
    {
        CComPtr<IXMLDOMNode> pNode(NULL);

        hr = GetNode(bstrQuery, &pNode);
    }
    else
    {
        hr = E_INVALIDARG;
    }

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

    ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
    return hr;
}

/*++

Routine Name:

    CPSHandler::QueryNodeValue

Routine Description:

    This routine locates the node specified by the XPath query passed in and
    returns the value of the "value" attribute as a string.

Arguments:

    bstrQuery   - The XPath query locating the node to retrieve the value for
    pbstrOption - Pointer to a BSTR to recieve the value string

Return Value:

    HRESULT
    S_OK                - On success
    E_ELEMENT_NOT_FOUND - If node does not exist
    E_*                 - On error

--*/
HRESULT
CPSHandler::QueryNodeValue(
    _In_z_      BSTR  bstrQuery,
    _Outptr_ BSTR* pbstrValue
    )
{
    HRESULT hr = S_OK;

    //
    // Validate input parameters
    //
    if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER)))
    {
        *pbstrValue = NULL;

        if (SysStringLen(bstrQuery) > 0)
        {
            hr = GetNodeValue(bstrQuery, pbstrValue);
        }
        else
        {
            hr = E_INVALIDARG;
        }
    }

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

    ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
    return hr;
}

/*++

Routine Name:

    CPSHandler::QueryNodeValue

Routine Description:

    This routine locates the node specified by the XPath query passed in and
    returns the value of the "value" attribute as an INT.

Arguments:

    bstrQuery - The XPath query locating the node to retrieve the value for
    pValue    - Pointer to an INT to recieve the value

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::QueryNodeValue(
    _In_z_ BSTR bstrQuery,
    _Out_  INT* pValue
    )
{
    HRESULT hr = S_OK;

    CComBSTR bstrValue;
    if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER)))
    {
        if (SysStringLen(bstrQuery) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr) &&
        SUCCEEDED(hr = QueryNodeValue(bstrQuery, &bstrValue)))
    {
        *pValue = static_cast<INT>(_wtoi(bstrValue));
    }

    ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
    return hr;
}

/*++

Routine Name:

    CPSHandler::QueryNodeValue

Routine Description:

    This routine locates the node specified by the XPath query passed in and
    returns the value of the "value" attribute as a REAL.

Arguments:

    bstrQuery - The XPath query locating the node to retrieve the value for
    pValue    - Pointer to a REAL to recieve the value

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::QueryNodeValue(
    _In_z_ BSTR bstrQuery,
    _Out_  REAL* pValue
    )
{
    HRESULT hr = S_OK;

    CComBSTR bstrValue;
    if (SUCCEEDED(hr = CHECK_POINTER(pValue, E_POINTER)))
    {
        if (SysStringLen(bstrQuery) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr) &&
        SUCCEEDED(hr = QueryNodeValue(bstrQuery, &bstrValue)))
    {
        *pValue = static_cast<REAL>(_wtof(bstrValue));
    }

    ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
    return hr;
}

/*++

Routine Name:

    CPSHandler::GetNodeValue

Routine Description:

    This routine retrieves the value of a node given the XPath query to the node

Arguments:

    bstrNodeQuery - The XPath query for the node from which the value should be retrieved
    pbstrValue    - Pointer to ta BSTR that recieves the value of the node

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

Note:

    The annotation for pbstrValue is intended to express that the BSTR may
    be NULL when S_FALSE is returned, but not when S_OK is returned.
    
    In any case, when a failure HRESULT is returned, all out parameter
    annotations are ignored.

--*/
HRESULT
CPSHandler::GetNodeValue(
    _In_z_      BSTR  bstrNodeQuery,
    _Inout_ _At_(*pbstrValue, _Pre_maybenull_)
    _When_(return == S_FALSE, _At_(*pbstrValue, _Post_maybenull_))
    _When_(return != S_FALSE, _At_(*pbstrValue, _Post_valid_))
                BSTR* pbstrValue
    )
{
    HRESULT hr = S_OK;

    CComPtr<IXMLDOMNode> pFeatureNode(NULL);

    if (SUCCEEDED(hr = CHECK_POINTER(pbstrValue, E_POINTER)))
    {
        SysFreeString(*pbstrValue);
        *pbstrValue = NULL;
        if (SysStringLen(bstrNodeQuery) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr) &&
        SUCCEEDED(hr = GetNode(bstrNodeQuery, &pFeatureNode)) &&
        hr != S_FALSE)
    {
        //
        // Scored properties can either be defined as "Value" or "ParameterRef"
        // Find out which of these applies to this property and handle accordingly
        //
        CComBSTR bstrValue(m_bstrFrameworkPrefix);
        bstrValue += VALUE_ELEMENT_NAME;

        CComBSTR bstrParamRef(m_bstrFrameworkPrefix);
        bstrParamRef += PARAM_REF_ELEMENT_NAME;

        CComVariant varValue;

        CComPtr<IXMLDOMNode> pPropertyNode(NULL);
        if (SUCCEEDED(hr = pFeatureNode->selectSingleNode(bstrValue, &pPropertyNode)) &&
            hr != S_FALSE)
        {
            //
            // Value node. Just retrieve the node value
            //
            hr = pPropertyNode->get_nodeTypedValue(&varValue);
        }
        else if (SUCCEEDED(hr = pFeatureNode->selectSingleNode(bstrParamRef, &pPropertyNode)) &&
                 hr != S_FALSE)
        {
            //
            // Property defined by parameter ref. Retrieve the name and look up the value
            // from the parameter init elements
            //
            CComPtr<IXMLDOMNodeList> pParamInitList(NULL);
            CComBSTR bstrParamRefValue;

            if (SUCCEEDED(hr = GetAttributeValue(pPropertyNode, CComBSTR(NAME_ATTRIBUTE_NAME), &bstrParamRefValue)) &&
                hr != S_FALSE &&
                SUCCEEDED(hr = GetNodes(CComBSTR(PARAM_INIT_ELEMENT_NAME), &pParamInitList)) &&
                hr != S_FALSE)
            {
                CComBSTR bstrParamInit;
                CComPtr<IXMLDOMNode> pInitNode(NULL);

                hr = pParamInitList->reset();

                while (SUCCEEDED(hr) &&
                       hr != S_FALSE)
                {
                    if (SUCCEEDED(hr = pParamInitList->nextNode(&pInitNode)) && hr != S_FALSE && pInitNode != NULL)
                    {
                        hr = GetAttributeValue(pInitNode, CComBSTR(NAME_ATTRIBUTE_NAME), &bstrParamInit);
                        if (SUCCEEDED(hr) && bstrParamInit == bstrParamRefValue)
                        {
                            hr = pInitNode->get_nodeTypedValue(&varValue);
                            break;
                        }
                    }


                    //
                    // Release the node and name before getting the next
                    //
                    pInitNode = NULL;
                    bstrParamInit.Empty();
                }
            }
        }

        if (SUCCEEDED(hr) &&
            hr != S_FALSE &&
            SysStringLen(varValue.bstrVal) > 0)
        {
            *pbstrValue = ::SysAllocString(varValue.bstrVal);

            if (*pbstrValue == NULL)
            {
                hr = E_OUTOFMEMORY;
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::GetAttributeValue

Routine Description:

    This routine retrieves the value of a named attribute as a string from a DOM node

Arguments:

    pNode          - Pointer to the DOM node to retrieve the attribute value from
    bstrAttribName - The name of the attribute
    pbstrResult    - Pointer to a BSTR that recieves the attribute value

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::GetAttributeValue(
    _In_            CONST IXMLDOMNode* pNode,
    _In_z_          BSTR               bstrAttribName,
    _Outptr_result_maybenull_ BSTR*              pbstrResult
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pNode, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pbstrResult, E_POINTER)))
    {
        if (SysStringLen(bstrAttribName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        *pbstrResult = NULL;

        //
        // Map the associated attributes and get the string result
        //
        CComPtr<IXMLDOMNamedNodeMap> pIXMLDOMNamedNodeMap(NULL);
        CComPtr<IXMLDOMNode>         pSubNode(NULL);

        if (SUCCEEDED(hr = const_cast<IXMLDOMNode*>(pNode)->get_attributes(&pIXMLDOMNamedNodeMap)) &&
            hr != S_FALSE &&
            SUCCEEDED(hr = pIXMLDOMNamedNodeMap->getNamedItem(bstrAttribName, &pSubNode)) &&
            hr != S_FALSE)
        {
            hr = pSubNode->get_text(pbstrResult);
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::GetNodes

Routine Description:

    This routine returns a list of all the nodes in the PrintTicket with the
    specified element name

Arguments:

    ppParamInit - Pointer to an IXMLDOMNodeList pointer that recieves the node list

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::GetNodes(
    _In_        BSTR              bstrElementName,
    _Outptr_ IXMLDOMNodeList** ppNodeList
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(ppNodeList, E_POINTER)))
    {
        if (SysStringLen(bstrElementName) > 0)
        {
            *ppNodeList = NULL;

            //
            // Retrieve all psf:ParameterInit nodes in the PrintTicket
            //
            CComBSTR bstrParamInitQuery(L"//");
            bstrParamInitQuery += m_bstrFrameworkPrefix;
            bstrParamInitQuery += bstrElementName;

            hr = m_pPrintDocument->selectNodes(bstrParamInitQuery, ppNodeList);
        }
        else
        {
            hr = E_FAIL;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::CreateScoredProperty

Routine Description:

    This routine creates a scored property using the value node passed in.

Arguments:

    bstrPropName        - The name of the property element to be created
    pValueNode          - Pointer to the IXMLDOMNode that represents the scored property value
    ppScoredPropElement - Pointer to an IXMLDOMElement that recieves the new element

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::CreateScoredProperty(
    _In_        CONST BSTR       bstrPropName,
    _In_        IXMLDOMNode*     pValueNode,
    _Outptr_ IXMLDOMElement** ppScoredPropElement
    )
{
    HRESULT hr = S_OK;

    //
    // Validate parameters then create the scored property and value node
    //
    if (SUCCEEDED(hr = CHECK_POINTER(pValueNode, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(ppScoredPropElement, E_POINTER)))
    {
        if (SysStringLen(bstrPropName) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr) &&
        SUCCEEDED(hr = CreateScoredProperty(bstrPropName, ppScoredPropElement)))
    {
        hr = (*ppScoredPropElement)->appendChild(pValueNode, NULL);
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CPSHandler::GetPrefixFromURI

Routine Description:

    Obtains the Prefix associated with a Namespace URI from an XML PrintSchema Document.

Arguments:

    bstrNamespaceURI - Namespace URI to be used in look-up.
    bstrNamespacePrefix - Namespace Prefix to be returned.

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CPSHandler::GetPrefixFromURI(
    _In_z_                    BSTR  bstrNamespaceURI,
    _Outptr_result_maybenull_ BSTR* bstrNamespacePrefix
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(bstrNamespacePrefix, E_POINTER)))
    {
        if (SysStringLen(bstrNamespaceURI) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        *bstrNamespacePrefix = NULL;

        try
        {
            //
            // Construct the Root Query string
            //
            CStringXDW cstrRootQuery;
            cstrRootQuery.Format(szPTRootQuery, szTmpNS, m_bstrDocumentType);

            //
            // Find the PrintSchema element so we can retrieve the private namespace prefix
            //
            CComPtr<IXMLDOMNode>         pPTNode(NULL);
            CComPtr<IXMLDOMNamedNodeMap> pPTAtts(NULL);

            if (SUCCEEDED(hr = GetNode(CComBSTR(cstrRootQuery), &pPTNode)) &&
                hr != S_FALSE &&
                SUCCEEDED(hr = pPTNode->get_attributes(&pPTAtts)) &&
                SUCCEEDED(hr = pPTAtts->reset()))
            {
                //
                // Iterate over all attributes and match the node value against
                // the namespace URI
                //
                BOOL bMatched = FALSE;
                CComPtr<IXMLDOMNode> pAttNode(NULL);

                while (SUCCEEDED(hr) &&
                       !bMatched &&
                       SUCCEEDED(hr = pPTAtts->nextNode(&pAttNode)) &&
                       hr != S_FALSE)
                {
                    CComVariant varValue;

                    if (SUCCEEDED(hr = pAttNode->get_nodeValue(&varValue)))
                    {
                        if (CComBSTR(varValue.bstrVal) == bstrNamespaceURI)
                        {
                            bMatched = TRUE;
                        }
                    }

                    if (!bMatched)
                    {
                        //
                        // No match - free the attribute node before retrieving the next
                        //
                        pAttNode = NULL;
                    }
                }

                if (SUCCEEDED(hr) &&
                    bMatched)
                {
                    //
                    // If we match then get the node name and strip xmlns: to derive
                    // the private namespace prefix
                    //
                    CStringXDW cstrNSPrefix;
                    CComBSTR bstrNodeName;

                    if (SUCCEEDED(hr = pAttNode->get_nodeName(&bstrNodeName)))
                    {
                         cstrNSPrefix = bstrNodeName;
                         CStringXDW cstrXMLNS(L"xmlns:");

                         if (cstrNSPrefix.Find(cstrXMLNS) != 0 ||
                             cstrNSPrefix.Delete(0, cstrXMLNS.GetLength()) <= 0)
                         {
                             ERR("Could not create private namespace prefix correctly\n");

                             hr = E_FAIL;
                         }
                         else
                         {
                             cstrNSPrefix += L":";

                             SysFreeString(*bstrNamespacePrefix);
                             *bstrNamespacePrefix = cstrNSPrefix.AllocSysString();
                         }
                    }
                }
            }
            else
            {
                ERR("Failed to find the PC root element.\n");
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

HRESULT
CPSHandler::CreateXMLAttribute(
    _Inout_    IXMLDOMElement *pTarget,
    _In_       PCWSTR pszName,
    _In_opt_   PCWSTR pszTargetURI,
    _In_       PCWSTR pszValue
    )
/*++

Routine Description:

    This routine adds a new attribute to the given XML element.  The URI
    parameter must be present, but may be an empty string.

    If this routine fails, the document being constructed should be
    considered invalid, and be thrown out in its entirity.

    The newly created attribute will be appended to the list of attributes on the element

Arguments:

    pTarget - the element to which the attribute is to be added
    pszName - the name of the attribtue
    pszTargetURI - the URI in which the attribute should reside
    pszValue - the value to put in the attribute

Returns:

    S_OK on success, else
    E_* on failure

--*/
{
    HRESULT hr = S_OK;
    CComPtr<IXMLDOMAttribute> pCurrentAttr;
    CComPtr<IXMLDOMNode> pCurrentNode;

    if( !( pTarget && pszName && pszValue ) )
    {
        hr = E_INVALIDARG;
    }

    if(SUCCEEDED(hr))
    {
        VARIANT type;
        VariantInit( &type );
        V_VT(&type) = VT_I4;
        V_I4(&type) = NODE_ATTRIBUTE;

        hr = m_pPrintDocument->createNode(type, const_cast<BSTR>(pszName), const_cast<BSTR>(pszTargetURI), &pCurrentNode);

        VariantClear( &type );
    }

    if( SUCCEEDED(hr) )
    {
        hr = pCurrentNode->QueryInterface( IID_IXMLDOMAttribute, (void**)&pCurrentAttr );
    }

    if( SUCCEEDED(hr) )
    {
        VARIANT attrVal;
        BSTR bstrValue = SysAllocString(pszValue);

        if( bstrValue )
        {
            VariantInit(&attrVal);
            V_VT(&attrVal) = VT_BSTR;
            V_BSTR(&attrVal) = bstrValue;
            hr = pCurrentAttr->put_value(attrVal);

            if( SUCCEEDED(hr) )
            {
                hr = VariantClear(&attrVal);
            }
            else
            {
                VariantClear(&attrVal);
            }
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if( SUCCEEDED(hr) )
    {
        hr = pTarget->setAttributeNode( pCurrentAttr, NULL );
    }

    return hr;
}

HRESULT
CPSHandler::CreateXMLElement(
    _In_       PCWSTR pszName,
    _In_       PCWSTR pszTargetURI,
    _Out_opt_  IXMLDOMElement **ppEl
    )
/*++

Routine Description:

    Create a new DOM element using the given QName and URI.  Implemented using DOMDocument->CreateNode.

Arguments:

    pszName - The QName of the element to be created
    pszTargetUri - The namespace in which the created element lives.  The
        caller does not have control over the prefix... just the URI
    ppEl - If the caller needs a pointer to the newly created node, this should
        be a non-null

Return Value:

    S_OK on success,
    E_* on failure.  Common values that would be expected
        include E_OUTOFMEMORY, and E_INVALIDARG.

--*/
{
    HRESULT hr = S_OK;
    CComPtr<IXMLDOMNode> pCurrentNode;

    if( !( pszName && pszTargetURI ) )
    {
        hr = E_INVALIDARG;
    }

    if(SUCCEEDED(hr))
    {
        VARIANT type;
        VariantInit( &type );
        V_VT(&type) = VT_I4;
        V_I4(&type) = NODE_ELEMENT;
        hr = m_pPrintDocument->createNode( type, const_cast<BSTR>(pszName), const_cast<BSTR>(pszTargetURI), &pCurrentNode );
        VariantClear( &type );
    }

    //
    // Only give the client back the new value element if we succeed.
    //
    if( SUCCEEDED(hr) && ppEl )
    {
        hr = pCurrentNode->QueryInterface( IID_IXMLDOMElement, (void**)ppEl );
    }

    return hr;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS