/*******************************************************************************
*
*  (C) COPYRIGHT MICROSOFT CORP., 1998
*
*  TITLE:       IPropItm.Cpp
*
*  VERSION:     2.0
*
*  AUTHOR:      ReedB
*
*  DATE:        19 Feb, 1998
*
*  DESCRIPTION:
*   Implementation of WIA item class server properties.
*
*******************************************************************************/
#include "precomp.h"
#include "stiexe.h"

#include <regstr.h>
#include <wiamindr.h>
// #include <wiadbg.h>

#include "wiapsc.h"
#include "helpers.h"

//
// Strings used to access the registry. REGSTR_* string constants can be
// found in sdk\inc\regstr.h
//

TCHAR g_szREGSTR_PATH_WIA[] = REGSTR_PATH_SETUP TEXT("\\WIA");

/*******************************************************************************
*
*  ReadMultiple
*  WriteMultiple
*  ReadPropertyNames
*  Enum
*  GetPropertyAttributes
*  GetCount
*
*  DESCRIPTION:
*   IWiaPropertyStorage methods.
*
*  PARAMETERS:
*
*******************************************************************************/

/**************************************************************************\
* CWiaItem::ReadMultiple
*
*   This method reads the specified number of properties from the item's
*   current value property storage.  This method conforms to that standard
*   OLE IPropertyStorage::ReadMultiple method.
*
* Arguments:
*
*    cpspec             -   Number of properties to read.
*    rgpspec            -   Array of PropSpec's specifying which properties
*                           are to be read.
*    rgpropvar          -   Array where the property values will be copied
*                           to.
*
* Arguments:
*
*    cpspec
*    rgpspec
*    rgpropvar
*
* Return Value:
*
*    status
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::ReadMultiple(
    ULONG cpspec,
    const PROPSPEC __RPC_FAR rgpspec[],
    PROPVARIANT __RPC_FAR rgpropvar[])
{
    DBG_FN(CWiaItem::ReadMultiple);
    HRESULT  hr;
    LONG     lFlags = 0;

    //
    // Corresponding driver item must be valid to talk with hardware.
    //

    hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
    if (FAILED(hr)) {
        return hr;
    }

    //
    // rgpropvar must be valid
    //

    if (IsBadWritePtr(rgpropvar, sizeof(PROPVARIANT) * cpspec)) {
        DBG_ERR(("CWiaItem::ReadMultiple, last parameter (rgpropvar) is invalid"));
        return E_INVALIDARG;
    }

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {

        //
        //  Check whether the properties being read are the WIA Managed properties.
        //  If they are, there is still no need to initialize the item.
        //

        if (AreWiaInitializedProps(cpspec, (PROPSPEC*) rgpspec)) {
            return (m_pPropStg->CurStg())->ReadMultiple(cpspec, rgpspec, rgpropvar);
        }

        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::ReadMultiple, InitLazyProps failed"));
            return hr;
        }
    }

    //
    // Check whether the properties requested are all cacheable
    //

    hr = (m_pPropStg->AccessStg())->ReadMultiple(cpspec, rgpspec, rgpropvar);
    if (FAILED(hr)) {

        ReportReadWriteMultipleError(hr, "CWiaItem::ReadMultiple", NULL, TRUE, cpspec, rgpspec);

        //
        // Property attributes are not required absolutely, continue without it.
        //

    } else {

        for (ULONG i = 0; i < cpspec; i++) {

            //
            // The client requests a property not read yet or non-cacheable
            //

            if ((rgpropvar[i].vt == VT_UI4) &&
                (! (rgpropvar[i].lVal & WIA_PROP_CACHEABLE))) {
                break;
            }
        }

        //
        // Clear the access flags from the rgpropvar
        //

        FreePropVariantArray(cpspec, rgpropvar);

        //
        // If all the properties are cacheable, then take the quick path
        //

        if (i == cpspec) {

            hr = (m_pPropStg->CurStg())->ReadMultiple(cpspec, rgpspec, rgpropvar);

            if (hr == S_OK) {

                //
                //  Check whether all the properties are retrieved correctly
                //  some properties might not have been read from the storage
                //

                for (ULONG i = 0; i < cpspec; i++) {

                    if (rgpropvar[i].vt == VT_EMPTY) {
                        break;
                    }
                }

                if (i == cpspec) {

                    //
                    // All the properties requested are found in cache
                    //

                    return (hr);
                } else {

                    FreePropVariantArray(cpspec, rgpropvar);
                }
            }

        }

    }

    if (SUCCEEDED(hr)) {

        //
        //  Make sure all PropSpecs are using PropID's.  This is so that
        //  drivers only have to deal with PropID's.  If some of the
        //  PropSpecs are using string names, then convert them.
        //

        PROPSPEC *pPropSpec = NULL;
        hr = m_pPropStg->NamesToPropIDs(cpspec, (PROPSPEC*) rgpspec, &pPropSpec);
        if (SUCCEEDED(hr)) {

            //
            // Give device mini driver a chance to update the device properties.
            //
            {
                LOCK_WIA_DEVICE _LWD(this, &hr);

                if(SUCCEEDED(hr)) {
                    hr = m_pActiveDevice->m_DrvWrapper.WIA_drvReadItemProperties((BYTE*)this,
                        lFlags,
                        cpspec,
                        (pPropSpec ? pPropSpec : rgpspec),
                        &m_lLastDevErrVal);
                }
            }

            if (pPropSpec) {
                LocalFree(pPropSpec);
                pPropSpec = NULL;
            }
        }

        if (SUCCEEDED(hr)) {
            hr = (m_pPropStg->CurStg())->ReadMultiple(cpspec, rgpspec, rgpropvar);
            if (FAILED(hr)) {
                ReportReadWriteMultipleError(hr,
                                             "CWiaItem::ReadMultiple",
                                             NULL,
                                             TRUE,
                                             cpspec,
                                             rgpspec);
            }
        }
    }

    return hr;
}

/**************************************************************************\
* CWiaItem::ReadPropertyNames
*
*   Returns the string name of the specified properties if they exist.
*   This conforms to the standard OLE IPropertyStorage::ReadPropertyNames
*   method.
*
* Arguments:
*
*   pstmProp - Pointer to property stream.
*
* Return Value:
*
*   Status
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::ReadPropertyNames(
    ULONG cpropid,
    const PROPID __RPC_FAR rgpropid[],
    LPOLESTR __RPC_FAR rglpwstrName[])
{
    DBG_FN(CWiaItem::ReadPropertyNames);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::ReadPropertyNames, InitLazyProps failed"));
            return hr;
        }
    }

   return (m_pPropStg->CurStg())->ReadPropertyNames(cpropid,rgpropid,rglpwstrName);
}

/**************************************************************************\
* CWiaItem::WritePropertyNames
*
*   Returns the string name of the specified properties if they exist.
*   This conforms to the standard OLE IPropertyStorage::ReadPropertyNames
*   method.
*
* Arguments:
*
*   pstmProp - Pointer to property stream.
*
* Return Value:
*
*   Status
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::WritePropertyNames(
    ULONG           cpropid,
    const PROPID    rgpropid[],
    const LPOLESTR  rglpwstrName[])
{
    DBG_FN(CWiaItem::WritePropertyNames);
    PROPVARIANT *pv;
    PROPSPEC    *pspec;
    ULONG       index;
    HRESULT     hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::WritePropertyNames, InitLazyProps failed"));
            return hr;
        }
    }

    pv = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpropid);
    if (!pv) {
        DBG_ERR(("CWiaItem::WritePropertyNames, Out of memory"));
        return E_OUTOFMEMORY;
    }

    pspec = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * cpropid);
    if (!pspec) {
        DBG_ERR(("CWiaItem::WritePropertyNames, Out of memory"));
        LocalFree(pv);
        return E_OUTOFMEMORY;
    }

    //
    //  Put PROPIDs into the PROPSPEC array.
    //

    for (index = 0; index < cpropid; index++) {
        pspec[index].ulKind = PRSPEC_PROPID;
        pspec[index].propid = rgpropid[index];
    }

    hr = (m_pPropStg->AccessStg())->ReadMultiple(cpropid,
                                                 pspec,
                                                 pv);
    if (SUCCEEDED(hr)) {

        //
        //  Make sure the properties are App. written properties.  If a valid
        //  access flag for a property exists, then it was written by the
        //  driver and not the App, so exit.
        //

        for (index = 0; index < cpropid; index++) {
            if (pv[index].vt != VT_EMPTY) {
                DBG_ERR(("CWiaItem::WritePropertyNames, not allowed to write prop: %d.",rgpropid[index]));
                hr = E_ACCESSDENIED;
                break;
            }
        }

        if (SUCCEEDED(hr)) {
            hr = (m_pPropStg->CurStg())->WritePropertyNames(cpropid,
                                                            rgpropid,
                                                            rglpwstrName);
            if (FAILED(hr)) {
                DBG_ERR(("CWiaItem::WritePropertyNames, WritePropertyNames failed"));
            }
        }
    } else {
        DBG_ERR(("CWiaItem::WritePropertyNames, Reading Access values failed"));
    }

    LocalFree(pspec);
    LocalFree(pv);
    return hr;
}

/**************************************************************************\
* CWiaItem::Enum
*
*   Returns a IEnumSTATPROPSTG enumerator over the current value property
*   storage.  Conforms to the standard OLE IPRopertyStorage::Enum method.
*
* Arguments:
*
*   pstmProp - Pointer to property stream.
*
* Return Value:
*
*   Status
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::Enum(
   IEnumSTATPROPSTG __RPC_FAR *__RPC_FAR *ppenum)
{
    DBG_FN(CWiaItem::Enum);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::Enum, InitLazyProps failed"));
            return hr;
        }
    }

    return (m_pPropStg->CurStg())->Enum(ppenum);
}

/**************************************************************************\
* CWiaItem::WriteMultiple
*
*   This method writes the specified number of properties into the item's
*   property storage.  Validation will be performed on those property
*   values. The properties will be restored to their old (valid) values
*   if validation fails.
*
* Arguments:
*
*    cpspec             -   Number of properties to write.
*    rgpspec            -   Array of PropSpec's specifying which properties
*                           are to be written.
*    rgpropvar          -   Array containing values that the properties
*                           will be set to.
*    propidNameFirst    -   Minimum value for property identifiers when
*                           they don't exist and must be allocated.
*
* Return Value:
*
*   Status              -   S_OK if writes and validation succeeded.
*                           E_INVALIDARG if validation failed due to an
*                           incorrect property value.
*                           Other error returns are from
*                           ValidateWiaDrvItemAccess, CheckPropertyAccess,
*                           CreatePropertyStorage and CopyProperties.
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::WriteMultiple(
    ULONG                        cpspec,
    const PROPSPEC __RPC_FAR     rgpspec[],
    const PROPVARIANT __RPC_FAR  rgpropvar[],
    PROPID                       propidNameFirst)
{
    DBG_FN(CWiaItem::WriteMultiple);
    HRESULT hr;

    //
    // Corresponding driver item must be valid.
    //

    hr = ValidateWiaDrvItemAccess(m_pWiaDrvItem);
    if (FAILED(hr)) {
        DBG_ERR(("CWiaItem::WriteMultiple, ValidateDrvItemAccess failed"));
        return hr;
    }

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::WriteMultiple, InitLazyProps failed"));
            return hr;
        }
    }

    //
    // there is no point in going further if there are no properties to
    // write
    //
    if(cpspec == 0) {
        return S_OK;
    }

    //
    // We do not want to fail users who erroneousely attempt to write
    // to write to read-only properties IF that the values they
    // are trying to write are the same as current values. To achive
    // this, we first current values of the properties they want to
    // write:
    //

    PROPVARIANT *curVals = (PROPVARIANT *) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
    PROPSPEC *newSpecs = (PROPSPEC *) LocalAlloc(LPTR, sizeof(PROPSPEC) * cpspec);
    PROPVARIANT *newVals = (PROPVARIANT *) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
    ULONG newcpspec = cpspec;

    if(curVals == NULL || newSpecs == NULL || newVals == NULL) {
        DBG_ERR(("CWiaItem::WriteMultiple, failed to allocate memory"));
        goto Cleanup;
    }

    CopyMemory(newSpecs, rgpspec, sizeof(PROPSPEC) * cpspec);
    CopyMemory(newVals, rgpropvar, sizeof(PROPVARIANT) * cpspec);

    memset(curVals, 0, sizeof(PROPVARIANT) * cpspec);
    hr = m_pPropStg->CurStg()->ReadMultiple(cpspec, rgpspec, curVals);
    if(SUCCEEDED(hr)) {
        //
        // Now for every property value they want to write we check if
        // it is the same as the current value
        //

        ULONG   ulNewEltIndex = 0;
        for(ULONG i = 0; i < cpspec; i++) {

            if(curVals[i].vt != rgpropvar[i].vt)
                continue;

            if(memcmp(curVals + i, rgpropvar + i, sizeof(PROPVARIANT)) == 0 ||
               (curVals[i].vt == VT_BSTR && !lstrcmp(curVals[i].bstrVal, rgpropvar[i].bstrVal)) ||
               (curVals[i].vt == VT_CLSID && IsEqualGUID(*curVals[i].puuid, *rgpropvar[i].puuid)))
            {
                // the value "matches", wipe it from both arrays.
                if(i != (cpspec - 1)) {

                    //
                    //  Move a block of values/propspecs.
                    //  The number of elements to move is 1 less than the
                    //  remaining number of elements we still have to check.
                    //  Move these elements up in the new value array - put
                    //  them after the elements we've decided to keep so far
                    //
                    MoveMemory(newVals + ulNewEltIndex,
                               newVals + ulNewEltIndex + 1,
                               (cpspec - i - 1) * sizeof(PROPVARIANT));
                    MoveMemory(newSpecs + ulNewEltIndex,
                               newSpecs + ulNewEltIndex + 1,
                               (cpspec - i - 1) * sizeof(PROPSPEC));
                }

                newcpspec--;
            } else {
                //
                //  We want to keep this element, so increase the element index.
                //
                ulNewEltIndex++;
            }
        }

        // It could happen that all values are the same, in which case we
        // don't want to write anything at all
        if(newcpspec == 0) {
            hr = S_OK;
            goto Cleanup;
        }
    }


    //
    //  Verify write access to all requested properties. If any of the
    //  properties are read ony, the call fails with access denied.
    //

    hr = m_pPropStg->CheckPropertyAccess(TRUE,
                                         newcpspec,
                                         (PROPSPEC*)newSpecs);
    if (FAILED(hr)) {
        DBG_ERR(("CWiaItem::WriteMultiple, CheckPropertyAccess failed"));
        goto Cleanup;
    }

    //
    //  First create the backup.
    //

    hr = m_pPropStg->Backup();
    if (SUCCEEDED(hr)) {

        //
        //  Write property values.
        //

        hr =  (m_pPropStg->CurStg())->WriteMultiple(newcpspec,
                                                    newSpecs,
                                                    newVals,
                                                    propidNameFirst);
        if (SUCCEEDED(hr)) {

            //
            //  Write was successful, so do validation
            //

            LONG    lFlags = 0;

            //
            //  Make sure all PropSpecs are using PropID's.  If some of the
            //  PropSpecs are using string names, then convert them.
            //  This is so that drivers only have to deal with PropID's.
            //

            PROPSPEC *pPropSpec = NULL;

            hr = m_pPropStg->NamesToPropIDs(newcpspec, (PROPSPEC*) newSpecs, &pPropSpec);
            if (SUCCEEDED(hr)) {

                //
                // Let the device mini driver know the properties have changed.
                // Device only gets propspec, must read prop values from item's
                // property stream.
                //
                {
                    LOCK_WIA_DEVICE _LWD(this, &hr);

                    if(SUCCEEDED(hr)) {
                        hr = m_pActiveDevice->m_DrvWrapper.WIA_drvValidateItemProperties((BYTE*)this,
                            lFlags,
                            newcpspec,
                            (pPropSpec ? pPropSpec : newSpecs),
                            &m_lLastDevErrVal);
                    }
                }

                if (pPropSpec) {
                    LocalFree(pPropSpec);
                    pPropSpec = NULL;
                }
            } else {
                DBG_ERR(("CWiaItem::WriteMultiple, conversion to PropIDs failed"));
            }

        } else {
            DBG_ERR(("CWiaItem::WriteMultiple, test write failed"));
        }

        HRESULT hresult;

        if (SUCCEEDED(hr)) {

            //
            //  Validation passed, so free the backups.  Use a new
            //  HRESULT, since we don't want to overwrite hr returned by
            //  drvValidateItemProperties.
            //

            hresult = m_pPropStg->ReleaseBackups();
            if (FAILED(hresult)) {
                DBG_ERR(("CWiaItem::WriteMultiple, ReleaseBackups failed, continuing anyway..."));
            }
        } else {

            //
            //  Didn't pass validation failed, so restore old values.  Use
            //  a new HRESULT, since we don't want to overwrite hr returned
            //  by drvValidateItemProperties.
            //

            hresult = m_pPropStg->Undo();
            if (FAILED(hresult)) {

                DBG_ERR(("CWiaItem::WriteMultiple, Undo() failed, could not restore invalid properties to their original values"));
            }
        }
    } else {
        DBG_ERR(("CWiaItem::WriteMultiple, couldn't make backup copy of properties"));
    }

Cleanup:
    if(curVals) {
        FreePropVariantArray(cpspec, curVals);
        LocalFree(curVals);
    }
    if(newVals) LocalFree(newVals);
    if(newSpecs) LocalFree(newSpecs);

    return hr;
}

/**************************************************************************\
* GetPropertyAttributes
*
*   Get the access flags and valid values for a property.
*
* Arguments:
*
*   pWiasContext   - Pointer to WIA item
*   cPropSpec      - The number of properties
*   pPropSpec      - array of property specification.
*   pulAccessFlags - array of LONGs access flags.
*   pPropVar       - Pointer to returned valid values.
*
* Return Value:
*
*    Status
*
* History:
*
*    1/15/1999 Original Version
*   07/19/1999 Moved from iitem to ipropitm to implement IWiaPropertyStorage
*              interface.
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::GetPropertyAttributes(
    ULONG                   cPropSpec,
    PROPSPEC                pPropSpec[],
    ULONG                   pulAccessFlags[],
    PROPVARIANT             ppvValidValues[])
{
    DBG_FN(CWiaItem::GetPropertyAttributes);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::GetPropertyAttributes, InitLazyProps failed"));
            return hr;
        }
    }

    //
    //  RPC has already done parameter validation for us, so call
    //  GetPropertyAttributesHelper to do the work.
    //
    return GetPropertyAttributesHelper(this,
                                       cPropSpec,
                                       pPropSpec,
                                       pulAccessFlags,
                                       ppvValidValues);
}

/**************************************************************************\
* CWiaItem::GetCount
*
*   Returns the number of properties stored in an item's current value
*   property storage.
*
* Arguments:
*
*   pulPropCount    - Address to store the property count.
*
* Return Value:
*
*   Status
*
* History:
*
*    9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::GetCount(
    ULONG*      pulPropCount)
{
    DBG_FN(CWiaItem::GetCount);
    IEnumSTATPROPSTG    *pIEnum;
    STATPROPSTG         stg;
    ULONG               ulCount;
    HRESULT             hr = S_OK;

    if (pulPropCount == NULL) {
        DBG_ERR(("CWiaItem::GetCount, NULL parameter!"));
        return E_INVALIDARG;
    } else {
        *pulPropCount = 0;
    }

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::GetCount, InitLazyProps failed"));
            return hr;
        }
    }

    hr = (m_pPropStg->CurStg())->Enum(&pIEnum);
    if (SUCCEEDED(hr)) {
        ulCount = 0;

        while (pIEnum->Next(1, &stg, NULL) == S_OK) {
            ulCount++;

            if(stg.lpwstrName) {
                CoTaskMemFree(stg.lpwstrName);
            }
        }

        if (SUCCEEDED(hr)) {
            hr = S_OK;
            *pulPropCount = ulCount;
        } else {
            DBG_ERR(("CWiaItem::GetCount, pIEnum->Next failed (0x%X)", hr));
        }
        pIEnum->Release();
    } else {
        DBG_ERR(("CWiaItem::GetCount, Enum off CurStg failed (0x%X)", hr));
    }
    return hr;
}

/**************************************************************************\
* CWiaItem::GetPropertyStream
*
*   Get a copy of an items property stream. Caller must free returned
*   property stream.
*
* Arguments:
*
*   pCompatibilityId    - Address of GUID to receive the device's property
*                         stream CompatibilityId.
*   ppstmProp           - Pointer to returned property stream.
*
* Return Value:
*
*   Status
*
* History:
*
*   09/03/1998 Original Version
*   12/12/1999 Modified to use CompatibilityId
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::GetPropertyStream(
    GUID     *pCompatibilityId,
    LPSTREAM *ppstmProp)
{
    DBG_FN(CWiaItem::GetPropertyStream);

    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::GetPropertyStream, InitLazyProps failed"));
            return hr;
        }
    }

    return m_pPropStg->GetPropertyStream(pCompatibilityId, ppstmProp);
}

/**************************************************************************\
* CWiaItem::SetPropertyStream
*
*   Set an items property stream.
*
* Arguments:
*
*   pCompatibilityId    - Pointer to a GUID representing the property
*                         stream CompatibilityId.
*   pstmProp            - Pointer to property stream.
*
* Return Value:
*
*   Status
*
* History:
*
*   09/03/1998  Original Version
*   12/12/1999  Modified to use CompatibilityId
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::SetPropertyStream(
    GUID        *pCompatibilityId,
    LPSTREAM    pstmProp)
{
    DBG_FN(CWiaItem::SetPropertyStream);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::SetPropertyStream, InitLazyProps failed"));
            return hr;
        }
    }

    return m_pPropStg->SetPropertyStream(pCompatibilityId, this, pstmProp);
}

/**************************************************************************\
*
*   Methods of IPropertyStorage not directly off IWiaPropertySTorage
*
*   DeleteMultiple
*   DeletePropertyNames
*   Commit
*   Revert
*   SetTimes
*   SetClass
*   Stat
*
*   9/3/1998 Original Version
*
\**************************************************************************/

HRESULT _stdcall CWiaItem::DeleteMultiple(
    ULONG cpspec,
    const PROPSPEC __RPC_FAR rgpspec[])
{
    DBG_FN(CWiaItem::DeleteMultiple);
   return E_ACCESSDENIED;
}

HRESULT _stdcall CWiaItem::DeletePropertyNames(
    ULONG cpropid,
    const PROPID __RPC_FAR rgpropid[])
{
    DBG_FN(CWiaItem::DeletePropertyNames);
   return E_ACCESSDENIED;
}

HRESULT _stdcall CWiaItem::Commit(DWORD grfCommitFlags)
{
    DBG_FN(CWiaItem::Commit);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::Commit, InitLazyProps failed"));
            return hr;
        }
    }

    hr = (m_pPropStg->CurStg())->Commit(grfCommitFlags);
    return hr;
}

HRESULT _stdcall CWiaItem::Revert(void)
{
    DBG_FN(CWiaItem::Revert);
   HRESULT hr;

   //
   //  Check whether item properties have been initialized
   //

   if (!m_bInitialized) {
       hr = InitLazyProps();
       if (FAILED(hr)) {
           DBG_ERR(("CWiaItem::Revert, InitLazyProps failed"));
           return hr;
       }
   }

   hr = (m_pPropStg->CurStg())->Revert();
   return hr;
}

HRESULT _stdcall CWiaItem::SetTimes(
    const FILETIME __RPC_FAR *pctime,
    const FILETIME __RPC_FAR *patime,
    const FILETIME __RPC_FAR *pmtime)
{
    DBG_FN(CWiaItem::SetTimes);
   HRESULT hr;

   //
   //  Check whether item properties have been initialized
   //

   if (!m_bInitialized) {
       hr = InitLazyProps();
       if (FAILED(hr)) {
           DBG_ERR(("CWiaItem::SetTimes, InitLazyProps failed"));
           return hr;
       }
   }

   hr = (m_pPropStg->CurStg())->SetTimes(pctime,patime,pmtime);
   return hr;
}

HRESULT _stdcall CWiaItem::SetClass(REFCLSID clsid)
{
    DBG_FN(CWiaItem::SetClass);
    HRESULT hr;

    //
    //  Check whether item properties have been initialized
    //

    if (!m_bInitialized) {
        hr = InitLazyProps();
        if (FAILED(hr)) {
            DBG_ERR(("CWiaItem::SetClass, InitLazyProps failed"));
            return hr;
        }
    }
    return (m_pPropStg->CurStg())->SetClass(clsid);
}

HRESULT _stdcall CWiaItem::Stat(STATPROPSETSTG *pstatpsstg)
{
    DBG_FN(CWiaItem::Stat);
   HRESULT hr;

   //
   //  Check whether item properties have been initialized
   //

   if (!m_bInitialized) {
       hr = InitLazyProps();
       if (FAILED(hr)) {
           DBG_ERR(("CWiaItem::Stat, InitLazyProps failed"));
           return hr;
       }
   }

   hr = (m_pPropStg->CurStg())->Stat(pstatpsstg);
   return hr;
}