//+--------------------------------------------------------------------------- // // 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 #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 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 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; ulSetdwFlags & 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; ulcPropIds; 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 xapUPropInfo; XArray 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; iUPropcPropIds; 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 xaPropInfo; XArrayOLE 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 xaPropInfoSet( cSets ); ulOutIndex = 0; ulEnd = cPropertySets == 0 ? cSets : cPropertySets; // Fill in the output array for(ulSet=0; ulSetpwszDescription = 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