#include "oleds.hxx" #if (!defined(BUILD_FOR_NT40)) // ---------------- C D B P R O P E R T I E S C O D E ---------------------- //----------------------------------------------------------------------------- // CDBProperties::CDBProperties // // @mfunc // CDBProperties constructor. // // @rdesc NONE //----------------------------------------------------------------------------- CDBProperties::CDBProperties(): _cPropSets(0), _aPropSets(0), _cPropInfoSets(0), _aPropInfoSets(0) { } //----------------------------------------------------------------------------- // CDBProperties::~CDBProperties // // @mfunc // CDBProperties destructor. Release storage used by CDBProperties. // // @rdesc NONE //----------------------------------------------------------------------------- CDBProperties::~CDBProperties() { ULONG iSet, iProp, iSetInfo; for (iSet=0; iSet<_cPropSets; ++iSet) { for (iProp=0; iProp <_aPropSets[iSet].cProperties; ++iProp) VariantClear(&(_aPropSets[iSet].rgProperties[iProp].vValue)); delete [] _aPropSets[iSet].rgProperties; } delete [] _aPropSets; for (iSet=0; iSet<_cPropInfoSets; ++iSet) { delete [] _aPropInfoSets[iSet].rgPropertyInfos; } delete [] _aPropInfoSets; } //----------------------------------------------------------------------------- // CDBProperties::GetPropertySet // // @mfunc Looks up a property set by its GUID. // // @rdesc Pointer to desired property set, or 0 if not found. //----------------------------------------------------------------------------- DBPROPSET* CDBProperties::GetPropertySet(const GUID& guid) const { DBPROPSET* pPropSet = 0; // the answer, assume not found // linear search ULONG iPropSet; for (iPropSet=0; iPropSet<_cPropSets; ++iPropSet) { if (IsEqualGUID(guid, _aPropSets[iPropSet].guidPropertySet)) { pPropSet = &_aPropSets[iPropSet]; break; } } return ( pPropSet ); } //----------------------------------------------------------------------------- // CDBProperties::GetPropertyInfoSet // // @mfunc Looks up a property info set by its GUID. // // @rdesc Pointer to desired property info set, or 0 if not found. //----------------------------------------------------------------------------- DBPROPINFOSET* CDBProperties::GetPropertyInfoSet(const GUID& guid) const { DBPROPINFOSET* pPropInfoSet = 0; // the answer, assume not found // linear search ULONG iPropSet; for (iPropSet=0; iPropSet<_cPropInfoSets; ++iPropSet) { if (IsEqualGUID(guid, _aPropInfoSets[iPropSet].guidPropertySet)) { pPropInfoSet = &_aPropInfoSets[iPropSet]; break; } } return ( pPropInfoSet ); } //----------------------------------------------------------------------------- // CDBProperties::CopyPropertySet // // @mfunc Makes a copy of a property set, given its GUID. // // @rdesc // @flag S_OK | copying succeeded, // @flag E_FAIL | no property set for given GUID, // @flag E_OUTOFMEMORY | copying failed because of memory allocation. //----------------------------------------------------------------------------- HRESULT CDBProperties::CopyPropertySet(const GUID& guid, DBPROPSET* pPropSetDst) const { ADsAssert(pPropSetDst && "must supply a PropSet pointer"); HRESULT hr = S_OK; const DBPROPSET* pPropSetSrc = GetPropertySet(guid); ULONG iProp; if (pPropSetSrc == 0) // not found { hr = E_FAIL; goto Cleanup; } // start with shallow copy *pPropSetDst = *pPropSetSrc; // allocate property array pPropSetDst->rgProperties = (DBPROP*) CoTaskMemAlloc(pPropSetSrc->cProperties * sizeof(DBPROP)); if (pPropSetDst->rgProperties == 0) { pPropSetDst->cProperties = 0; // defensive hr = E_OUTOFMEMORY; goto Cleanup; } memcpy( pPropSetDst->rgProperties, pPropSetSrc->rgProperties, pPropSetSrc->cProperties*sizeof(DBPROP)); // copy the property array for (iProp=0; iPropcProperties; ++iProp) { VariantInit(&(pPropSetDst->rgProperties[iProp].vValue)); if(FAILED(hr = VariantCopy(&(pPropSetDst->rgProperties[iProp].vValue), (VARIANT *)&(pPropSetSrc->rgProperties[iProp].vValue)))) { while(iProp) { iProp--; VariantClear(&(pPropSetDst->rgProperties[iProp].vValue)); } CoTaskMemFree(pPropSetDst->rgProperties); pPropSetDst->rgProperties = NULL; pPropSetDst->cProperties = 0; // defensive goto Cleanup; } } Cleanup: RRETURN ( hr ); } //----------------------------------------------------------------------------- // CDBProperties::CopyPropertyInfoSet // // @mfunc Makes a copy of a property info set, given its GUID. // // @rdesc // @flag S_OK | copying succeeded, // @flag E_FAIL | no property set for given GUID, // @flag E_OUTOFMEMORY | copying failed because of memory allocation. //----------------------------------------------------------------------------- HRESULT CDBProperties::CopyPropertyInfoSet ( const GUID& guid, DBPROPINFOSET* pPropInfoSetDst, WCHAR** ppDescBuffer, ULONG_PTR* pcchDescBuffer, ULONG_PTR* pichCurrent ) const { ADsAssert(pPropInfoSetDst && "must supply a PropSet pointer"); HRESULT hr = S_OK; const DBPROPINFOSET* pPropInfoSetSrc = GetPropertyInfoSet(guid); if (pPropInfoSetSrc == 0) // not found { hr = E_FAIL; goto Cleanup; } // start with shallow copy *pPropInfoSetDst = *pPropInfoSetSrc; // allocate property array pPropInfoSetDst->rgPropertyInfos = (DBPROPINFO *) CoTaskMemAlloc( pPropInfoSetSrc->cPropertyInfos * sizeof(DBPROPINFO)); if (pPropInfoSetDst->rgPropertyInfos == 0) { pPropInfoSetDst->cPropertyInfos = 0; // defensive hr = E_OUTOFMEMORY; goto Cleanup; } memcpy( pPropInfoSetDst->rgPropertyInfos, pPropInfoSetSrc->rgPropertyInfos, pPropInfoSetSrc->cPropertyInfos*sizeof(DBPROPINFO)); if(FAILED(hr =CopyPropertyDescriptions( pPropInfoSetDst, ppDescBuffer, pcchDescBuffer, pichCurrent))) { CoTaskMemFree(pPropInfoSetDst->rgPropertyInfos); pPropInfoSetDst->rgPropertyInfos = NULL; pPropInfoSetDst->cPropertyInfos = 0; // defensive hr = E_OUTOFMEMORY; } Cleanup: RRETURN ( hr ); } //----------------------------------------------------------------------------- // CDBProperties::GetProperty // // @mfunc Looks up a property by its property set GUID and ID. // // @rdesc Pointer to DBPROP for the property, or 0 if not found. //----------------------------------------------------------------------------- const DBPROP* CDBProperties::GetProperty(const GUID& guid, DBPROPID dwId) const { ULONG iProp; const DBPROPSET* pPropSet = GetPropertySet(guid); const DBPROP* pProp = 0; // the answer, assume not found if (pPropSet == 0) // no properties for desired property set goto Cleanup; // look up the desired property in the property set for (iProp=0; iPropcProperties; ++iProp) { if (dwId == pPropSet->rgProperties[iProp].dwPropertyID) { pProp = & pPropSet->rgProperties[iProp]; break; } } Cleanup: return ( pProp ); } //----------------------------------------------------------------------------- // CDBProperties::GetPropertyInfo // // @mfunc Looks up a property info by its property set GUID and ID. // // @rdesc Pointer to DBPROPINFO for the property info, or 0 if not found. //----------------------------------------------------------------------------- const DBPROPINFO UNALIGNED* CDBProperties::GetPropertyInfo(const GUID& guid, DBPROPID dwId) const { ULONG iPropInfo; const DBPROPINFOSET* pPropInfoSet = GetPropertyInfoSet(guid); const DBPROPINFO UNALIGNED* pPropInfo = 0; // the answer, assume not found if (pPropInfoSet == 0) // no properties for desired property set goto Cleanup; // look up the desired property in the property set for (iPropInfo=0; iPropInfo cPropertyInfos; ++iPropInfo) { if (dwId == pPropInfoSet->rgPropertyInfos[iPropInfo].dwPropertyID) { pPropInfo = & pPropInfoSet->rgPropertyInfos[iPropInfo]; break; } } Cleanup: return ( pPropInfo ); } //----------------------------------------------------------------------------- // CDBProperties::SetProperty // // @mfunc Adds a new property, or resets an existing one // This overloaded function is same as the other except that the // last parameter is of type PWSTR [mgorti] // // @rdesc // @flag S_OK | property added/reset, // @flag E_OUTOFMEMORY | no memory for new property set or new property. //----------------------------------------------------------------------------- HRESULT CDBProperties::SetProperty(const GUID& guid, const DBPROP& prop, BOOL fAddNew, PWSTR pwszDesc) { HRESULT hr; DBPROP *pProp; // pointer to array entry for new property ULONG iProp; DBPROPSET* pPropSet = GetPropertySet(guid); if (pPropSet == 0) // no properties yet in desired property set { if(!fAddNew) { hr = E_FAIL; goto Cleanup; } // get a new property set array DBPROPSET * aNewPropSets = new DBPROPSET[_cPropSets + 1]; if (aNewPropSets == 0) { hr = E_OUTOFMEMORY; goto Cleanup; } memcpy(aNewPropSets, _aPropSets, _cPropSets *sizeof(DBPROPSET)); // add the new property set pPropSet = & aNewPropSets[_cPropSets]; pPropSet->guidPropertySet = guid; pPropSet->cProperties = 0; pPropSet->rgProperties = 0; // release the old array, install the new one delete [] _aPropSets; _aPropSets = aNewPropSets; ++ _cPropSets; } // look for the desired property. if(!fAddNew) { pProp = 0; for (iProp=0; iPropcProperties; ++iProp) { if (pPropSet->rgProperties[iProp].dwPropertyID == prop.dwPropertyID) { pProp = &pPropSet->rgProperties[iProp]; break; } } if (pProp == 0) { hr = E_FAIL; goto Cleanup; } } // if it's a new property, add it. OLE-DB doesn't provide for any "unused" // portion in the array of DBPROPS, so we must reallocate the array every // time we add a property. else { ULONG cPropLeftOver; // allocate new property array cPropLeftOver = C_PROP_INCR - (pPropSet->cProperties + C_PROP_INCR - 1)%C_PROP_INCR - 1; if(cPropLeftOver) { pProp = &pPropSet->rgProperties[pPropSet->cProperties]; } else { DBPROP* aNewProperties = new DBPROP[pPropSet->cProperties + C_PROP_INCR]; if (aNewProperties == 0) { hr = E_OUTOFMEMORY; goto Cleanup; } // copy old array into new memcpy( aNewProperties, pPropSet->rgProperties, pPropSet->cProperties *sizeof(DBPROP)); // prepare to use new property entry pProp = & aNewProperties[pPropSet->cProperties]; // release old array, install new delete [] pPropSet->rgProperties; pPropSet->rgProperties = aNewProperties; } ++ pPropSet->cProperties; } // copy the property into my array if(!fAddNew) { DBPROP propSave; propSave = *pProp; *pProp = prop; VariantInit(&(pProp->vValue)); if(FAILED(hr = VariantCopy( &(pProp->vValue), (VARIANT *)&(prop.vValue)))) { *pProp = propSave; goto Cleanup; } } else { DBPROPINFO propinfo; *pProp = prop; propinfo.pwszDescription = pwszDesc; propinfo.dwPropertyID = prop.dwPropertyID; propinfo.dwFlags = DBPROPFLAGS_READ; if(guid == DBPROPSET_DBINIT) propinfo.dwFlags |= DBPROPFLAGS_DBINIT; else if(guid == DBPROPSET_DATASOURCEINFO) propinfo.dwFlags |= DBPROPFLAGS_DATASOURCEINFO; else propinfo.dwFlags |= DBPROPFLAGS_ROWSET; propinfo.vtType = V_VT(&(prop.vValue)); VariantInit(&(propinfo.vValues)); if(FAILED(hr = SetPropertyInfo(guid, propinfo))) goto Cleanup; } hr = S_OK; Cleanup: RRETURN ( hr ); } //----------------------------------------------------------------------------- // CDBProperties::SetPropertyInfo // // @mfunc Adds a new property info, or resets an existing one. // // @rdesc // @flag S_OK | property info added/reset, // @flag E_OUTOFMEMORY | no memory for new property info set // or new property info. //----------------------------------------------------------------------------- HRESULT CDBProperties::SetPropertyInfo(const GUID& guid, const DBPROPINFO& propinfo) { HRESULT hr; PDBPROPINFO pPropInfo; // pointer to array entry for new property ULONG iPropInfo; DBPROPINFOSET* pPropInfoSet = GetPropertyInfoSet(guid); if (pPropInfoSet == 0) // no properties yet in desired property set { // get a new property set array DBPROPINFOSET * aNewPropInfoSets = new DBPROPINFOSET[_cPropInfoSets + 1]; if (aNewPropInfoSets == 0) { hr = E_OUTOFMEMORY; goto Cleanup; } memcpy( aNewPropInfoSets, _aPropInfoSets, _cPropInfoSets *sizeof(DBPROPINFOSET)); // add the new property set pPropInfoSet = & aNewPropInfoSets[_cPropInfoSets]; pPropInfoSet->guidPropertySet = guid; pPropInfoSet->cPropertyInfos = 0; pPropInfoSet->rgPropertyInfos = 0; // release the old array, install the new one delete [] _aPropInfoSets; _aPropInfoSets = aNewPropInfoSets; ++ _cPropInfoSets; } // look for the desired property. pPropInfo = 0; for (iPropInfo=0; iPropInfocPropertyInfos; ++iPropInfo) { if (pPropInfoSet->rgPropertyInfos[iPropInfo].dwPropertyID == propinfo.dwPropertyID) { pPropInfo = &pPropInfoSet->rgPropertyInfos[iPropInfo]; break; } } // if it's a new property, add it. OLE-DB doesn't provide for any "unused" // portion in the array of DBPROPS, so we must reallocate the array every // time we add a property. if (pPropInfo == 0) { ULONG cPropLeftOver; // allocate new property array cPropLeftOver = C_PROP_INCR - (pPropInfoSet->cPropertyInfos + C_PROP_INCR - 1)%C_PROP_INCR - 1; if(cPropLeftOver) { pPropInfo = &pPropInfoSet->rgPropertyInfos[pPropInfoSet->cPropertyInfos]; } else { DBPROPINFO* aNewPropertyInfos = new DBPROPINFO[pPropInfoSet->cPropertyInfos + C_PROP_INCR]; if (aNewPropertyInfos == 0) { hr = E_OUTOFMEMORY; goto Cleanup; } // copy old array into new memcpy( aNewPropertyInfos, pPropInfoSet->rgPropertyInfos, pPropInfoSet->cPropertyInfos *sizeof(DBPROPINFO)); // prepare to use new property entry pPropInfo = & aNewPropertyInfos[pPropInfoSet->cPropertyInfos]; // release old array, install new delete [] pPropInfoSet->rgPropertyInfos; pPropInfoSet->rgPropertyInfos = aNewPropertyInfos; } ++ pPropInfoSet->cPropertyInfos; } // copy the property into my array *pPropInfo = propinfo; hr = S_OK; Cleanup: RRETURN ( hr ); } //----------------------------------------------------------------------------- // CDBProperties::LoadDescription // // @mfunc Loads a localized string from the localization DLL. // // @rdesc Count of characters returned in the buffer. //----------------------------------------------------------------------------- int CDBProperties::LoadDescription ( ULONG ids, //@parm IN | String ID PWSTR pwszBuff, //@parm OUT | Temporary buffer ULONG cchBuff //@parm IN | Count of characters buffer can hold ) const { return ( 0 ); // return( LoadStringW(g_hinstDll, ids, pwszBuff, cchBuff) ); } //----------------------------------------------------------------------------- // CDBProperties::CopyPropertyDescriptions // // @mfunc Copies into a buffer descriptions of properties in a given set. // // @rdesc // @flag S_OK | copying of property descriptions succeeded, // @flag E_OUTOFMEMORY | buffer for property descriptions could not // be allocated/extended. //----------------------------------------------------------------------------- HRESULT CDBProperties::CopyPropertyDescriptions ( DBPROPINFOSET* pPropInfoSet, WCHAR** ppDescBuffer, ULONG_PTR* pcchDescBuffer, ULONG_PTR* pichCurrent ) const { LONG iprop, cchLeft, cchNew; int cchCopied; WCHAR *pwszTmp; if(ppDescBuffer) { cchLeft = (LONG)*pcchDescBuffer - (LONG)*pichCurrent; for(iprop =0; (ULONG)iprop cPropertyInfos; iprop++) { if(pPropInfoSet->rgPropertyInfos[iprop].dwFlags == DBPROPFLAGS_NOTSUPPORTED) continue; if(cchLeft < (LONG)CCHAR_MAX_PROP_STR_LENGTH) { cchNew = CCHAR_AVERAGE_PROP_STR_LENGTH * (pPropInfoSet->cPropertyInfos - iprop - 1) + CCHAR_MAX_PROP_STR_LENGTH + *pcchDescBuffer - cchLeft; pwszTmp = (WCHAR *)CoTaskMemAlloc(cchNew *sizeof(WCHAR)); if(pwszTmp == NULL) RRETURN ( E_OUTOFMEMORY ); if(*ppDescBuffer) { memcpy( pwszTmp, *ppDescBuffer, (*pcchDescBuffer -cchLeft)*sizeof(WCHAR)); CoTaskMemFree(*ppDescBuffer); } cchLeft += cchNew -(LONG)*pcchDescBuffer; *ppDescBuffer = pwszTmp; *pcchDescBuffer = cchNew; } //?? Do we need to load these strings from resources ?? //$TODO$ Raid #86943 Copy property descriptions from source to destination buffer. cchCopied = wcslen(pPropInfoSet->rgPropertyInfos[iprop].pwszDescription); wcscpy((WCHAR *)(*ppDescBuffer) + *pichCurrent, pPropInfoSet->rgPropertyInfos[iprop].pwszDescription); pPropInfoSet->rgPropertyInfos[iprop].pwszDescription = (WCHAR *)(*pichCurrent); *pichCurrent += (cchCopied +1); cchLeft -= (cchCopied +1); } } else { // We need to NULL out the pwszDescription values: // for(iprop =0; (ULONG)iprop cPropertyInfos; iprop++) { pPropInfoSet->rgPropertyInfos[iprop].pwszDescription = NULL; } } RRETURN ( NOERROR ); } //----------------------------------------------------------------------------- // CDBProperties::CheckAndInitPropArgs // // @mfunc Helper function used while getting property sets. // Used to check and get information about property sets. // Tells if the caller is requesting // special sets or the set of properties in error. // // @rdesc // @flag S_OK | check succeeded, // @flag E_INVALIDARG | one of the arguments is invalid. //----------------------------------------------------------------------------- HRESULT CDBProperties::CheckAndInitPropArgs ( ULONG cPropertySets, // IN | Number of property sets const DBPROPIDSET rgPropertySets[], // IN | Property Sets ULONG *pcPropertySets, // OUT | Count of structs returned void **prgPropertySets,// OUT | Array of Properties BOOL *pfPropInError, BOOL *pfPropSpecial ) { LONG ipropset; ULONG cpropsetSpecial; // Initialize if( pcPropertySets ) *pcPropertySets = 0; if( prgPropertySets ) *prgPropertySets = NULL; if(pfPropInError) *pfPropInError = FALSE; if(pfPropSpecial) *pfPropSpecial = FALSE; // Check Arguments, on failure post HRESULT to error queue if( ((cPropertySets > 0) && !rgPropertySets) || !pcPropertySets || !prgPropertySets ) RRETURN ( E_INVALIDARG ); // New argument check for > 1 cPropertyIDs and NULL pointer for // array of property ids. for(ipropset=0, cpropsetSpecial = 0; (ULONG)ipropset1 || rgPropertySets[ipropset].cPropertyIDs || rgPropertySets[ipropset].rgPropertyIDs) RRETURN (E_INVALIDARG); else *pfPropInError = TRUE; } } //Count the number of special property sets being asked. else if( rgPropertySets[ipropset].guidPropertySet == DBPROPSET_DATASOURCEALL || rgPropertySets[ipropset].guidPropertySet == DBPROPSET_DATASOURCEINFOALL || rgPropertySets[ipropset].guidPropertySet == DBPROPSET_DBINITALL || rgPropertySets[ipropset].guidPropertySet == DBPROPSET_SESSIONALL || rgPropertySets[ipropset].guidPropertySet == DBPROPSET_ROWSETALL) cpropsetSpecial++; } //When requesting special property sets, all of them //must be special or none. if(cpropsetSpecial) { if(pfPropSpecial) *pfPropSpecial = TRUE; if(cpropsetSpecial < cPropertySets) RRETURN (E_INVALIDARG); } else if(pfPropSpecial) *pfPropSpecial = FALSE; RRETURN ( NOERROR ); } //----------------------------------------------------------------------------- // CDBProperties::VerifySetPropertiesArgs // // @mfunc Helper function used in IDBProperties::SetProperties. Validates // arguments passed to IDBProperties::SetProperties. // // @rdesc // @flag S_OK | Validation succeeded. // @flag E_INVALIDARG | Validation failed - one of the arguments // is in error. //----------------------------------------------------------------------------- HRESULT CDBProperties::VerifySetPropertiesArgs ( ULONG cPropertySets, //@parm IN | Count of properties DBPROPSET rgPropertySets[] //@parm IN | Properties ) { ULONG ipropset; if(cPropertySets && rgPropertySets == NULL) RRETURN (E_INVALIDARG); for(ipropset =0; ipropset