windows-nt/Source/XPSP1/NT/inetsrv/query/icommand/propbase.cxx
2020-09-26 16:20:57 +08:00

2111 lines
70 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 1999.
//
// File: propbase.cxx
//
// Contents: Utility object containing implementation of base property
//
// Classes: CUtlProps
//
// History: 10-28-97 danleg Created from monarch uprops.cpp
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "propbase.hxx"
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::CUtlProps, public
//
// Synopsis: Constructor for CUtlProps
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
CUtlProps::CUtlProps( DWORD dwFlags ) :
_cPropSetDex(0),
_cUPropSet(0),
_cUPropSetHidden(0),
_pUPropSet(0),
_dwFlags(dwFlags),
_xaUProp(),
_cElemPerSupported(0),
_xadwSupported(),
_xadwPropsInError(),
_xaiPropSetDex()
{
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::~CUtlProps, public
//
// Synopsis: Destructor for CUtlProps
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
CUtlProps::~CUtlProps()
{
FreeMemory();
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::FillDefaultValues, public
//
// Synopsis: Fill all the default values. Note that failure might leave
// things only half done.
//
// Arguments: [ulPropSetTarget] - Propset to fill if only one
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::FillDefaultValues( ULONG ulPropSetTarget )
{
SCODE sc = S_OK;
ULONG ulPropId;
ULONG iNewDex;
// Fill in all the actual values.
// Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
// Only writable properties are in UPROP array.
// Maybe restrict to a single PropSet if within valid range [0..._cUPropSet-1].
// Otherwise do all propsets.
ULONG iPropSet = (ulPropSetTarget < _cUPropSet) ? ulPropSetTarget : 0;
for( ; iPropSet<_cUPropSet; iPropSet++)
{
iNewDex = 0;
for(ulPropId=0; ulPropId<_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
{
if ( _pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags &
(DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
{
// Initialize dwFlags element of UPropVal
_xaUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
VariantClear( &_xaUProp[iPropSet].pUPropVal[iNewDex].vValue );
sc = GetDefaultValue(
iPropSet,
_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId,
&_xaUProp[iPropSet].pUPropVal[iNewDex].dwOption,
&_xaUProp[iPropSet].pUPropVal[iNewDex].vValue );
if ( FAILED(sc) )
return sc;
iNewDex++;
}
}
// We're through if restricting to single PropSet.
if ( ulPropSetTarget < _cUPropSet )
break;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetPropertiesArgChk, public
//
// Synopsis: Initialize the buffers and check for E_INVALIDARG cases.
// This routine is used by RowsetInfo, CommandProperties and
// IDBProperties
//
// Arguments: [cPropertySets] - number of property sets
// [rgPropertySets] - property classes and ids
// [pcProperties] - count of structs returned [out]
// [prgProperties] - array of properties [out]
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
void CUtlProps::GetPropertiesArgChk
(
const ULONG cPropertySets,
const DBPROPIDSET rgPropertySets[],
ULONG* pcProperties,
DBPROPSET** prgProperties
)
{
ULONG ul;
// Initialize values
if ( pcProperties )
*pcProperties = 0;
if ( prgProperties )
*prgProperties = 0;
// Check Arguments
if ( ((cPropertySets > 0) && !rgPropertySets) ||
!pcProperties || !prgProperties )
THROW( CException(E_INVALIDARG) );
// New argument check for > 1 cPropertyIDs and NULL pointer for
// array of property ids.
for(ul=0; ul<cPropertySets; ul++)
{
if ( rgPropertySets[ul].cPropertyIDs &&
!(rgPropertySets[ul].rgPropertyIDs) )
THROW( CException(E_INVALIDARG) );
// Check for propper formation of DBPROPSET_PROPERTIESINERROR
if ( (_dwFlags & ARGCHK_PROPERTIESINERROR) &&
rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR )
{
if ( (cPropertySets > 1) ||
(rgPropertySets[ul].cPropertyIDs != 0) ||
(rgPropertySets[ul].rgPropertyIDs != 0) )
THROW( CException(E_INVALIDARG) );
}
}
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::SetPropertiesArgChk, public
//
// Synopsis: Initialize the buffers and check for E_INVALIDARG cases
// NOTE: This routine is used by CommandProperties and
// IDBProperties
//
// Arguments: [cPropertySets] - count of structs returned
// [rgPropertySets] - array of propertysets
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
void CUtlProps::SetPropertiesArgChk
(
const ULONG cPropertySets,
const DBPROPSET rgPropertySets[]
)
{
ULONG ul;
// Argument Checking
if ( cPropertySets > 0 && !rgPropertySets )
THROW( CException(E_INVALIDARG) );
// New argument check for > 1 cPropertyIDs and NULL pointer for
// array of property ids.
for(ul=0; ul<cPropertySets; ul++)
{
if ( rgPropertySets[ul].cProperties &&
!(rgPropertySets[ul].rgProperties) )
THROW( CException(E_INVALIDARG) );
}
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetProperties, public
//
// Synopsis: Collect the property information that the consumer is
// interested in. If no restriction guids are supplied,
// return all known properties.
//
// NOTE: If cProperties is 0, this function will return an array
// of guids that had been previously set. IF cProperties is non 0,
// the routine will use the array of property guids passed in and
// return informatino about the properties asked for only.
//
// This routine is used by RowsetInfo and CommandProperties.
//
// Arguments: [cPropertySets] - number of property setes
// [rgPropertySets] - property classes and ids
// [pcProperties] - count of structs returned [out]
// [prgProperties] - array of properties [out]
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::GetProperties(
const ULONG cPropertySets,
const DBPROPIDSET rgPropertySets[],
ULONG* pcProperties,
DBPROPSET** prgProperties )
{
UPROPVAL* pUPropVal;
ULONG ulCurProp;
ULONG cTmpPropertySets = cPropertySets;
SCODE sc = S_OK;
ULONG ulSet = 0;
ULONG ulNext = 0;
ULONG cSets = 0;
ULONG cProps = 0;
ULONG ulProp = 0;
DWORD dwStatus = 0;
DBPROP* pProp = 0;
UPROPINFO* pUPropInfo = 0;
ULONG ulCurSet;
ULONG iPropSet;
// We need to have special handling for DBPROPSET_PROPERTIESINERROR.
// Turn on a flags to indicate this mode and make cTmpPropertySets
// appear to be 0.
if ( (_dwFlags & ARGCHK_PROPERTIESINERROR) &&
rgPropertySets &&
(rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
{
cTmpPropertySets = 0;
dwStatus |= GETPROP_PROPSINERROR;
}
// If the consumer does not restrict the property sets by specify an
// array of property sets and a cTmpPropertySets greater than 0, then we
// need to make sure we have some to return
if ( 0 == cTmpPropertySets )
{
// Determine the number of property sets supported
cSets = _cUPropSet;
}
else
{
// Since special property set guids are not supported by
// GetProperties, we can just use the count of property sets given to
// us.
cSets = cTmpPropertySets;
}
// If no properties set, then return
if ( 0 == cSets )
return S_OK;
// Allocate the DBPROPSET structures
DBPROPSET * pPropSet = (DBPROPSET *) CoTaskMemAlloc( cSets * sizeof DBPROPSET );
if ( 0 != pPropSet )
{
RtlZeroMemory( pPropSet, cSets * sizeof(DBPROPSET) );
// Fill in the output array
iPropSet = 0;
for(ulSet=0; ulSet<cSets; ulSet++)
{
// Depending of if Property sets are specified store the
// return property set.
if ( cTmpPropertySets == 0 )
{
if ( _pUPropSet[ulSet].dwFlags & UPROPSET_HIDDEN )
continue;
pPropSet[iPropSet].guidPropertySet = *(_pUPropSet[ulSet].pPropSet);
}
else
pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
iPropSet++;
}
}
else
{
vqDebugOut(( DEB_ERROR, "Could not allocate DBPROPSET array for GetProperties\n" ));
return E_OUTOFMEMORY;
}
TRY
{
// Process requested or derived Property sets
iPropSet=0;
for( ulSet = 0; ulSet < cSets; ulSet++ )
{
XCoMem<DBPROP> xProp;
cProps = 0;
pProp = 0;
ulNext = 0;
dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
// Calculate the number of property nodes needed for this
// property set.
if ( 0 == cTmpPropertySets )
{
// If processing requesting all property sets, do not
// return the hidden sets.
if ( _pUPropSet[ulSet].dwFlags & UPROPSET_HIDDEN )
continue;
cProps = _pUPropSet[ulSet].cUPropInfo;
dwStatus |= GETPROP_ALLPROPIDS;
ulCurSet = ulSet;
}
else
{
Win4Assert( ulSet == iPropSet );
// If the count of PROPIDs is 0 or it is a special property set,
// then the consumer is requesting all propids for this property
// set.
if ( 0 == rgPropertySets[ulSet].cPropertyIDs )
{
dwStatus |= GETPROP_ALLPROPIDS;
// We have to determine if the property set is supported and
// if so the count of properties in the set.
if ( S_OK == GetIndexofPropSet( &(pPropSet[iPropSet].guidPropertySet),
&ulCurSet ) )
{
cProps += _pUPropSet[ulCurSet].cUPropInfo;
}
else
{
// Not Supported
dwStatus |= GETPROP_ERRORSOCCURRED;
goto NEXT_SET;
}
}
else
{
cProps = rgPropertySets[ulSet].cPropertyIDs;
//@TODO determine extra nodes needed for colids based on restriction array, it is
//possible that the same restriction is used twice, thus using our other calculation method
//would cause an overflow.
if (GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK)
{
dwStatus |= GETPROP_NOTSUPPORTED;
dwStatus |= GETPROP_ERRORSOCCURRED;
}
}
}
// Allocate DBPROP array
if ( 0 == cProps ) //Possible with Hidden Passthrough sets
goto NEXT_SET;
pProp = (DBPROP *) CoTaskMemAlloc( cProps * sizeof(DBPROP) );
xProp.Set( pProp );
if ( 0 != pProp )
{
// Now that we have determined we can support the property set,
// we need to gather current property values
for( ulProp=0; ulProp < cProps; ulProp++ )
{
// initialize the structure. Memberwise initialization is
// faster than old memset code -- MDW
pProp[ulProp].dwPropertyID = 0;
pProp[ulProp].dwOptions = 0;
pProp[ulProp].dwStatus = 0;
RtlZeroMemory( &(pProp[ulProp].colid), sizeof DBID );
VariantInit( &(pProp[ulProp].vValue) );
if ( 0 != ( dwStatus & GETPROP_NOTSUPPORTED ) )
{
// Not supported, so we need to mark all as NOT_SUPPORTED
pProp[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
pProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
continue;
}
DBPROP * pCurProp = &(pProp[ulNext]);
// Initialize Variant Value
pCurProp->dwStatus = DBPROPSTATUS_OK;
// Retrieve current value of properties
if ( 0 != ( dwStatus & GETPROP_ALLPROPIDS ) )
{
// Verify property is supported, if not do not return
if ( !TESTBIT(&(_xadwSupported[ulCurSet * _cElemPerSupported]), ulProp) )
continue;
// If we are looking for properties in error, then we
// should ignore all that are not in error.
if ( ( 0 != (dwStatus & GETPROP_PROPSINERROR) ) &&
!TESTBIT(&(_xadwPropsInError[ulCurSet * _cElemPerSupported]), ulProp) )
continue;
pUPropInfo = (UPROPINFO*)&(_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
Win4Assert( pUPropInfo );
pCurProp->dwPropertyID = pUPropInfo->dwPropId;
pCurProp->colid = DB_NULLID;
// If the property is WRITEABLE or CHANGABLE and not
// inerror, then the value will be gotten from the
// UPROPVAL array, else it will be derive from the
// GetDefaultValue
if ( 0 != ( pUPropInfo->dwFlags &
( DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE ) ) )
{
pUPropVal = &(_xaUProp[ulCurSet].
pUPropVal[GetUPropValIndex( ulCurSet,
pCurProp->dwPropertyID )]);
Win4Assert( 0 != pUPropVal );
if ( 0 != ( pUPropVal->dwFlags & DBINTERNFLAGS_INERROR ) )
{
sc = GetDefaultValue( ulCurSet,
pUPropInfo->dwPropId,
&(pCurProp->dwOptions),
&(pCurProp->vValue) );
if ( FAILED( sc ) )
{
pCurProp->vValue.vt = VT_EMPTY;
THROW( CException( sc ) );
}
}
else
{
pCurProp->dwOptions = pUPropVal->dwOption;
sc = VariantCopy( &(pCurProp->vValue),
&(pUPropVal->vValue) );
if ( FAILED( sc ) )
{
pCurProp->vValue.vt = VT_EMPTY;
THROW( CException( sc ) );
}
}
}
else
{
sc = GetDefaultValue( ulCurSet,
pUPropInfo->dwPropId,
&(pCurProp->dwOptions),
&(pCurProp->vValue) );
if ( FAILED( sc ) )
{
pCurProp->vValue.vt = VT_EMPTY;
THROW( CException( sc ) );
}
}
// Return all Properties in Error with CONFLICT status
if ( 0 != ( dwStatus & GETPROP_PROPSINERROR ) )
pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
dwStatus |= GETPROP_VALIDPROP;
}
else
{
// Process Properties based on Restriction array.
pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
pCurProp->colid = DB_NULLID;
if ( S_OK == GetIndexofPropIdinPropSet( ulCurSet,
pCurProp->dwPropertyID,
&ulCurProp ) )
{
// Supported
pUPropInfo = (UPROPINFO*)&(_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
Win4Assert( 0 != pUPropInfo );
// If the property is WRITEABLE, then the value will
// be gotten from the UPROPVAL array, else it will be
// derive from the GetDefaultValue
if ( 0 != ( pUPropInfo->dwFlags &
(DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) ) )
{
pUPropVal = &(_xaUProp[ulCurSet].
pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
Win4Assert( 0 != pUPropVal );
pCurProp->dwOptions = pUPropVal->dwOption;
sc = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
}
else
{
sc = GetDefaultValue( ulCurSet,
pUPropInfo->dwPropId,
&(pCurProp->dwOptions),
&(pCurProp->vValue) );
}
if ( FAILED( sc ) )
{
pCurProp->vValue.vt = VT_EMPTY;
THROW( CException( sc ) );
}
dwStatus |= GETPROP_VALIDPROP;
}
else
{
// Not Supported
pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
dwStatus |= GETPROP_ERRORSOCCURRED;
}
}
// Increment return nodes count
ulNext++;
}
// Make sure we support the property set
if ( 0 != ( dwStatus & GETPROP_NOTSUPPORTED ) )
{
ulNext = cProps;
goto NEXT_SET;
}
}
else
{
THROW( CException( E_OUTOFMEMORY ) );
}
NEXT_SET:
// It is possible that all properties are not supported,
// thus we should delete that memory and set rgProperties
// to NULL
if ( 0 == ulNext && 0 != pProp )
{
CoTaskMemFree( pProp );
pProp = 0;
}
xProp.Acquire();
pPropSet[iPropSet].cProperties = ulNext;
pPropSet[iPropSet].rgProperties = pProp;
iPropSet++;
Win4Assert( iPropSet <= cSets );
}
Win4Assert( iPropSet <= cSets );
*pcProperties = iPropSet;
*prgProperties = pPropSet;
// At least one propid was marked as not S_OK
if ( dwStatus & GETPROP_ERRORSOCCURRED )
{
// If at least 1 property was set
if ( dwStatus & GETPROP_VALIDPROP )
return DB_S_ERRORSOCCURRED;
else
{
// Do not free any of the memory on a DB_E_
return DB_E_ERRORSOCCURRED;
}
}
sc = S_OK;
}
CATCH( CException, e )
{
// Since we have no properties to return we need to free allocated memory
if ( 0 != pPropSet )
{
// Free any DBPROP arrays
for( ulSet = 0; ulSet < cSets; ulSet++ )
{
// Need to loop through all the VARIANTS and clear them
for( ulProp = 0; ulProp < pPropSet[ulSet].cProperties; ulProp++ )
VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
CoTaskMemFree( pPropSet[ulSet].rgProperties );
}
// Free DBPROPSET
CoTaskMemFree( pPropSet );
}
*pcProperties = 0;
*prgProperties = 0;
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //CUtlProps::GetProperties
//+---------------------------------------------------------------------------
//
// Method: CUtlProp::SetProperties, public
//
// Synopsis: This routine takes the array of properties that the consumer
// has give, determines whether each property can be supported.
// For the ones supported, it sets a bit.
//
// Arguments: [cPropertySets] - count of DBPROPSETS in rgPropertySets
// [rgPropertySets] - array of DBPROPSETS of values to be set
//
// Returns: SCODE indicating the following:
// S_OK - Success
// E_FAIL - Provider specific error
// DB_S_ERRORSOCCURRED - One or more properties not set
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::SetProperties
(
const ULONG cPropertySets,
const DBPROPSET rgPropertySets[]
)
{
DWORD dwState = 0;
ULONG ulSet, ulCurSet, ulCurProp, ulProp;
DBPROP* rgDBProp;
UPROPINFO* pUPropInfo;
VARIANT vDefaultValue;
DWORD dwOption;
Win4Assert( ! cPropertySets || rgPropertySets );
// Initialize Variant
VariantInit(&vDefaultValue);
// Process property sets
for(ulSet=0; ulSet<cPropertySets; ulSet++)
{
Win4Assert( ! rgPropertySets[ulSet].cProperties || rgPropertySets[ulSet].rgProperties );
// Make sure we support the property set
if ( GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet),
&ulCurSet) == S_FALSE )
{
// Not supported, thus we need to mark all as NOT_SUPPORTED
rgDBProp = rgPropertySets[ulSet].rgProperties;
for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
{
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
}
continue;
}
// Handle properties of a supported property set
rgDBProp = rgPropertySets[ulSet].rgProperties;
for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
{
// Is this a supported PROPID for this property set
if ( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID,
&ulCurProp) == S_FALSE)
{
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
continue;
}
// Set the pUPropInfo pointer
pUPropInfo = (UPROPINFO*)&(_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
Win4Assert( pUPropInfo );
// check dwOption for a valid option
if ( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED) &&
(rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_OPTIONAL) )
{
vqDebugOut(( DEB_WARN, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions ));
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION;
continue;
}
// Check that the property is settable
// @devnote: We do not check against DBPROPFLAGS_CHANGE here
if ( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 )
{
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
VariantClear(&vDefaultValue);
// VT_EMPTY against a read only property should be a no-op since
// the VT_EMPTY means the default.
if ( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY )
{
dwState |= SETPROP_VALIDPROP;
continue;
}
if ( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID,
&dwOption, &(vDefaultValue))) )
{
if ( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) )
{
switch( V_VT(&vDefaultValue) )
{
case VT_BOOL:
if ( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) )
{
dwState |= SETPROP_VALIDPROP;
continue;
}
break;
case VT_I2:
if ( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) )
{
dwState |= SETPROP_VALIDPROP;
continue;
}
break;
case VT_I4:
if ( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) )
{
dwState |= SETPROP_VALIDPROP;
continue;
}
break;
case VT_BSTR:
if ( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 )
{
dwState |= SETPROP_VALIDPROP;
continue;
}
break;
}
}
}
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
continue;
}
// Check that the property is being set with the correct VARTYPE
if ( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) &&
(rgDBProp[ulProp].vValue.vt != VT_EMPTY) )
{
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
continue;
}
// Check that the value is legal
if ( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) &&
IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE )
{
dwState |= SETPROP_ERRORS;
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
continue;
}
if ( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, &(rgDBProp[ulProp]))) )
{
dwState |= SETPROP_VALIDPROP;
}
}
}
VariantClear(&vDefaultValue);
// At least one propid was marked as not S_OK
if ( dwState & SETPROP_ERRORS )
{
// If at least 1 property was set
if ( dwState & SETPROP_VALIDPROP )
return DB_S_ERRORSOCCURRED;
else
return DB_E_ERRORSOCCURRED;
}
return S_OK;
} // CUtlProp::SetProperties
//+---------------------------------------------------------------------------
//
// Method: CUtlProp::IsPropSet, public
//
// Synopsis: Check if a VT_BOOL property is true or false
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
BOOL CUtlProps::IsPropSet
(
const GUID* pguidPropSet,
DBPROPID dwPropId
)
{
SCODE sc = S_OK;
ULONG iPropSet;
ULONG iPropId;
VARIANT vValue;
DWORD dwOptions;
VariantInit(&vValue);
if ( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
{
if ( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
{
if ( _pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags &
(DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
{
ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
dwOptions = _xaUProp[iPropSet].pUPropVal[iPropVal].dwOption;
sc = VariantCopy( &vValue,
&(_xaUProp[iPropSet].pUPropVal[iPropVal].vValue) );
}
else
{
sc = GetDefaultValue( iPropSet, dwPropId,
&dwOptions, &vValue );
}
if ( dwOptions == DBPROPOPTIONS_REQUIRED )
{
if ( SUCCEEDED(sc) )
{
Win4Assert( vValue.vt == VT_BOOL );
if ( V_BOOL(&vValue) == VARIANT_TRUE )
{
VariantClear(&vValue);
return TRUE;
}
}
}
}
}
VariantClear(&vValue);
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProp::GetPropValue, public
//
// Synopsis:
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::GetPropValue
(
const GUID* pguidPropSet,
DBPROPID dwPropId,
VARIANT* pvValue
)
{
SCODE sc = E_FAIL;
ULONG iPropSet;
ULONG iPropId;
DWORD dwOptions;
if ( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
{
if ( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
{
if ( _pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
{
sc = VariantCopy( pvValue,
&(_xaUProp[iPropSet].pUPropVal[
GetUPropValIndex(iPropSet, dwPropId)].vValue) );
}
else
{
VariantClear(pvValue);
sc = GetDefaultValue( iPropSet,
dwPropId,
&dwOptions,
pvValue );
}
}
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProp::SetPropValue, public
//
// Synopsis:
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
HRESULT CUtlProps::SetPropValue
(
const GUID* pguidPropSet,
DBPROPID dwPropId,
VARIANT* pvValue
)
{
SCODE sc = E_FAIL;
ULONG iPropSet;
ULONG iPropId;
if ( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
{
if ( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
{
Win4Assert( _pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
sc = VariantCopy( &(_xaUProp[iPropSet].pUPropVal[
GetUPropValIndex(iPropSet, dwPropId)].vValue),
pvValue );
}
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::CopyUPropVal, public
//
// Synopsis: Copy the values stored in UpropVal
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::CopyUPropVal
(
ULONG iPropSet,
UPROPVAL* rgUPropVal
)
{
SCODE sc = S_OK;
DBPROP dbProp;
Win4Assert( rgUPropVal );
Win4Assert( iPropSet < _cUPropSet );
VariantInit(&dbProp.vValue);
UPROP * pUProp = &(_xaUProp[iPropSet]);
for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
{
UPROPVAL * pUPropVal = &(pUProp->pUPropVal[ul]);
// Transfer dwOptions
rgUPropVal[ul].dwOption = pUPropVal->dwOption;
// Transfer Flags
rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
// Transfer value
VariantInit(&(rgUPropVal[ul].vValue));
sc = VariantCopy( &(rgUPropVal[ul].vValue), &(pUPropVal->vValue) );
if ( FAILED(sc) )
break;
}
VariantClear( &(dbProp.vValue) );
return sc;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetIndexofPropSet, public
//
// Synopsis: Given a propset guid, find the index of the propset in our
// current set to be returned.
//
// Arguments: [pPropset] - Guid of propset to find index of
// [pulCurSet] - Index of current property set [out]
//
// Returns: SCODE indicating the following:
// S_OK - guid was matched and index returned
// S_FALSE - guid was not matched
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::GetIndexofPropSet
(
const GUID* pPropSet,
ULONG* pulCurSet
)
{
ULONG ul;
Win4Assert( pPropSet && pulCurSet );
for(ul=0; ul<_cUPropSet; ul++)
{
if ( *pPropSet == *(_pUPropSet[ul].pPropSet) )
{
*pulCurSet = ul;
return S_OK;
}
}
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetIndexofPropIdinPropSet, public
//
// Synopsis: Given a propertyset guid, determine what index in our current
// set of property sets is to be returned
//
// Arguments: [iCurSet] - Index of current property set
// [dwPropertyId] - Property id
// [piCurPropId] - Index of requeted id [out]
//
// Returns: SCODE as follows:
// S_OK - Propid found in propset
// S_FALSE - Propid not found in propset
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::GetIndexofPropIdinPropSet
(
ULONG iCurSet,
DBPROPID dwPropertyId,
ULONG* piCurPropId
)
{
ULONG ul;
UPROPINFO* pUPropInfo;
Win4Assert( piCurPropId );
pUPropInfo = (UPROPINFO*)_pUPropSet[iCurSet].pUPropInfo;
for(ul=0; ul<_pUPropSet[iCurSet].cUPropInfo; ul++)
{
if ( dwPropertyId == pUPropInfo[ul].dwPropId )
{
*piCurPropId = ul;
// Test to see if the property is supported for this
// instantiation
if ( TESTBIT(&(_xadwSupported[iCurSet * _cElemPerSupported]), ul) )
return S_OK;
else
return S_FALSE;
}
}
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::FInit, protected
//
// Synopsis: Initialization. Called from constructors of derived classes.
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
void CUtlProps::FInit( CUtlProps * pCopyMe )
{
SCODE sc = S_OK;
ULONG ulPropId;
ULONG cPropIds;
ULONG iPropSet;
ULONG iNewDex;
XArray<UPROPINFO*> xapUPropInfo;
XArray<UPROPVAL> xaUPropVal;
UPROPINFO * pUPropInfo;
// If a pointer is passed in, we should copy that property object
if ( pCopyMe )
{
// Establish some base values
pCopyMe->CopyAvailUPropSets( &_cUPropSet,
&_pUPropSet,
&_cElemPerSupported );
Win4Assert( (_cUPropSet != 0) && (_cElemPerSupported != 0) );
// Retrieve Supported Bitmask
_xadwPropsInError.Init( _cUPropSet * _cElemPerSupported );
ClearPropertyInError();
// This uses XArray<>::Init to allocate and copy into _xadwSupported
pCopyMe->CopyUPropSetsSupported( _xadwSupported );
}
else
{
sc = InitAvailUPropSets( &_cUPropSet, &_pUPropSet, &_cElemPerSupported );
if ( FAILED(sc) )
THROW( CException(sc) );
Win4Assert( (_cUPropSet != 0) && (_cElemPerSupported != 0) );
if ( !_cUPropSet || !_cElemPerSupported )
THROW( CException(E_FAIL) );
_xadwSupported.Init( _cUPropSet * _cElemPerSupported );
_xadwPropsInError.Init( _cUPropSet * _cElemPerSupported );
ClearPropertyInError();
// Set all slots to an initial value
sc = InitUPropSetsSupported( _xadwSupported.GetPointer() );
if ( FAILED(sc) )
{
_xadwSupported.Free();
THROW( CException(sc) );
}
}
// Allocate UPROPS structures for the count of Property sets
_xaUProp.Init( _cUPropSet );
RtlZeroMemory( _xaUProp.GetPointer(), _cUPropSet * sizeof(UPROP) );
// Within the UPROPS Structure allocate and intialize the
// Property IDs that belong to this property set.
for(iPropSet=0; iPropSet<_cUPropSet; iPropSet++)
{
cPropIds = GetCountofWritablePropsInPropSet( iPropSet );
if ( cPropIds > 0 )
{
// Initialize/allocate xaUPropVal. Even when we are copying, the
// copy routine simply does a member-wise value assignment.
xaUPropVal.Init( cPropIds );
if ( pCopyMe )
{
// CopyUPropInfo uses XArray<>::Init to allocate/copy xapUPropInfo
pCopyMe->CopyUPropInfo( iPropSet, xapUPropInfo );
// CopyUPropVal only transfers values. Allocate xaUPropVal before calling this
Win4Assert( !xaUPropVal.IsNull() );
sc = pCopyMe->CopyUPropVal( iPropSet, xaUPropVal.GetPointer() );
if ( FAILED(sc) )
THROW( CException(sc) );
}
else
{
// Initialize and allocate arrays
xapUPropInfo.Init( cPropIds );
// Clear Pointer Array
RtlZeroMemory( xapUPropInfo.GetPointer(), cPropIds * sizeof(UPROPINFO *) );
// Set Pointer to correct property ids with a property set
pUPropInfo = (UPROPINFO *) _pUPropSet[iPropSet].pUPropInfo;
// Set up the writable property buffers
iNewDex = 0;
for(ulPropId=0; ulPropId<_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
{
if ( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
{
// Following assert indicates that the are more
// writable properties then space allocated
Win4Assert( iNewDex < cPropIds );
xapUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]);
xaUPropVal[iNewDex].dwOption = DBPROPOPTIONS_OPTIONAL;
xaUPropVal[iNewDex].dwFlags = 0;
VariantInit(&(xaUPropVal[iNewDex].vValue));
sc = GetDefaultValue( iPropSet,
pUPropInfo[ulPropId].dwPropId,
&(xaUPropVal[iNewDex].dwOption),
&(xaUPropVal[iNewDex].vValue) );
if ( FAILED( sc ) )
THROW( CException(sc) );
iNewDex++;
}
}
Win4Assert( cPropIds == iNewDex );
}
_xaUProp[iPropSet].rgpUPropInfo = xapUPropInfo.Acquire();
_xaUProp[iPropSet].pUPropVal = xaUPropVal.Acquire();
_xaUProp[iPropSet].cPropIds = cPropIds;
}
}
// Finally determine if there are any hidden property sets.. Those
// that do not show up in GetPropertyInfo and should not be returns on
// a 0, NULL call to GetProperties
for(iPropSet=0; iPropSet<_cUPropSet; iPropSet++)
{
if ( _pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN )
_cUPropSetHidden++;
}
} // CUtlProps::FInit
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::FreeMemory, private
//
// Synopsis: Free all memory
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
void CUtlProps::FreeMemory()
{
ULONG ulPropSet;
ULONG ulPropId;
UPROPVAL* pUPropVal;
// Remove Property Information
if ( !_xaUProp.IsNull() )
{
//
// Reset _cUPropSet to its max. Used by derived classes that expose a subset
// of their prop sets in some states. (eg. CMDSProps hides all but DBPROPSET_INIT
// if the datasource is in an uninitlaized state)
//
for(ulPropSet=0; ulPropSet<_cUPropSet; ulPropSet++)
{
pUPropVal = _xaUProp[ulPropSet].pUPropVal;
for(ulPropId=0; ulPropId<_xaUProp[ulPropSet].cPropIds; ulPropId++)
{
VariantClear(&(pUPropVal[ulPropId].vValue));
}
// TODO: UPROPSET change structure to use XArray
delete[] _xaUProp[ulPropSet].rgpUPropInfo;
delete[] _xaUProp[ulPropSet].pUPropVal;
}
_xaUProp.Free();
}
_xadwSupported.Free();
_xadwPropsInError.Free();
_xaiPropSetDex.Free();
_cPropSetDex = 0;
_cUPropSet = 0;
_cUPropSetHidden = 0;
_dwFlags = 0;
_cElemPerSupported = 0;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetCountofWritablePropsInPropSet, private
//
// Synopsis: Given an index to the property set, count the number of
// writable or changable properties under this property set.
// devnote: this includes properties with the internal flag of
// DBPROPFLAGS_CHANGE along with DBPROPFLAGS_WRITE
//
// Returns: Count of writable properties
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
ULONG CUtlProps::GetCountofWritablePropsInPropSet
(
ULONG iPropSet //@parm IN | Index of Property Set
)
{
ULONG ul;
ULONG cWritable = 0;
UPROPINFO* pUPropInfo;
Win4Assert( _pUPropSet );
Win4Assert( iPropSet < _cUPropSet );
pUPropInfo = (UPROPINFO*)_pUPropSet[iPropSet].pUPropInfo;
for(ul=0; ul<_pUPropSet[iPropSet].cUPropInfo; ul++)
{
if ( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
cWritable++;
}
return cWritable;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::GetUPropValIndex, private
//
// Synopsis:
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
ULONG CUtlProps::GetUPropValIndex
(
ULONG iCurSet,
DBPROPID dwPropId
)
{
ULONG ul;
for(ul=0; ul<_xaUProp[iCurSet].cPropIds; ul++)
{
if ( (_xaUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId )
return ul;
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlProps::SetProperty, private
//
// Synopsis: The iCurProp is an index into _pUPropSet, not into _xaUProp
//
// Arguments: [iCurSet] - Index within _xaUProp and _pUPropSet
// [iCurProp] -
// [pDBProp] - Pointer to current property node [out]
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlProps::SetProperty
(
ULONG iCurSet, //@parm IN | Index within _xaUProp and _pUPropSet
ULONG iCurProp,
DBPROP* pDBProp //@PARM INOUT | Pointer to current property node
)
{
SCODE sc = S_OK;
UPROP* pUProp;
UPROPVAL* pUPropVal;
UPROPINFO* pUPropInfo;
ULONG iUProp;
Win4Assert( pDBProp );
// Set pointer to correct set
pUProp = &(_xaUProp[iCurSet]);
Win4Assert( pUProp );
pUPropInfo = (UPROPINFO*)&(_pUPropSet[iCurSet].pUPropInfo[iCurProp]);
Win4Assert( pUPropInfo );
// Determine the index within _xaUProp
for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++)
{
if ( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID )
break;
}
if ( iUProp >= pUProp->cPropIds )
{
Win4Assert( !"Should have found index of property to set" );
sc = E_FAIL;
pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
goto EXIT;
}
//Get the UPROPVAL node pointer within that propset.
pUPropVal = &(pUProp->pUPropVal[iUProp]);
Win4Assert( pUPropVal );
// Handle VT_EMPTY, which indicates to the provider to
// reset this property to the providers default
if ( pDBProp->vValue.vt == VT_EMPTY )
{
// Should clear here, since previous values may already
// have been cached and need to be replaced.
VariantClear(&(pUPropVal->vValue));
pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED;
sc = GetDefaultValue( iCurSet,
pDBProp->dwPropertyID,
&(pUPropVal->dwOption),
&(pUPropVal->vValue) );
goto EXIT;
}
pUPropVal->dwOption = pDBProp->dwOptions;
sc = VariantCopy( &(pUPropVal->vValue), &(pDBProp->vValue) );
if ( FAILED(sc) )
goto EXIT;
pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
EXIT:
if ( SUCCEEDED(sc) )
pDBProp->dwStatus = DBPROPSTATUS_OK;
return sc;
}
//
// CUtlPropInfo methods
//
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::CUtlPropInfo, public
//
// Synopsis: Constructor
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
CUtlPropInfo::CUtlPropInfo() :
_cUPropSet(0),
_cPropSetDex(0),
_cElemPerSupported(0),
_pUPropSet(0)
{
}
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::GetPropertyInfo, public
//
// Synopsis: Retrieve the requested property info
//
// Arguments: [cPropertySets] - Count of property sets
// [rgPropertySets] - Property sets
// [pcPropertyInfoSets] - Count of properties returned [out]
// [prgPropertyInfoSets] - Property information returned [out]
// [ppDescBuffer] - Buffer for returned descriptions [out]
//
// Returns: SCODE as follows:
// S_OK - At least one index returned
// S_FALSE - No matching property set found
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlPropInfo::GetPropertyInfo
(
ULONG cPropertySets,
const DBPROPIDSET rgPropertySets[],
ULONG* pcPropertyInfoSets,
DBPROPINFOSET** prgPropertyInfoSets,
WCHAR** ppDescBuffer
)
{
SCODE sc = S_OK;
ULONG ul, ulSet, ulNext, ulEnd, ulProp;
ULONG ulOutIndex;
ULONG cSets;
ULONG cPropInfos;
DWORD dwStatus = 0;
DBPROPINFO* pCurPropInfo = 0;
WCHAR* pDescBuffer = 0;
UPROPINFO* pUPropInfo = 0;
WCHAR wszBuff[256];
int cch;
XArrayOLE<DBPROPINFO> xaPropInfo;
XArrayOLE<WCHAR> xawszDescBuffer;
// If the consumer does not restrict the property sets
// by specify an array of property sets and a cPropertySets
// greater than 0, then we need to make sure we
// have some to return
if ( cPropertySets == 0 )
{
// Determine the number of property sets supported
cSets = _cUPropSet;
}
else
{
cSets = 0;
// Determine number of property sets required
// This is only required when any of the "special" property set GUIDs were specified
for(ulSet=0; ulSet<cPropertySets; ulSet++)
{
// Note that we always allocate nodes, mark all bad properties,
// and return DB_E_ERRORSOCCURRED. See Nile spec bug 2665.
// We always allocate at least one.
if ( GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK )
cSets += _cPropSetDex;
else
cSets++;
}
}
Win4Assert( cSets );
//
// Allocate the DBPROPINFOSET structures. XArray zeors out the memory.
//
XArrayOLE<DBPROPINFOSET> xaPropInfoSet( cSets );
ulOutIndex = 0;
ulEnd = cPropertySets == 0 ? cSets : cPropertySets;
// Fill in the output array
for(ulSet=0; ulSet<ulEnd; ulSet++)
{
// Depending of if Property sets are specified store the
// return property set.
if (cPropertySets == 0)
{
xaPropInfoSet[ulSet].guidPropertySet = *(_pUPropSet[ulSet].pPropSet);
}
else
{
if ( ((rgPropertySets[ulSet].guidPropertySet == DBPROPSET_DATASOURCEALL) ||
(rgPropertySets[ulSet].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) ||
(rgPropertySets[ulSet].guidPropertySet == DBPROPSET_DBINITALL) ||
(rgPropertySets[ulSet].guidPropertySet == DBPROPSET_SESSIONALL) ||
(rgPropertySets[ulSet].guidPropertySet == DBPROPSET_ROWSETALL)) &&
(GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK) )
{
for(ul=0; ul<_cPropSetDex; ul++,ulOutIndex++)
{
xaPropInfoSet[ulOutIndex].guidPropertySet = *(_pUPropSet[_xaiPropSetDex[ul]].pPropSet);
xaPropInfoSet[ulOutIndex].cPropertyInfos = 0;
}
}
else
{
// Handle non-category property sets
// Handle unknown property sets
xaPropInfoSet[ulOutIndex].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
xaPropInfoSet[ulOutIndex].cPropertyInfos = rgPropertySets[ulSet].cPropertyIDs;
ulOutIndex++;
}
}
}
// Allocate a Description Buffer if needed
if ( ppDescBuffer )
{
ULONG cBuffers = CalcDescripBuffers(cSets, xaPropInfoSet.GetPointer());
if ( 0 != cBuffers )
{
xawszDescBuffer.Init( cBuffers * CCH_GETPROPERTYINFO_DESCRIP_BUFFER_SIZE );
pDescBuffer = xawszDescBuffer.GetPointer();
}
else
{
// No buffers needed. Make sure client already set to NULL.
Win4Assert( 0 == *ppDescBuffer );
}
}
TRANSLATE_EXCEPTIONS;
TRY
{
// Process requested or derived Property sets
dwStatus = 0;
for(ulSet=0; ulSet<cSets; ulSet++)
{
ulNext=0;
cPropInfos = 0;
dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
// Calculate the number of property nodes needed for this
// property set.
if ( cPropertySets == 0 )
{
cPropInfos = _pUPropSet[ulSet].cUPropInfo;
dwStatus |= GETPROPINFO_ALLPROPIDS;
_xaiPropSetDex[0] = ulSet;
_cPropSetDex = 1;
}
else
{
// If the count of PROPIDs is 0 (NOTE: the above routine already determined
// if it belonged to a category and if so set the count of properties to 0 for
// each propset in that category.
if ( 0 == xaPropInfoSet[ulSet].cPropertyInfos )
{
dwStatus |= GETPROPINFO_ALLPROPIDS;
// We have to determine if the property set is supported and if so
// the count of properties in the set.
if ( GetPropertySetIndex(&(xaPropInfoSet[ulSet].guidPropertySet)) == S_OK )
{
Win4Assert( _cPropSetDex == 1 );
cPropInfos += _pUPropSet[_xaiPropSetDex[0]].cUPropInfo;
}
else
{
// Not Supported
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
goto NEXT_SET;
}
}
else
{
cPropInfos = xaPropInfoSet[ulSet].cPropertyInfos;
if ( GetPropertySetIndex(&(xaPropInfoSet[ulSet].guidPropertySet)) == S_FALSE )
{
dwStatus |= GETPROPINFO_NOTSUPPORTED;
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
}
}
}
// Allocate DBPROP array
Win4Assert( cPropInfos != 0 );
xaPropInfo.Init( cPropInfos );
for(ulProp=0; ulProp<cPropInfos; ulProp++)
{
VariantInit(&(xaPropInfo[ulProp].vValues));
if ( dwStatus & GETPROPINFO_NOTSUPPORTED )
{
// Not supported, thus we need to mark all as NOT_SUPPORTED
xaPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
xaPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED;
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
}
}
// Make sure we support the property set
if ( dwStatus & GETPROPINFO_NOTSUPPORTED )
{
ulNext = cPropInfos;
goto NEXT_SET;
}
// Retrieve the property information for this property set
for(ul=0; ul<_cPropSetDex; ul++)
{
pUPropInfo = (UPROPINFO*)(_pUPropSet[_xaiPropSetDex[ul]].pUPropInfo);
Win4Assert( pUPropInfo );
// Retrieve current value of properties
if ( dwStatus & GETPROPINFO_ALLPROPIDS )
{
for(ulProp=0; ulProp<_pUPropSet[_xaiPropSetDex[ul]].cUPropInfo; ulProp++)
{
// Verify property is supported, if not do not return
if ( !TESTBIT(&(_xadwSupported[_xaiPropSetDex[ul] * _cElemPerSupported]), ulProp) )
continue;
pCurPropInfo = &(xaPropInfo[ulNext]);
// If the ppDescBuffer pointer was not NULL, then
// we need supply description of the properties
if ( ppDescBuffer )
{
// Set Buffer pointer
pCurPropInfo->pwszDescription = pDescBuffer;
// Load the string into temp buffer
//@TODO Add Reallocation routine
cch = LoadDescription( pUPropInfo[ulProp].pwszDesc,
wszBuff,
NUMELEM(wszBuff) );
if ( 0 != cch )
{
// Adjust for '\0'
cch++;
// Transfer to official buffer if room
RtlCopyMemory( pDescBuffer, wszBuff, cch * sizeof(WCHAR) );
pDescBuffer += cch;
}
else
{
wcscpy( pDescBuffer, L"UNKNOWN" );
pDescBuffer += NUMELEM(L"UNKNOWN");
}
}
pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId;
pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags;
pCurPropInfo->vtType = pUPropInfo[ulProp].VarType;
//@TODO for some there will be a list
pCurPropInfo->vValues.vt = VT_EMPTY;
dwStatus |= GETPROPINFO_VALIDPROP;
// Increment to next available buffer
ulNext++;
}
}
else
{
Win4Assert( _cPropSetDex == 1 );
for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ )
{
pCurPropInfo = &(xaPropInfo[ulNext]);
// Process Properties based on Restriction array.
pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
if ( S_OK == GetUPropInfoPtr( _xaiPropSetDex[ul],
pCurPropInfo->dwPropertyID,
&pUPropInfo) )
{
// If the ppDescBuffer pointer was not NULL, then
// we need supply description of the properties
if ( ppDescBuffer )
{
// Set Buffer pointer
pCurPropInfo->pwszDescription = pDescBuffer;
// Load the string into temp buffer
if ( cch = LoadDescription( pUPropInfo->pwszDesc,
wszBuff,
NUMELEM(wszBuff)) )
{
// Adjust for '\0'
cch++;
// Transfer to official buffer if room
RtlCopyMemory( pDescBuffer, wszBuff, cch * sizeof(WCHAR) );
pDescBuffer += cch;
}
else
{
wcscpy(pDescBuffer, L"UNKNOWN");
pDescBuffer += (wcslen(L"UNKNOWN") + 1);
}
}
pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId;
pCurPropInfo->dwFlags = pUPropInfo->dwFlags;
pCurPropInfo->vtType = pUPropInfo->VarType;
dwStatus |= GETPROPINFO_VALIDPROP;
}
else
{
// Not Supported
pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
}
}
}
}
NEXT_SET:
xaPropInfoSet[ulSet].cPropertyInfos = ulNext;
xaPropInfoSet[ulSet].rgPropertyInfos = xaPropInfo.Acquire();
}
// Success, set return values
*pcPropertyInfoSets = cSets;
*prgPropertyInfoSets = xaPropInfoSet.Acquire();
if ( ppDescBuffer )
*ppDescBuffer = xawszDescBuffer.Acquire();
// At least one propid was marked as not S_OK
if ( dwStatus & GETPROPINFO_ERRORSOCCURRED )
{
// If at least 1 property was set
if ( dwStatus & GETPROPINFO_VALIDPROP )
return DB_S_ERRORSOCCURRED;
else
{
// Do not free any of the rgPropertyInfoSets, but
// do free the ppDescBuffer
if ( pDescBuffer )
{
Win4Assert( ppDescBuffer );
CoTaskMemFree( pDescBuffer );
*ppDescBuffer = 0;
}
return DB_E_ERRORSOCCURRED;
}
}
}
CATCH( CException, e )
{
// most likely E_OUTOFMEMORY
sc = e.GetErrorCode();
// Check if failure and clean up any allocated memory
if ( FAILED(sc) )
{
// Free Description Buffer
if ( pDescBuffer )
{
Win4Assert( ppDescBuffer );
CoTaskMemFree( *ppDescBuffer );
*ppDescBuffer = 0;
}
if ( !xaPropInfoSet.IsNull() )
{
// Loop through Property Sets
for(ulSet=0; ulSet<cSets; ulSet++)
{
if ( xaPropInfoSet[ulSet].rgPropertyInfos )
CoTaskMemFree( xaPropInfoSet[ulSet].rgPropertyInfos );
}
}
}
// Rethrow exception to the calling function
RETHROW();
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::FInit, protected
//
// Synopsis: Initialization. Called from constructors of derived classes.
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
void CUtlPropInfo::FInit
(
)
{
SCODE sc = S_OK;
InitAvailUPropSets( &_cUPropSet,
&_pUPropSet,
&_cElemPerSupported );
Win4Assert( (_cUPropSet != 0) && (_cElemPerSupported != 0) );
if ( !_cUPropSet || !_cElemPerSupported )
THROW( CException(E_FAIL) );
_xadwSupported.Init( _cUPropSet * _cElemPerSupported );
sc = InitUPropSetsSupported( _xadwSupported.GetPointer() );
if ( FAILED(sc) )
{
_xadwSupported.Free();
THROW( CException(sc) );
}
if ( _cUPropSet )
{
_xaiPropSetDex.Init( _cUPropSet );
}
return;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::GetUPropInfoPtr, private
//
// Synopsis: Retrieve a pointer to the UPROPINFO structure that contains
// information about this property id within this property set
//
// Arguments: [iPropSetDex] - Index into UPropSets
// [dwPropertyId] - Property to search for with UPropSet
// [ppUPropInfo] - Pointer in which to return ptr to UPropInfo [out]
//
// Returns: SCODE as follows:
// S_OK - Property id found
// S_FALSE - No matching prop id found or property not supported
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlPropInfo::GetUPropInfoPtr
(
ULONG iPropSetDex, //@parm IN | Index into UPropSets
DBPROPID dwPropertyId, //@parm IN | Propery to search for with UPropSet
UPROPINFO** ppUPropInfo //@parm OUT | Pointer in which to return ptr to UPropInfo
)
{
ULONG ulProps;
// Scan through the property sets looking for matching attributes
for(ulProps=0; ulProps<_pUPropSet[iPropSetDex].cUPropInfo; ulProps++)
{
if ( _pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId )
{
*ppUPropInfo = (UPROPINFO*)&(_pUPropSet[iPropSetDex].pUPropInfo[ulProps]);
// Test to see if the property is supported for this instantiation
if ( TESTBIT(&(_xadwSupported[iPropSetDex * _cElemPerSupported]), ulProps) )
return S_OK;
else
return S_FALSE;
}
}
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::GetPropertySetIndex, private
//
// Synopsis: Retrieve the index or indices of PropertySets that match the
// given guid.
//
// NOTE: If given a DBPROPET_DATASOURCEALL, DBPROPSET_DATASOURCEINFOALL
// or DBPROPSET_ROWSETALL, the routine may return multiple
// indices.
// Returns: SCODE as follows:
// S_OK - At least one index was returned.
// S_FALSE - No matching property set found
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
SCODE CUtlPropInfo::GetPropertySetIndex
(
const GUID* pPropertySet //@parm IN | Pointer to Property Set Guid
)
{
DWORD dwFlag = 0;
ULONG ulSet;
Win4Assert( _cUPropSet && _pUPropSet );
Win4Assert( !_xaiPropSetDex.IsNull() );
Win4Assert( pPropertySet );
_cPropSetDex = 0;
if ( *pPropertySet == DBPROPSET_DATASOURCEALL )
{
dwFlag = DBPROPFLAGS_DATASOURCE;
}
else if ( *pPropertySet == DBPROPSET_DATASOURCEINFOALL )
{
dwFlag = DBPROPFLAGS_DATASOURCEINFO;
}
else if ( *pPropertySet == DBPROPSET_ROWSETALL )
{
dwFlag = DBPROPFLAGS_ROWSET;
}
else if ( *pPropertySet == DBPROPSET_DBINITALL )
{
dwFlag = DBPROPFLAGS_DBINIT;
}
else if ( *pPropertySet == DBPROPSET_SESSIONALL )
{
dwFlag = DBPROPFLAGS_SESSION;
}
else // No scan required, just look for match.
{
for(ulSet=0; ulSet<_cUPropSet; ulSet++)
{
if ( *(_pUPropSet[ulSet].pPropSet) == *pPropertySet )
{
_xaiPropSetDex[_cPropSetDex] = ulSet;
_cPropSetDex++;
break;
}
}
goto EXIT;
}
// Scan through the property sets looking for matching attributes
for(ulSet=0; ulSet<_cUPropSet; ulSet++)
{
if ( _pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
{
_xaiPropSetDex[_cPropSetDex] = ulSet;
_cPropSetDex++;
}
}
EXIT:
return (_cPropSetDex) ? S_OK : S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Method: CUtlPropInfo::CalcDescripBuffers, private
//
// Synopsis: Calculate the number of description buffers that will be needed
//
// Argunemts: [cPropInfoSet] - Count of propinfo sets
// [pPropInfoSet] - Property info sets
//
// Returns: Number of buffers needed
//
// History: 11-12-97 danleg Created from Monarch
//
//----------------------------------------------------------------------------
ULONG CUtlPropInfo::CalcDescripBuffers
(
ULONG cPropInfoSet, //@parm IN | count of property info sets
DBPROPINFOSET* pPropInfoSet //@parm IN | property info sets
)
{
ULONG ul, ulSet;
ULONG cBuffers = 0;
Win4Assert( _pUPropSet && cPropInfoSet && pPropInfoSet );
for(ulSet=0; ulSet<cPropInfoSet; ulSet++)
{
if ( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
{
for(ul=0; ul<_cPropSetDex; ul++)
{
cBuffers += _pUPropSet[_xaiPropSetDex[ul]].cUPropInfo;
}
}
}
return cBuffers;
}