|
|
//+---------------------------------------------------------------------------
//
// 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; }
|