//----------------------------------------------------------------------------- // Microsoft OLE DB RowsetViewer // Copyright (C) 1994 - 1999 By Microsoft Corporation. // // @doc // // @module PROPERTY.CPP // //----------------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////// // Includes // //////////////////////////////////////////////////////////////////////// #include "Headers.h" /////////////////////////////////////////////////////////////// // TPropBase // /////////////////////////////////////////////////////////////// template TPropBase::TPropBase(ULONG cElements, TYPE* rgElements) { if(cElements) Attach(cElements, rgElements); } /////////////////////////////////////////////////////////////// // ~TPropBase // /////////////////////////////////////////////////////////////// template TPropBase::~TPropBase() { RemoveAll(); } /////////////////////////////////////////////////////////////// // TPropBase::AddProperty // /////////////////////////////////////////////////////////////// template TYPE* TPropBase::AddProperty(DBPROPID dwPropertyID, const DBID& colid) { //See if the property exists... TYPE* pProp = FindProperty(dwPropertyID, colid); if(!pProp) { TYPE dbProp; memset(&dbProp, 0, sizeof(TYPE)); //Add this property... pProp = AddElement(dbProp); } return pProp; } /////////////////////////////////////////////////////////////// // CProperties // /////////////////////////////////////////////////////////////// CProperties::CProperties(DBPROPSET* pPropSet) { Attach(pPropSet); } /////////////////////////////////////////////////////////////// // ~CProperties // /////////////////////////////////////////////////////////////// CProperties::~CProperties() { } /////////////////////////////////////////////////////////////// // CProperties::Attach // /////////////////////////////////////////////////////////////// void CProperties::Attach(DBPROPSET* pPropSet) { //Delegate if(pPropSet) CVector::Attach(pPropSet->cProperties, pPropSet->rgProperties); } /////////////////////////////////////////////////////////////// // CProperties::Detach // /////////////////////////////////////////////////////////////// void CProperties::Detach(DBPROPSET* pPropSet) { //Delegate CVector::Detach(&pPropSet->cProperties, &pPropSet->rgProperties); } /////////////////////////////////////////////////////////////// // CProperties::RemoveAll // /////////////////////////////////////////////////////////////// void CProperties::RemoveAll() { //We need to walk and free out-of-line data... for(ULONG iProp=0; iProp::RemoveAll(); } /////////////////////////////////////////////////////////////// // CProperties::FindProperty // /////////////////////////////////////////////////////////////// DBPROP* CProperties::FindProperty(DBPROPID dwPropertyID, const DBID& colid) { //Loop over the array of properties in this set for(ULONG iProp=0; iPropdwPropertyID == dwPropertyID && DBIDEqual(&pProp->colid, &colid)) return pProp; } return NULL; } /////////////////////////////////////////////////////////////// // CProperties::SetProperty // /////////////////////////////////////////////////////////////// HRESULT CProperties::SetProperty(DBPROPID dwPropertyID, DBTYPE wType, void* pv, DBPROPOPTIONS dwOptions, const DBID& colid) { HRESULT hr = S_OK; //Add this property (if it doesn't already exist) DBPROP* pProp = AddProperty(dwPropertyID, colid); if(!pProp) TESTC(hr = E_OUTOFMEMORY); //Free any previous value VariantClearFast(&pProp->vValue); DBIDFree(&pProp->colid); //Setup the new property pProp->dwPropertyID = dwPropertyID; pProp->dwOptions = dwOptions; pProp->dwStatus = DBPROPSTATUS_OK; //Copy the colid DBIDCopy(&pProp->colid, &colid); //Copy the Value pProp->vValue.vt = wType; switch(wType) { case DBTYPE_BOOL: V_BOOL(&pProp->vValue) = (VARIANT_BOOL)pv; break; case DBTYPE_I2: V_I2(&pProp->vValue) = (SHORT)(ULONG_PTR)(pv); break; case DBTYPE_I4: V_I4(&pProp->vValue) = (LONG)(ULONG_PTR)(pv); break; #ifdef _WIN64 case DBTYPE_I8: //TODO64: V_I8(&pProp->vValue) = (LONG_PTR)pv; pProp->vValue.ullVal = (LONG_PTR)pv; break; #endif //_WIN64 case DBTYPE_WSTR: case DBTYPE_BSTR: V_BSTR(&pProp->vValue) = SysAllocString((BSTR)pv); break; case DBTYPE_VARIANT: XTEST(VariantCopyFast(&pProp->vValue, (VARIANT*)pv)); break; default: ASSERT(FALSE); //Unhandled property type TESTC(hr = E_INVALIDARG); break; } CLEANUP: return hr; } /////////////////////////////////////////////////////////////// // CPropertyInfos // /////////////////////////////////////////////////////////////// CPropertyInfos::CPropertyInfos(DBPROPINFOSET* pPropSet) { Attach(pPropSet); } /////////////////////////////////////////////////////////////// // ~CPropertyInfos // /////////////////////////////////////////////////////////////// CPropertyInfos::~CPropertyInfos() { } /////////////////////////////////////////////////////////////// // CPropertyInfos::Attach // /////////////////////////////////////////////////////////////// void CPropertyInfos::Attach(DBPROPINFOSET* pPropSet) { //Delegate if(pPropSet) CVector::Attach(pPropSet->cPropertyInfos, pPropSet->rgPropertyInfos); } /////////////////////////////////////////////////////////////// // CPropertyInfos::Detach // /////////////////////////////////////////////////////////////// void CPropertyInfos::Detach(DBPROPINFOSET* pPropSet) { //Delegate CVector::Detach(&pPropSet->cPropertyInfos, &pPropSet->rgPropertyInfos); } /////////////////////////////////////////////////////////////// // CPropertyInfos::RemoveAll // /////////////////////////////////////////////////////////////// void CPropertyInfos::RemoveAll() { //We need to walk and free out-of-line data... for(ULONG iProp=0; iProp::RemoveAll(); } /////////////////////////////////////////////////////////////// // CPropertyInfos::FindProperty // /////////////////////////////////////////////////////////////// DBPROPINFO* CPropertyInfos::FindProperty(DBPROPID dwPropertyID, const DBID& colid) { //Loop over the array of properties in this set for(ULONG iPropInfo=0; iPropInfodwPropertyID == dwPropertyID) return pPropInfo; } return NULL; } /////////////////////////////////////////////////////////////// // CPropertyIDs // /////////////////////////////////////////////////////////////// CPropertyIDs::CPropertyIDs(DBPROPIDSET* pPropSet) { Attach(pPropSet); } /////////////////////////////////////////////////////////////// // ~CPropertyIDs // /////////////////////////////////////////////////////////////// CPropertyIDs::~CPropertyIDs() { } /////////////////////////////////////////////////////////////// // CPropertyIDs::Attach // /////////////////////////////////////////////////////////////// void CPropertyIDs::Attach(DBPROPIDSET* pPropSet) { //Delegate if(pPropSet) CVector::Attach(pPropSet->cPropertyIDs, pPropSet->rgPropertyIDs); } /////////////////////////////////////////////////////////////// // CPropertyIDs::Detach // /////////////////////////////////////////////////////////////// void CPropertyIDs::Detach(DBPROPIDSET* pPropSet) { //Delegate CVector::Detach(&pPropSet->cPropertyIDs, &pPropSet->rgPropertyIDs); } /////////////////////////////////////////////////////////////// // CPropertyIDs::FindProperty // /////////////////////////////////////////////////////////////// DBPROPID* CPropertyIDs::FindProperty(DBPROPID dwPropertyID, const DBID& colid) { //Loop over the array of properties in this set for(ULONG iProp=0; iProp TPropSetBase::TPropSetBase(ULONG cElements, TYPE* rgElements) { if(cElements) Attach(cElements, rgElements); } /////////////////////////////////////////////////////////////// // ~TPropSetBase // /////////////////////////////////////////////////////////////// template TPropSetBase::~TPropSetBase() { RemoveAll(); } /////////////////////////////////////////////////////////////// // TPropSetBase::RemoveAll // /////////////////////////////////////////////////////////////// template void TPropSetBase::RemoveAll() { //We need to walk and free out-of-line data... ::FreeProperties(&m_cElements, &m_rgElements); //Delegate CVector::RemoveAll(); } /////////////////////////////////////////////////////////////// // TPropSetBase::AddPropSet // /////////////////////////////////////////////////////////////// template TYPE* TPropSetBase::AddPropSet(REFGUID guidPropertySet) { //See if the property set already exists... TYPE* pPropSet = FindPropSet(guidPropertySet); if(!pPropSet) { TYPE dbPropSet; memset(&dbPropSet, 0, sizeof(TYPE)); dbPropSet.guidPropertySet = guidPropertySet; //Add this property set pPropSet = AddElement(dbPropSet); } return pPropSet; } /////////////////////////////////////////////////////////////// // TPropSetBase::FindPropSet // /////////////////////////////////////////////////////////////// template TYPE* TPropSetBase::FindPropSet(REFGUID guidPropertySet) { //Loop over the number of property sets for(ULONG iPropSet=0; iPropSetguidPropertySet) return pPropSet; } return NULL; } /////////////////////////////////////////////////////////////// // CPropSets // /////////////////////////////////////////////////////////////// CPropSets::CPropSets(ULONG cPropSets, DBPROPSET* rgPropSets) : TPropSetBase(cPropSets, rgPropSets) { } /////////////////////////////////////////////////////////////// // ~CPropSets // /////////////////////////////////////////////////////////////// CPropSets::~CPropSets() { } /////////////////////////////////////////////////////////////// // CPropSets::SetProperty // /////////////////////////////////////////////////////////////// HRESULT CPropSets::SetProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet, DBTYPE wType, void* pv, DBPROPOPTIONS dwOptions, const DBID& colid) { //Add this property set (if doesn't already exist) DBPROPSET* pPropSet = AddPropSet(guidPropertySet); if(!pPropSet) return E_OUTOFMEMORY; //Delegate CProperties sCProperties(pPropSet); HRESULT hr = sCProperties.SetProperty(dwPropertyID, wType, pv, dwOptions, colid); sCProperties.Detach(pPropSet); return hr; } /////////////////////////////////////////////////////////////// // CPropSets::FindProperty // /////////////////////////////////////////////////////////////// DBPROP* CPropSets::FindProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet, const DBID& colid) { //Find the property set... DBPROPSET* pPropSet = FindPropSet(guidPropertySet); if(pPropSet) { CProperties sCProperties(pPropSet); DBPROP* pProp = sCProperties.FindProperty(dwPropertyID, colid); sCProperties.Detach(pPropSet); return pProp; } return NULL; } /////////////////////////////////////////////////////////////// // CPropInfoSets // /////////////////////////////////////////////////////////////// CPropInfoSets::CPropInfoSets(ULONG cPropInfoSets, DBPROPINFOSET* rgPropInfoSets) : TPropSetBase(cPropInfoSets, rgPropInfoSets) { } /////////////////////////////////////////////////////////////// // ~CPropInfoSets // /////////////////////////////////////////////////////////////// CPropInfoSets::~CPropInfoSets() { } /////////////////////////////////////////////////////////////// // CPropInfoSets::FindProperty // /////////////////////////////////////////////////////////////// DBPROPINFO* CPropInfoSets::FindProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet) { //Find the property set... DBPROPINFOSET* pPropSet = FindPropSet(guidPropertySet); if(pPropSet) { CPropertyInfos sCProperties(pPropSet); DBPROPINFO* pProp = sCProperties.FindProperty(dwPropertyID, DB_NULLID); sCProperties.Detach(pPropSet); return pProp; } return NULL; } /////////////////////////////////////////////////////////////// // CPropIDSets // /////////////////////////////////////////////////////////////// CPropIDSets::CPropIDSets(ULONG cPropIDSets, DBPROPIDSET* rgPropIDSets) : TPropSetBase(cPropIDSets, rgPropIDSets) { } /////////////////////////////////////////////////////////////// // ~CPropIDSets // /////////////////////////////////////////////////////////////// CPropIDSets::~CPropIDSets() { } /////////////////////////////////////////////////////////////// // CPropIDSets::SetProperty // /////////////////////////////////////////////////////////////// HRESULT CPropIDSets::SetProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet) { //Add this property set (if doesn't already exist) DBPROPIDSET* pPropSet = AddPropSet(guidPropertySet); if(!pPropSet) return E_OUTOFMEMORY; //Delegate CPropertyIDs sCProperties(pPropSet); HRESULT hr = sCProperties.SetProperty(dwPropertyID); sCProperties.Detach(pPropSet); return hr; } /////////////////////////////////////////////////////////////// // CPropIDSets::FindProperty // /////////////////////////////////////////////////////////////// DBPROPID* CPropIDSets::FindProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet) { //Find the property set... DBPROPIDSET* pPropSet = FindPropSet(guidPropertySet); if(pPropSet) { CPropertyIDs sCProperties(pPropSet); DBPROPID* pProp = sCProperties.FindProperty(dwPropertyID, DB_NULLID); sCProperties.Detach(pPropSet); return pProp; } return NULL; } //////////////////////////////////////////////////////////////////////////// // Find the Property Set within the PropInfoSets and return a pointer to it // //////////////////////////////////////////////////////////////////////////// DBPROPINFOSET* FindPropSet(REFGUID guidPropertySet, ULONG cPropInfoSets, DBPROPINFOSET* rgPropInfoSets) { //Loop over the property sets for(ULONG iPropSet=0; iPropSetguidPropertySet) return pPropInfoSet; } return NULL; } //////////////////////////////////////////////////////////////////////////// // Find the Property within the PropInfoSets and return a pointer to it // //////////////////////////////////////////////////////////////////////////// DBPROPINFO* FindProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet, ULONG cPropInfoSets, DBPROPINFOSET* rgPropInfoSets) { //Loop over the number of property sets for(ULONG iPropSet=0; iPropSetguidPropertySet) continue; //Loop over the array of properties in this set for(ULONG iProp=0; iPropcPropertyInfos; iProp++) { DBPROPINFO* pPropInfo = &pPropInfoSet->rgPropertyInfos[iProp]; if(pPropInfo->dwPropertyID == dwPropertyID) return pPropInfo; } } return NULL; } //////////////////////////////////////////////////////////////////////////// // CombineProperties // //////////////////////////////////////////////////////////////////////////// HRESULT CombineProperties(ULONG* pcPropInfoSets, DBPROPINFOSET** prgPropInfoSets, ULONG cPropInfoSets2, DBPROPINFOSET* rgPropInfoSets2, BOOL bFreeAddedPropSet) { ASSERT(pcPropInfoSets); ASSERT(prgPropInfoSets); HRESULT hr = S_OK; //Make our lives a little easier... ULONG cPropInfoSets = *pcPropInfoSets; DBPROPINFOSET* rgPropInfoSets = *prgPropInfoSets; //Now combine both sets... if(cPropInfoSets2 && rgPropInfoSets2) { if(cPropInfoSets && rgPropInfoSets) { //Loop over all the provider returned properties, and see if they //already exist in the OLE DB Defined properties. for(ULONG iPropSet=0; iPropSetguidPropertySet, cPropInfoSets, rgPropInfoSets); if(pFoundSet) { //Add all properties of this set... for(ULONG iProp=0; iPropcPropertyInfos; iProp++) { DBPROPINFO* pPropInfo2 = &pPropInfoSet2->rgPropertyInfos[iProp]; DBPROPINFO* pFoundProp = FindProperty(pPropInfo2->dwPropertyID, pPropInfoSet2->guidPropertySet, 1, pFoundSet); if(pFoundProp) { //Found the propertyset as well as the property //just need to update it in the list... *pFoundProp = *pPropInfo2; } else { //Found the property set, but not the property //just need to add this property to the list... SAFE_REALLOC(pFoundSet->rgPropertyInfos, DBPROPINFO, pFoundSet->cPropertyInfos + 1); pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos] = *pPropInfo2; pFoundSet->cPropertyInfos++; } //Do we need to make a copy of the variant... if(!bFreeAddedPropSet) { //TODO //Also what about the stringbuffer with property descriptions? } } } else { //Need to add the entire property set, as well as all the properties. SAFE_REALLOC(rgPropInfoSets, DBPROPINFOSET, cPropInfoSets + 1); rgPropInfoSets[cPropInfoSets].guidPropertySet = pPropInfoSet2->guidPropertySet; rgPropInfoSets[cPropInfoSets].cPropertyInfos = pPropInfoSet2->cPropertyInfos; //Add all the properties of this set... SAFE_ALLOC(rgPropInfoSets[cPropInfoSets].rgPropertyInfos, DBPROPINFO, pPropInfoSet2->cPropertyInfos); for(ULONG iProp=0; iPropcPropertyInfos; iProp++) { rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp] = pPropInfoSet2->rgPropertyInfos[iProp]; //Do we need to make a copy of the variant... if(!bFreeAddedPropSet) { //TODO //Also what about the stringbuffer with property descriptions? } } cPropInfoSets++; } //We are done with this array of properties... if(bFreeAddedPropSet) SAFE_FREE(pPropInfoSet2->rgPropertyInfos); } //NOTE: In the process of combining both of these sets, we are doing //direct memory copy of the internal DBPROPINFO items, this way //we don't need to variant copy all the values, and duplicate all the //strings. But this also requires that we don't free the source of the //copies as well. So we will finally end up freeing the combined //property sets (cPropInfoSets) but not (cPropInfoSets2) if(bFreeAddedPropSet) SAFE_FREE(rgPropInfoSets2); } else { cPropInfoSets = cPropInfoSets2; rgPropInfoSets = rgPropInfoSets2; } } CLEANUP: *pcPropInfoSets = cPropInfoSets; *prgPropInfoSets = rgPropInfoSets; return hr; } //////////////////////////////////////////////////////////////////////////// // CombineProperties // //////////////////////////////////////////////////////////////////////////// HRESULT CombineProperties(ULONG* pcPropInfoSets, DBPROPINFOSET** prgPropInfoSets, ULONG cPropSets2, DBPROPSET* rgPropSets2, BOOL bFreeAddedPropSet) { ASSERT(pcPropInfoSets); ASSERT(prgPropInfoSets); HRESULT hr = S_OK; //Make our lives a little easier... ULONG cPropInfoSets = *pcPropInfoSets; DBPROPINFOSET* rgPropInfoSets = *prgPropInfoSets; //Now combine both sets... if(cPropSets2 && rgPropSets2) { //Loop over all the provider returned properties, and see if they //already exist in the OLE DB Defined properties. for(ULONG iPropSet=0; iPropSetguidPropertySet, cPropInfoSets, rgPropInfoSets); if(pFoundSet) { //Add all properties of this set... for(ULONG iProp=0; iPropcProperties; iProp++) { DBPROP* pProp2 = &pPropSet2->rgProperties[iProp]; DBPROPINFO* pFoundProp = FindProperty(pProp2->dwPropertyID, pPropSet2->guidPropertySet, 1, pFoundSet); if(pFoundProp) { //Found the propertyset as well as the property //just need to update it in the list... pFoundProp->dwPropertyID = pProp2->dwPropertyID; pFoundProp->vValues = pProp2->vValue; //Update the Type (if its meaningful...) if(pProp2->vValue.vt != VT_EMPTY) pFoundProp->vtType = pProp2->vValue.vt; //NOTE: WE store the dwOptions flag within the DBPROPFLAGS_REQUIRED ENABLE_BIT(pFoundProp->dwFlags, DBPROPFLAGS_REQUIRED, pProp2->dwOptions == DBPROPOPTIONS_REQUIRED); } else { //Found the property set, but not the property //just need to add this property to the list... SAFE_REALLOC(pFoundSet->rgPropertyInfos, DBPROPINFO, pFoundSet->cPropertyInfos + 1); memset(&pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos], 0, sizeof(DBPROPINFO)); pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos].dwPropertyID = pProp2->dwPropertyID; pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos].vtType = pProp2->vValue.vt; pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos].vValues = pProp2->vValue; //NOTE: WE store the dwOptions flag within the DBPROPFLAGS_REQUIRED ENABLE_BIT(pFoundSet->rgPropertyInfos[pFoundSet->cPropertyInfos].dwFlags, DBPROPFLAGS_REQUIRED, pProp2->dwOptions == DBPROPOPTIONS_REQUIRED); pFoundSet->cPropertyInfos++; } //Do we need to make a copy of the variant... if(!bFreeAddedPropSet) { //TODO //Also what about the stringbuffer with property descriptions? } } } else { //Need to add the entire property set, as well as all the properties. SAFE_REALLOC(rgPropInfoSets, DBPROPINFOSET, cPropInfoSets + 1); rgPropInfoSets[cPropInfoSets].guidPropertySet = pPropSet2->guidPropertySet; rgPropInfoSets[cPropInfoSets].cPropertyInfos = pPropSet2->cProperties; //Add all the properties of this set... SAFE_ALLOC(rgPropInfoSets[cPropInfoSets].rgPropertyInfos, DBPROPINFO, pPropSet2->cProperties); for(ULONG iProp=0; iPropcProperties; iProp++) { memset(&rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp], 0, sizeof(DBPROPINFO)); rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp].dwPropertyID = pPropSet2->rgProperties[iProp].dwPropertyID; rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp].vtType = pPropSet2->rgProperties[iProp].vValue.vt; rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp].vValues = pPropSet2->rgProperties[iProp].vValue; //NOTE: WE store the dwOptions flag within the DBPROPFLAGS_REQUIRED ENABLE_BIT(rgPropInfoSets[cPropInfoSets].rgPropertyInfos[iProp].dwFlags, DBPROPFLAGS_REQUIRED, pPropSet2->rgProperties[iProp].dwOptions == DBPROPOPTIONS_REQUIRED); //Do we need to make a copy of the variant... if(!bFreeAddedPropSet) { //TODO //Also what about the stringbuffer with property descriptions? } } cPropInfoSets++; } //We are done with this array of properties... if(bFreeAddedPropSet) SAFE_FREE(pPropSet2->rgProperties); } //NOTE: In the process of combining both of these sets, we are doing //direct memory copy of the internal DBPROPINFO items, this way //we don't need to variant copy all the values, and duplicate all the //strings. But this also requires that we don't free the source of the //copies as well. So we will finally end up freeing the combined //property sets (cPropInfoSets) but not (cPropInfoSets2) if(bFreeAddedPropSet) SAFE_FREE(rgPropSets2); } CLEANUP: *pcPropInfoSets = cPropInfoSets; *prgPropInfoSets = rgPropInfoSets; return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT GetProperty // // Get the property information from the data source or object. // propid specifies the property and propset specifies the property set to which // propid belongs. The datatype of the property is required for the correct // coercion of the data ///////////////////////////////////////////////////////////////////////////// HRESULT GetProperty(REFIID riid, IUnknown* pIUnknown, DBPROPID dwPropertyID, REFGUID guidPropertySet, DBPROP** ppProperty) { ASSERT(ppProperty); *ppProperty = NULL; HRESULT hr = S_OK; //Invalid Arguments if(!pIUnknown) return E_INVALIDARG; ULONG cPropSets = 0; DBPROPSET* rgPropSets = NULL; const ULONG cPropertyIDSets = 1; DBPROPIDSET rgPropertyIDSets[cPropertyIDSets]; //SetUp input DBPROPIDSET struct (all static) rgPropertyIDSets[0].cPropertyIDs = cPropertyIDSets; rgPropertyIDSets[0].rgPropertyIDs = &dwPropertyID; rgPropertyIDSets[0].guidPropertySet = guidPropertySet; //Need to figure out which Interface was passed in //IDBInitialize, or ICommand, or IRowset, all three allow GetProperties if(riid == IID_IDBProperties) { //GetProperties, property might not be supported hr = ((IDBProperties*)pIUnknown)->GetProperties(cPropertyIDSets, rgPropertyIDSets, &cPropSets, &rgPropSets); } else if(riid == IID_ICommandProperties) { //GetProperties, property might not be supported hr = ((ICommandProperties*)pIUnknown)->GetProperties(cPropertyIDSets, rgPropertyIDSets, &cPropSets, &rgPropSets); } else if(riid == IID_IRowsetInfo) { //GetProperties, property might not be supported hr = ((IRowsetInfo*)pIUnknown)->GetProperties(cPropertyIDSets, rgPropertyIDSets, &cPropSets, &rgPropSets); } //Check return result //Can be DB_S_ / DB_E_ERRORSOCCURRED if notsupported property... if(FAILED(hr) && hr != DB_E_ERRORSOCCURRED) TESTC(hr); //Verify results ASSERTC(cPropSets==1 && rgPropSets!=NULL); ASSERTC(rgPropSets[0].cProperties==1 && rgPropSets[0].rgProperties!=NULL); ASSERTC(rgPropSets[0].rgProperties[0].dwPropertyID == dwPropertyID); //Return the property to the user *ppProperty = rgPropSets[0].rgProperties; CLEANUP: //Just Free the outer Struct, //since we return the inner Property for the user to free SAFE_FREE(rgPropSets); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT GetProperty // ///////////////////////////////////////////////////////////////////////////// HRESULT GetProperty(REFIID riid, IUnknown* pIUnknown, DBPROPID dwPropertyID, REFGUID guidPropertySet, DBTYPE wType, void* pv) { ASSERT(pv); HRESULT hr = S_OK; DBPROP* pProp = NULL; //Delegate hr = GetProperty(riid, pIUnknown, dwPropertyID, guidPropertySet, &pProp); //Put the value in the users buffer... if(SUCCEEDED(hr) && pProp) { //If the types are not what the user expected to receive then //we have to fail since pValue is of type wType. if(wType != pProp->vValue.vt) { //Free the property (since were not returning it to the user...) XTEST(hr = VariantClearFast(&pProp->vValue)); TESTC(hr = E_INVALIDARG); } switch(wType) { case DBTYPE_BOOL: *(VARIANT_BOOL*)pv = V_BOOL(&pProp->vValue); break; case DBTYPE_I2: *(SHORT*)pv = V_I2(&pProp->vValue); break; case DBTYPE_I4: *(LONG*)pv = V_I4(&pProp->vValue); break; #ifdef _WIN64 case DBTYPE_I8: //TODO64: *(LONG_PTR*)pv = V_I8(&pProp->vValue); *(LONG_PTR*)pv = pProp->vValue.ullVal; break; #endif //_WIN64 case DBTYPE_WSTR: case DBTYPE_BSTR: *(BSTR*)pv = V_BSTR(&pProp->vValue); break; case DBTYPE_VARIANT: *(VARIANT*)pv = pProp->vValue; //Assignment break; default: ASSERT(FALSE); //Unhandled property type TESTC(hr = E_INVALIDARG); break; }; } CLEANUP: //NOTE: GetProperty returns a pointer to the DBPROP (rgProperties) which is allocated //and needs to be free'd. But the actual value we passed directly to the user which //is required to free the value, but we need to the free the outer array SAFE_FREE(pProp); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT GetPropInfo // ///////////////////////////////////////////////////////////////////////////// HRESULT GetPropInfo(IDBProperties* pIDBProperties, DBPROPID dwPropertyID, REFGUID guidPropertySet, DBPROPINFO** ppPropInfo) { if(ppPropInfo) *ppPropInfo = NULL; if(!pIDBProperties) return E_FAIL; HRESULT hr = S_OK; const ULONG cPropIDSets = 1; DBPROPIDSET rgPropIDSets[cPropIDSets]; ULONG cPropInfoSets = 0; DBPROPINFOSET* rgPropInfoSets = NULL; //Construct the DBPROPIDSET structure rgPropIDSets[0].cPropertyIDs = 1; rgPropIDSets[0].rgPropertyIDs = &dwPropertyID; rgPropIDSets[0].guidPropertySet = guidPropertySet; //Don't display dialog if errors occurred. //Errors can occur if properties are not supported by the provider TESTC(hr = pIDBProperties->GetPropertyInfo(cPropIDSets,rgPropIDSets,&cPropInfoSets,&rgPropInfoSets,NULL)); CLEANUP: *ppPropInfo = rgPropInfoSets ? rgPropInfoSets[0].rgPropertyInfos : NULL; SAFE_FREE(rgPropInfoSets); return hr; } ///////////////////////////////////////////////////////////////////////////// // DBPROPFLAGS GetPropInfoFlags // ///////////////////////////////////////////////////////////////////////////// DBPROPFLAGS GetPropInfoFlags(IDBProperties* pIDBProperties, DBPROPID dwPropertyID, REFGUID guidPropertySet) { if(!pIDBProperties) return 0; DBPROPINFO* pPropInfo = NULL; DBPROPFLAGS dwFlags = DBPROPFLAGS_NOTSUPPORTED; //GetPropInfo TESTC(GetPropInfo(pIDBProperties, dwPropertyID, guidPropertySet, &pPropInfo)); if(pPropInfo) { dwFlags = pPropInfo->dwFlags; //Free the variant, could contain a safearray or similar... XTEST(VariantClearFast(&pPropInfo->vValues)); } CLEANUP: SAFE_FREE(pPropInfo); return dwFlags; } ///////////////////////////////////////////////////////////////////////////// // BOOL IsSupportedProperty // ///////////////////////////////////////////////////////////////////////////// BOOL IsSupportedProperty(IDBProperties* pIDBProperties, DBPROPID dwPropertyID, REFGUID guidPropertySet) { return GetPropInfoFlags(pIDBProperties, dwPropertyID, guidPropertySet) != DBPROPFLAGS_NOTSUPPORTED; } ///////////////////////////////////////////////////////////////////////////// // BOOL IsSettableProperty // ///////////////////////////////////////////////////////////////////////////// BOOL IsSettableProperty(IDBProperties* pIDBProperties, DBPROPID dwPropertyID, REFGUID guidPropertySet) { return GetPropInfoFlags(pIDBProperties, dwPropertyID, guidPropertySet) & DBPROPFLAGS_WRITE; } ///////////////////////////////////////////////////////////////////////////// // HRESULT SetProperty // ///////////////////////////////////////////////////////////////////////////// HRESULT SetProperty(DBPROPID dwPropertyID, REFGUID guidPropertySet, ULONG* pcPropSets, DBPROPSET** prgPropSets, DBTYPE wType, void* pv, DBPROPOPTIONS dwOptions, const DBID& colid) { ASSERT(prgPropSets && pcPropSets); //The simplest Approach is to just use our class... CPropSets sCPropSets(*pcPropSets, *prgPropSets); //Delegate HRESULT hr = sCPropSets.SetProperty(dwPropertyID, guidPropertySet, wType, pv, dwOptions, colid); //Return the properties to the user and remove from static class... sCPropSets.Detach(pcPropSets, prgPropSets); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT FreeProperties // ///////////////////////////////////////////////////////////////////////////// HRESULT FreeProperties(ULONG* pcProperties, DBPROP** prgProperties) { ASSERT(pcProperties); ASSERT(prgProperties); HRESULT hr = S_OK; //no-op case if(*pcProperties==0 || *prgProperties==NULL) return S_OK; //Free the inner variants first for(ULONG iProp=0; iProp<*pcProperties; iProp++) { DBPROP* pProp = &((*prgProperties)[iProp]); XTEST(hr = VariantClearFast(&pProp->vValue)); } //Now NULL the set *pcProperties = 0; SAFE_FREE(*prgProperties); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT FreeProperties // ///////////////////////////////////////////////////////////////////////////// HRESULT FreeProperties(ULONG* pcPropSets, DBPROPSET** prgPropSets) { ASSERT(pcPropSets); ASSERT(prgPropSets); HRESULT hr = S_OK; //Loop over all the property sets for(ULONG iPropSet=0; iPropSet<*pcPropSets; iPropSet++) { DBPROPSET* pPropSet = &((*prgPropSets)[iPropSet]); FreeProperties(&pPropSet->cProperties, &pPropSet->rgProperties); } //Now NULL the outer set *pcPropSets = 0; SAFE_FREE(*prgPropSets); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT FreeProperties // ///////////////////////////////////////////////////////////////////////////// HRESULT FreeProperties(ULONG* pcPropIDSets, DBPROPIDSET** prgPropIDSets) { ASSERT(pcPropIDSets); ASSERT(prgPropIDSets); HRESULT hr = S_OK; //Loop over all the property sets for(ULONG iPropIDSet=0; iPropIDSet<*pcPropIDSets; iPropIDSet++) { DBPROPIDSET* pPropIDSet = &((*prgPropIDSets)[iPropIDSet]); SAFE_FREE(pPropIDSet->rgPropertyIDs); } //Now NULL the outer set *pcPropIDSets = 0; SAFE_FREE(*prgPropIDSets); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT FreeProperties // ///////////////////////////////////////////////////////////////////////////// HRESULT FreeProperties(ULONG* pcPropInfoSets, DBPROPINFOSET** prgPropInfoSets) { ASSERT(pcPropInfoSets); ASSERT(prgPropInfoSets); HRESULT hr = S_OK; //Loop over all the property info sets for(ULONG iPropSet=0; iPropSet<*pcPropInfoSets; iPropSet++) { DBPROPINFOSET* pPropInfoSet = &((*prgPropInfoSets)[iPropSet]); //Free the inner variants first for(ULONG iProp=0; iPropcPropertyInfos; iProp++) { DBPROPINFO* pPropInfo = &pPropInfoSet->rgPropertyInfos[iProp]; XTEST(hr = VariantClearFast(&pPropInfo->vValues)); } //Now free the set SAFE_FREE(pPropInfoSet->rgPropertyInfos); } //Now free the outer set *pcPropInfoSets = 0; SAFE_FREE((*prgPropInfoSets)); return hr; }