|
|
// object.cpp : Implementation of CObject
#include "stdafx.h"
#include "object.h"
#include "Property.h"
#include "Service.h"
#include "Program.h"
#include "ScheduleEntry.h"
#if 0
#undef TIMING
#define TIMING 1
#include "timing.h"
#endif
class _bstr_t2 : public _bstr_t { public: _bstr_t2(IID iid) { OLECHAR sz[40];
StringFromGUID2(iid, sz, sizeof(sz)/sizeof(OLECHAR));
_bstr_t::operator =(sz); } };
HRESULT CObject::get_RelatedObjectID(boolean fInverse, long id, long idRel, long *pidRet) { HRESULT hr; ADODB::_RecordsetPtr prs; const TCHAR *szID = !fInverse ? _T("idObj1") : _T("idObj2"); const TCHAR *szIDRet = !fInverse ? _T("idObj2") : _T("idObj1");
if (!fInverse) { hr = m_pdb->get_RelsByID1Rel(&prs); szID = _T("idObj1"); szIDRet = _T("idObj2"); } else { hr = m_pdb->get_RelsByID2Rel(&prs); szID = _T("idObj2"); szIDRet = _T("idObj1"); }
*pidRet = 0;
if (m_pdb->FSQLServer()) { TCHAR szFind[32];
prs->MoveFirst(); wsprintf(szFind, _T("%s = %d"), szID, id); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { _variant_t var(id); hr = prs->Seek(var, ADODB::adSeekFirstEQ); } if (FAILED(hr)) return S_FALSE; while (!prs->EndOfFile) { long idCur = prs->Fields->Item[szID]->Value; if (idCur != id) return S_FALSE; long idRelCur = prs->Fields->Item["idRel"]->Value; if (idRelCur == idRel) { *pidRet = prs->Fields->Item[szIDRet]->Value; return S_OK; } prs->MoveNext(); } return S_FALSE; }
HRESULT AddRelationship(ADODB::_RecordsetPtr prs, long idObj1, long idRel, long iOrder, long idObj2) { HRESULT hr;
hr = prs->AddNew(); if (FAILED(hr)) return hr; prs->Fields->Item["idObj1"]->Value = idObj1; prs->Fields->Item["idRel"]->Value = idRel; prs->Fields->Item["order"]->Value = iOrder; prs->Fields->Item["idObj2"]->Value = idObj2; hr = prs->Update();
return hr; }
HRESULT CObjects::AddRelationshipAt(long idObj1, long idRel, long iItem, long idObj2) { HRESULT hr; const long iOrderInc = 10;
ADODB::_RecordsetPtr prs; hr = m_pdb->get_RelsByID1Rel(&prs); if (FAILED(hr)) return hr;
if (m_pdb->FSQLServer()) { TCHAR szFind[32];
prs->MoveFirst(); wsprintf(szFind, _T("idObj1 = %d"), idObj1); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { _variant_t var(idObj1); hr = prs->Seek(var, ADODB::adSeekFirstEQ); } if (FAILED(hr)) return hr;
long iOrder = iOrderInc; long i; // Scan until we reach the requested item (or end)
for (i = 0; (i <= iItem) || (iItem == -1); i++) { if (prs->EndOfFile) break;
long idCur = prs->Fields->Item["idObj1"]->Value; if (idCur != idObj1) break; long idRelCur = prs->Fields->Item["idRel"]->Value; if (idRelCur != idRel) break;
prs->MoveNext(); }
// If there were any items, back up, and use the "order" value for the that one.
if (i > 0) { prs->MovePrevious(); iOrder = prs->Fields->Item["order"]->Value; // Now open up space by pushing up the items which follow.
if (iItem == -1) iOrder += iOrderInc; else { long iOrderCur = iOrder + 2*iOrderInc; long cItems = 1;
prs->MoveNext();
// Scan forward looking for a big enough gap.
while (!prs->EndOfFile) { long idCur = prs->Fields->Item["idObj1"]->Value; if (idCur == idObj1) { long idRelCur = prs->Fields->Item["idRel"]->Value; if (idRelCur == idRel) { iOrderCur = prs->Fields->Item["order"]->Value; if (iOrderCur > iOrder + cItems*2) break; cItems++; prs->MoveNext(); continue; } }
// We've reached the end... just space them all iOrderInc apart.
iOrderCur = iOrder + (cItems + 1)*iOrderInc; break; } long dSpace = (iOrderCur - iOrder)/(cItems + 1);
// Then scan backward spreading the gap evenly between the items.
for (long c = 0; c < cItems; c++) { if (prs->EndOfFile) { // MovePrevious doen't seem to work from EndOfFile...
// Use MoveLast instead
prs->MoveLast(); #ifdef _DEBUG
long iOrderOld = prs->Fields->Item["order"]->Value; #endif
} else prs->MovePrevious(); iOrderCur -= dSpace; #ifdef _DEBUG
long iOrderOld = prs->Fields->Item["order"]->Value; TCHAR sz[256]; wsprintf(sz, _T("AddRelationshipAt : %d --> %d\n"), iOrderOld, iOrderCur); OutputDebugString(sz); #endif
prs->Fields->Item["order"]->Value = iOrderCur; prs->Update(); } }
} // The slot at iOrder has been opened up, so the new relation can now be added.
return AddRelationship(prs, idObj1, idRel, iOrder, idObj2); }
/////////////////////////////////////////////////////////////////////////////
// CObjectType
STDMETHODIMP CObjectType::get_ID(long *pid) { ENTER_API { ValidateOut<long>(pid, m_id);
return S_OK; } LEAVE_API } HRESULT CObjectType::GetDB(CGuideDB **ppdb) { *ppdb = m_pdb; if (*ppdb == NULL) return E_FAIL;
(*ppdb)->AddRef();
return S_OK; }
STDMETHODIMP CObjectType::get_IID(BSTR *pbstrIID) { ENTER_API { ValidateOut(pbstrIID);
OLECHAR sz[40];
StringFromGUID2(m_clsid, sz, sizeof(sz)/sizeof(OLECHAR));
_bstr_t bstr(sz);
*pbstrIID = bstr.copy();
return S_OK; } LEAVE_API }
HRESULT CObjectType::CreateInstance(long id, IUnknown **ppunk) { HRESULT hr;
CComPtr<CObject> pobj = NewComObjectCachedLRU(CObject);
if (pobj == NULL) return E_OUTOFMEMORY;
hr = pobj->Init(id, this); if (FAILED(hr)) return hr; *ppunk = pobj.Detach();
return S_OK; }
HRESULT CObjectType::get_NewCollection(IObjects * *ppobjs) { HRESULT hr;
CComPtr<CObjects> pobjs = NewComObjectCachedLRU(CObjects); if (pobjs == NULL) return E_OUTOFMEMORY; m_pdb->CacheCollection(pobjs); pobjs->put_DB(m_pdb); pobjs->put_ObjectType(this); if (!m_fKnowCollectionCLSID) { OLECHAR szCLSID[128];
wcscpy(szCLSID, L"CLSID\\"); long cch = wcslen(szCLSID);
StringFromGUID2(m_clsid, szCLSID + cch, sizeof(szCLSID)/sizeof(OLECHAR) - cch);
HKEY hkey; long lErr; lErr = RegOpenKeyEx(HKEY_CLASSES_ROOT, szCLSID, 0, KEY_READ, &hkey); if (lErr == ERROR_SUCCESS) { OLECHAR szCollectionCLSID[128]; DWORD cb = sizeof(szCollectionCLSID); DWORD regtype; lErr = RegQueryValueEx(hkey, _T("CollectionCLSID"), 0, ®type, (LPBYTE) szCollectionCLSID, &cb); RegCloseKey(hkey); if ((lErr == ERROR_SUCCESS) && (regtype == REG_SZ)) { hr = CLSIDFromString(szCollectionCLSID, &m_clsidCollection); if (SUCCEEDED(hr)) m_fKnowCollectionCLSID = TRUE; } } }
if (m_fKnowCollectionCLSID) { pobjs->Init(m_clsidCollection); } *ppobjs = pobjs.Detach(); return S_OK; }
STDMETHODIMP CObjectType::get_New(IUnknown **ppobj) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj, NULL);
HRESULT hr; ADODB::_RecordsetPtr prs; hr = m_pdb->get_ObjsRS(&prs); if (FAILED(hr)) return hr;
// Create a new record.
hr = prs->AddNew();
prs->Fields->Item["idType"]->Value = m_id;
hr = prs->Update();
long id = prs->Fields->Item["id"]->Value; return m_pdb->CacheObject(id, this, ppobj); } LEAVE_API }
/////////////////////////////////////////////////////////////////////////////
// CObjectTypes
HRESULT CObjectTypes::Init(CGuideDB *pdb) { m_pdb = pdb;
if (pdb == NULL) return E_INVALIDARG;
// Special case the "Object" object type
CObjectType *pobjtype; pobjtype = Cache(0, _bstr_t2(__uuidof(IUnknown)));
ADODB::_RecordsetPtr prs; m_pdb->get_ObjTypesRS(&prs); prs->MoveFirst(); while (!prs->EndOfFile) { // Read in all the records
long id = prs->Fields->Item["id"]->Value; bstr_t bstrCLSID = prs->Fields->Item["clsid"]->Value;
pobjtype = Cache(id, bstrCLSID); prs->MoveNext(); }
return S_OK; }
STDMETHODIMP CObjectTypes::get_ItemWithCLSID(BSTR bstrCLSID, CObjectType **ppobjtype) { ENTER_API { ValidateIn(bstrCLSID); ValidateOutPtr<CObjectType>(ppobjtype, NULL);
CLSID clsid;
HRESULT hr = CLSIDFromString(bstrCLSID, &clsid); if (hr == CO_E_CLASSSTRING) return hr;
t_map::iterator it = m_map.find(clsid); if (it == m_map.end()) return E_INVALIDARG;
*ppobjtype = (*it).second;
return S_OK; } LEAVE_API }
CObjectType *CObjectTypes::Cache(long id, BSTR bstrCLSID) { CObjectType *pobjtype = NULL; CLSID clsid;
HRESULT hr = CLSIDFromString(bstrCLSID, &clsid);
if (hr == CO_E_CLASSSTRING) return NULL;
t_map::iterator it = m_map.find(clsid); if (it != m_map.end()) { pobjtype = (*it).second; } else { pobjtype = new CObjectType;
if (pobjtype == NULL) return NULL;
pobjtype->Init(m_pdb, id, clsid);
m_map[clsid] = pobjtype; m_pdb->put_ObjectType(id, pobjtype); }
return pobjtype; }
STDMETHODIMP CObjectTypes::get_AddNew(BSTR bstrCLSID, CObjectType **ppobjtype) { ENTER_API { ValidateIn(bstrCLSID); ValidateOutPtr<CObjectType>(ppobjtype, NULL);
HRESULT hr;
hr = get_ItemWithCLSID(bstrCLSID, ppobjtype); if (SUCCEEDED(hr)) return hr;
ADODB::_RecordsetPtr prs; hr = m_pdb->get_ObjTypesRS(&prs); if (FAILED(hr)) return hr; // Create a new record.
hr = prs->AddNew(); if (FAILED(hr)) return hr;
prs->Fields->Item["clsid"]->Value = bstrCLSID;
hr = prs->Update(); if (FAILED(hr)) return hr;
long id = prs->Fields->Item["id"]->Value;
*ppobjtype = Cache(id, bstrCLSID);
if (*ppobjtype == NULL) return E_OUTOFMEMORY;
return S_OK; } LEAVE_API }
#if 0
STDMETHODIMP CObjectTypes::get_AddNew(CLSID clsid, CObjectType **ppobjtype) { ENTER_API { ValidateOutPtr<CObjectType>(ppobjtype, NULL);
return S_OK; } LEAVE_API } #endif
/////////////////////////////////////////////////////////////////////////////
// CObject
STDMETHODIMP CObject::Init(long id, CObjectType *pobjtype) { HRESULT hr; if (m_id != 0) return E_INVALIDARG; m_id = id; m_pobjtype = pobjtype; _ASSERTE(m_pobjtype != NULL); m_pdb = m_pobjtype->m_pdb;
if (m_pobjtype->m_id != 0) { hr = m_punk.CoCreateInstance(pobjtype->m_clsid, GetControllingUnknown()); if (FAILED(hr)) return hr; }
return S_OK; }
STDMETHODIMP CObject::Save(IUnknown *punk) { HRESULT hr; if (punk == NULL) punk = this;
CComQIPtr<IPersistPropertyBag> ppersistpropbag(punk); if (ppersistpropbag != NULL) { hr = CreatePropBag(ppersistpropbag);
hr = ppersistpropbag->Save(m_ppropbag, TRUE, FALSE); } else { CComQIPtr<IPersistStream> ppersiststream(punk); if (ppersiststream != NULL) { CComPtr<IStream> pstream; hr = CreateStreamOnHGlobal(NULL, TRUE, &pstream); if (FAILED(hr)) return hr;
// Write a tag to indicate IPersistStream was used.
char ch = Format_IPersistStream; ULONG cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); if (FAILED(hr)) return hr; // Now have the object save it's bits.
hr = ppersiststream->Save(pstream, TRUE); if (FAILED(hr)) return hr; // Create a SafeArray from the bits.
HANDLE hdata; hr = GetHGlobalFromStream(pstream, &hdata); if (FAILED(hr)) return hr; long cbData = GlobalSize(hdata); SAFEARRAY *parray = SafeArrayCreateVector(VT_UI1, 0, cbData); if (parray == NULL) return E_OUTOFMEMORY; BYTE *pbDst; hr = SafeArrayAccessData(parray, (void **) &pbDst); if (FAILED(hr)) return hr; BYTE *pbSrc = (BYTE *) GlobalLock(hdata);
memcpy(pbDst, pbSrc, cbData);
GlobalUnlock(hdata); SafeArrayUnaccessData(parray);
// Put the SafeArray in a variant
_variant_t varT; varT.vt = VT_ARRAY | VT_UI1; varT.parray = parray; // Write the bits to the database
ADODB::_RecordsetPtr prs; hr = m_pdb->get_ObjsByID(&prs); if (FAILED(hr)) return hr;
_variant_t var = m_id; prs->Seek(var, ADODB::adSeekFirstEQ); if (prs->EndOfFile) return E_FAIL;
hr = prs->Fields->Item["oValue"]->AppendChunk(varT); if (FAILED(hr)) return hr; } else { return E_INVALIDARG; } } return hr; }
STDMETHODIMP CObject::Load() { HRESULT hr; CComQIPtr<IPersistPropertyBag> ppersistpropbag(this); if (ppersistpropbag != NULL) { hr = CreatePropBag(ppersistpropbag);
hr = ppersistpropbag->Load(m_ppropbag, NULL); } else { CComQIPtr<IPersistStream> ppersiststream(this); if (ppersiststream != NULL) { ADODB::_RecordsetPtr prs; hr = m_pdb->get_ObjsByID(&prs); if (FAILED(hr)) return hr; _variant_t var = m_id; prs->Seek(var, ADODB::adSeekFirstEQ); if (prs->EndOfFile) return E_FAIL;
long cb; ADODB::FieldPtr pfield; pfield.Attach(prs->Fields->Item["oValue"]); hr = pfield->get_ActualSize(&cb); if (FAILED(hr)) return hr;
_variant_t varData; hr = pfield->GetChunk(cb, &varData); if (FAILED(hr)) return hr; if ((varData.vt & VT_ARRAY) == 0) return E_FAIL; BYTE *pbSrc; hr = SafeArrayAccessData(varData.parray, (void **) &pbSrc); if (FAILED(hr)) return hr; HANDLE hdata; BOOL fFree = FALSE; hdata = GlobalHandle(pbSrc); if (hdata == NULL) { hdata = GlobalAlloc(GHND, cb); if (hdata == NULL) { SafeArrayUnaccessData(varData.parray); return E_OUTOFMEMORY; } BYTE *pbDst = (BYTE *) GlobalLock(hdata);
memcpy(pbDst, pbSrc, cb); fFree = TRUE; } else { BYTE *pbTest = (BYTE *) GlobalLock(hdata); int i = 0; if (pbTest != pbSrc) i++; GlobalUnlock(hdata); }
{ CComPtr<IStream> pstream; hr = CreateStreamOnHGlobal(hdata, fFree, &pstream); if (FAILED(hr)) { if (fFree) GlobalFree(hdata); return hr; } char ch; ULONG cbT = sizeof(ch); hr = pstream->Read(&ch, cbT, &cbT); switch (ch) { case Format_IPersistStream: hr = ppersiststream->Load(pstream); break; default: hr = STG_E_DOCFILECORRUPT; } } SafeArrayUnaccessData(varData.parray); } }
return S_OK; }
HRESULT CObject::CreatePropBag(IPersist *ppersist) { HRESULT hr; if (m_ppropbag == NULL) { CComPtr<IMetaProperties> pprops; hr = get_MetaProperties(&pprops); if (FAILED(hr)) return hr; CLSID clsid; hr = ppersist->GetClassID(&clsid); if (FAILED(hr)) return hr; OLECHAR sz[40];
StringFromGUID2(clsid, sz, sizeof(sz)/sizeof(OLECHAR));
_bstr_t bstrCLSID(sz); CComPtr<IMetaPropertySet> ppropset; hr = m_pdb->get_MetaPropertySet(bstrCLSID, &ppropset); CComPtr<IMetaPropertyTypes> pproptypes; hr = ppropset->get_MetaPropertyTypes(&pproptypes); m_ppropbag = NewComObject(CObjectPropertyBag); m_ppropbag->Init(pprops, pproptypes); } return S_OK; }
STDMETHODIMP CObject::get_Type(CObjectType **ppobjtype) { ENTER_API { ValidateOutPtr<CObjectType>(ppobjtype, NULL);
_ASSERTE(m_pobjtype != NULL); *ppobjtype = m_pobjtype;
return S_OK; } LEAVE_API }
STDMETHODIMP CObject::get_ID(long *pid) { ENTER_API { ValidateOut<long>(pid, m_id);
return S_OK; } LEAVE_API }
STDMETHODIMP CObject::get_MetaProperties(IMetaProperties **ppprops) { ENTER_API { ValidateOutPtr<IMetaProperties>(ppprops, NULL); HRESULT hr;
if (m_pprops == NULL) { hr = m_pdb->get_MetaPropertiesOf((IUnknown *) this, &m_pprops); if (FAILED(hr)) return hr; }
if (m_pprops == NULL) return E_OUTOFMEMORY; return m_pprops.QueryInterface(ppprops); } LEAVE_API }
STDMETHODIMP CObject::get_ItemInverseRelatedBy(long idRel, IUnknown **ppobj1) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj1, NULL);
HRESULT hr;
long idObj1; hr = get_RelatedObjectID(TRUE, m_id, idRel, &idObj1); if (hr == S_FALSE || FAILED(hr)) return hr;
return m_pdb->CacheObject(idObj1, (long) 0, ppobj1); } LEAVE_API }
HRESULT CObject::get_ItemsRelatedBy(CObjectType *pobjtype, long idRel, boolean fInverse, IObjects **ppobjs) { HRESULT hr; hr = pobjtype->get_NewCollection(ppobjs); if (FAILED(hr)) return hr; CComQIPtr<CObjects> pobjs(*ppobjs);
hr = pobjs->InitRelation(this, idRel, fInverse);
return hr; }
STDMETHODIMP CObject::get_ItemsInverseRelatedBy(CObjectType *pobjtype, long idRel, IObjects **ppobjs) { ENTER_API { ValidateInPtr<CObjectType>(pobjtype); ValidateOutPtr<IObjects>(ppobjs, NULL);
return get_ItemsRelatedBy(pobjtype, idRel, TRUE, ppobjs); } LEAVE_API }
STDMETHODIMP CObject::get_ItemRelatedBy(long idRel, IUnknown **ppobj2) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj2, NULL);
HRESULT hr;
long idObj2; hr = get_RelatedObjectID(FALSE, m_id, idRel, &idObj2); if (hr == S_FALSE || FAILED(hr)) return hr;
return m_pdb->CacheObject(idObj2, (long) 0, ppobj2); } LEAVE_API }
STDMETHODIMP CObject::put_ItemRelatedBy(long idRel, IUnknown *pobj2) { ENTER_API { ValidateInPtr<IUnknown>(pobj2);
HRESULT hr; long idObj2;
m_pdb->get_IdOf(pobj2, &idObj2);
ADODB::_RecordsetPtr prs;
hr = m_pdb->get_RelsByID1Rel(&prs);
if (m_pdb->FSQLServer()) { TCHAR szFind[32];
prs->MoveFirst(); wsprintf(szFind, _T("idObj1 = %d"), m_id); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { _variant_t var(m_id); hr = prs->Seek(var, ADODB::adSeekFirstEQ); } if (FAILED(hr)) return hr; while (!prs->EndOfFile) { long idCur = prs->Fields->Item["idObj1"]->Value; if (idCur != m_id) break; long idRelCur = prs->Fields->Item["idRel"]->Value; if (idRelCur == idRel) { prs->Fields->Item["idObj2"]->Value = idObj2; return S_OK; } prs->MoveNext(); } return AddRelationship(prs, m_id, idRel, 0, idObj2); } LEAVE_API }
STDMETHODIMP CObject::get_ItemsRelatedBy(CObjectType *pobjtype, long idRel, IObjects **ppobjs) { ENTER_API { ValidateInPtr<CObjectType>(pobjtype); ValidateOutPtr<IObjects>(ppobjs, NULL);
return get_ItemsRelatedBy(pobjtype, idRel, FALSE, ppobjs); } LEAVE_API }
HRESULT CObjects::Clone(IObjects **ppobjs) { HRESULT hr; hr = m_pobjtype->get_NewCollection(ppobjs); if (FAILED(hr)) return hr;
CComQIPtr<CObjects> pobjs(*ppobjs);
pobjs->Copy(this); return hr; }
/////////////////////////////////////////////////////////////////////////////
// CObjects
// Sample Query:
//
// SELECT DISTINCT Objects.id
// FROM ((((
// Objects
// INNER JOIN ObjectRelationships
// ON Objects.id = ObjectRelationships.idObj2)
// INNER JOIN Properties AS Properties_0
// ON Objects.id = Properties_0.idObj)
// INNER JOIN Properties AS Properties_1
// ON Objects.id = Properties_1.idObj)
// INNER JOIN Properties AS Properties_2
// ON Objects.id = Properties_2.idObj)
// WHERE
// (((
// Objects.idType = 1)
// AND (ObjectRelationships.idObj1 = 10))
// AND
// (
// ((Properties_0.idPropType=15) AND (Properties_0.sValue="Arthur"))
// OR
// ((Properties_2.idPropType=15) AND (Properties_2.sValue="Jeopardy!"))
// )
// );
HRESULT CObjects::GetQuery(QueryType qtype, _bstr_t *pbstr) { TCHAR sz[8*1024]; HRESULT hr; _bstr_t bstrCmd; _bstr_t bstrFrom; _bstr_t bstrOrder; _bstr_t bstrWhere; long cWhere = 0;
switch (qtype) { case Select: bstrCmd = _T("SELECT DISTINCT Objects.id, Objects.idType "); break;
case Delete: bstrCmd = _T("DELETE Objects.* "); break; }
bstrFrom = "Objects";
_ASSERTE(m_pobjtype != NULL);
long idType = 0;
hr = m_pobjtype->get_ID(&idType); if (FAILED(hr)) return hr; if (idType != 0) { wsprintf(sz, _T("Objects.idType = %d"), idType); bstrWhere = sz; cWhere++; } if (m_fOnlyUnreferenced) { if (cWhere > 0) bstrWhere = bstrWhere + " AND ";
bstrWhere = bstrWhere + "(Objects.id NOT IN" + " (SELECT DISTINCT ObjectRelationships.idObj2 FROM ObjectRelationships))" + " AND (Objects.id NOT IN" + " (SELECT DISTINCT Properties.lValue FROM Properties WHERE Properties.ValueType = 13))"; cWhere++; } if ((qtype == Select) && (m_idPropTypeKey != 0)) { switch (m_vtKey) { default: return E_UNEXPECTED;
case VT_I2: case VT_I4: bstrCmd = bstrCmd + ", Props_Key.lValue"; bstrOrder = _T(" ORDER BY Props_Key.lValue"); break; case VT_R4: case VT_R8: case VT_DATE: bstrCmd = bstrCmd + ", Props_Key.fValue"; bstrOrder = _T(" ORDER BY Props_Key.fValue"); break; case VT_BSTR_BLOB: case VT_BSTR: bstrCmd = bstrCmd + ", left(Props_Key.sValue,255) AS sValue"; bstrOrder = _T(" ORDER BY left(Props_Key.sValue,255)"); break; }
wsprintf(sz, _T("(%s INNER JOIN Properties AS Props_Key") _T(" ON Objects.id = Props_Key.idObj)"), (const TCHAR *) bstrFrom); bstrFrom = sz; if (cWhere++ > 0) bstrWhere = bstrWhere + " AND "; wsprintf(sz, _T("(Props_Key.idPropType = %d) AND (Props_Key.ValueType = %d)"), m_idPropTypeKey, m_vtKey); bstrWhere = bstrWhere + sz; if (m_idProviderKey != 0) { wsprintf(sz, _T("AND (Props_Key.idProvider = %d)"), m_idProviderKey); bstrWhere = bstrWhere + sz; } if (m_idLangKey != 0) { wsprintf(sz, _T("AND (Props_Key.idLanguage = %d)"), m_idLangKey); bstrWhere = bstrWhere + sz; } } if (m_pobjRelated != NULL) { const TCHAR *szRelatedField; const TCHAR *szResultField;
if (!m_fInverse) { szRelatedField = _T("idObj1"); szResultField = _T("idObj2"); if (qtype == Select) { bstrCmd = bstrCmd + _T(", ObjectRelationships.[order]"); bstrOrder = _T(" ORDER BY ObjectRelationships.[order]"); } } else { szRelatedField = _T("idObj2"); szResultField = _T("idObj1"); }
wsprintf(sz, _T("(%s INNER JOIN ObjectRelationships") _T(" ON Objects.id = ObjectRelationships.%s)"), (const TCHAR *) bstrFrom, szResultField); bstrFrom = sz;
long id;
m_pdb->get_IdOf(m_pobjRelated, &id);
if (cWhere++ == 0) { wsprintf(sz, _T("(ObjectRelationships.idRel = %d)") _T(" AND (ObjectRelationships.%s = %d)"), m_idRel, szRelatedField, id); } else { wsprintf(sz, _T("(%s) AND ") _T("(ObjectRelationships.idRel = %d)") _T(" AND (ObjectRelationships.%s = %d)"), (const TCHAR *) bstrWhere, m_idRel, szRelatedField, id); } bstrWhere = sz; }
if (m_ppropcond != NULL) { long cProps = 0; CComQIPtr<CMetaPropertyCondition> ppropcond(m_ppropcond); _bstr_t bstrWhereClause;
hr = ppropcond->get_QueryClause(cProps, &bstrWhereClause); if (FAILED(hr)) return hr;
if (cProps > 0) { if (cWhere > 0) { wsprintf(sz, _T("(%s) AND (%s)"), (const TCHAR *) bstrWhere, (const TCHAR *) bstrWhereClause); bstrWhere = sz; } else { bstrWhere += bstrWhereClause; } cWhere++; for (int i = 0; i < cProps; i++) { wsprintf(sz, _T("(%s INNER JOIN Properties AS Props_%d") _T(" ON Objects.id = Props_%d.idObj)"), (const TCHAR *) bstrFrom, i, i); bstrFrom = sz; } } }
if (!!bstrWhere) { bstrWhere = _bstr_t(" WHERE ") + bstrWhere; }
*pbstr = bstrCmd + _T(" FROM ") + bstrFrom + bstrWhere + bstrOrder + _T(";");
return S_OK; }
HRESULT CObjects::GetRS(ADODB::_Recordset **pprs) { HRESULT hr; #if 1
BOOL fQuery = TRUE; #else
BOOL fQuery = ((m_ppropcond != NULL) || (m_pobjRelated != NULL)); #endif
if (m_prs == NULL) { if (fQuery) { _bstr_t bstrQuery;
hr = GetQuery(Select, &bstrQuery); if (FAILED(hr)) return hr;
hr = m_pdb->NewQuery(bstrQuery, &m_prs); if (FAILED(hr)) return hr; } else { hr = m_pdb->get_ObjsByType(&m_prs); if (FAILED(hr)) return hr; } } if (m_prs == NULL) return E_FAIL;
(*pprs = m_prs)->AddRef();
return fQuery ? S_OK : S_FALSE; }
STDMETHODIMP CObjects::get_Count(long *plCount) { ENTER_API { ValidateOut<long>(plCount, 0); DeclarePerfTimer("get_Count");
HRESULT hr;
if (m_cItems == -1) { long idType; long cItems = 0; ADODB::_RecordsetPtr prs;
hr = GetRS(&prs); if (FAILED(hr)) return hr; bool fFast = (hr == S_OK); #if 0
if (fFast) { PerfTimerReset(); hr = prs->MoveLast(); hr = prs->get_RecordCount(&cItems); if (SUCCEEDED(hr) && (cItems >= 0)) { PerfTimerDump("Succeeded get_RecordCount"); goto ReturnIt; } cItems = 0; PerfTimerDump("Failed get_RecordCount"); } #endif
PerfTimerReset(); hr = m_pobjtype->get_ID(&idType); if (FAILED(hr)) return E_FAIL;
if (!fFast && idType != 0) { if (m_pdb->FSQLServer()) { TCHAR szFind[32];
prs->MoveFirst(); wsprintf(szFind, _T("idType = %d"), idType); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { _variant_t var(idType); prs->Seek(var, ADODB::adSeekAfterEQ); } } else { hr = prs->MoveFirst(); if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, ADODB::adErrNoCurrentRecord)) goto ReturnIt; }
// UNDONE: This is not the most efficient, but it's what works for now.
while (!prs->EndOfFile) { if (idType != 0) { long idType2 = prs->Fields->Item["idType"]->Value; if (idType != idType2) break; } cItems++; prs->MoveNext(); } PerfTimerDump("Count done"); ReturnIt: m_cItems = cItems; }
*plCount = m_cItems; return S_OK; } LEAVE_API }
STDMETHODIMP CObjects::get_Item(VARIANT varIndex, IUnknown **ppobj) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj, NULL);
HRESULT hr; _variant_t var(varIndex);
try { var.ChangeType(VT_I4); } catch (_com_error) { return E_INVALIDARG; } long i = var.lVal;
if (i < 0) return E_INVALIDARG;
long idType;
hr = m_pobjtype->get_ID(&idType); if (FAILED(hr)) return E_FAIL; ADODB::_RecordsetPtr prs;
hr = GetRS(&prs); if (FAILED(hr)) return hr;
if (hr == S_OK) { prs->MoveFirst(); } else { if (m_pdb->FSQLServer()) { TCHAR szFind[32];
wsprintf(szFind, _T("idType = %d"), idType); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { var = idType; prs->Seek(var, ADODB::adSeekAfterEQ); } }
if (prs->EndOfFile) return E_INVALIDARG;
if (i > 0) prs->Move(i);
if (prs->EndOfFile) return E_INVALIDARG;
long idType2 = prs->Fields->Item["idType"]->Value; if ((idType != 0) && (idType != idType2)) return E_INVALIDARG; long idObj = prs->Fields->Item["id"]->Value;
if (idType == 0) return m_pdb->CacheObject(idObj, idType2, ppobj);
return m_pdb->CacheObject(idObj, m_pobjtype, ppobj); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemWithID(long id, IUnknown **ppobj) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj, NULL); HRESULT hr;
hr = m_pdb->get_Object(id, ppobj); if (SUCCEEDED(hr)) return hr;
long idType;
hr = m_pobjtype->get_ID(&idType); if (FAILED(hr)) return E_FAIL; ADODB::_RecordsetPtr prs;
hr = m_pdb->get_ObjsByID(&prs);
if (m_pdb->FSQLServer()) { TCHAR szFind[32];
prs->MoveFirst(); wsprintf(szFind, _T("idObj = %d"), id); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { _variant_t var = id; prs->Seek(var, ADODB::adSeekFirstEQ); }
if (prs->EndOfFile) return E_INVALIDARG;
if (idType != 0) { long idType2 = prs->Fields->Item["idType"]->Value; if (idType != idType2) return E_INVALIDARG; }
return m_pdb->CacheObject(id, m_pobjtype, ppobj); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemWithKey(VARIANT varKey, IUnknown **ppobj) { ENTER_API { HRESULT hr; _bstr_t bstrKey;
try { bstrKey = varKey; } catch (_com_error) { return E_INVALIDARG; }
ADODB::_RecordsetPtr prs;
hr = GetRS(&prs); if (FAILED(hr)) return hr;
_bstr_t bstrFind;
switch (varKey.vt) { default: return E_INVALIDARG;
case VT_I2: case VT_I4: bstrFind = _T("lValue = ") + bstrKey; break; case VT_R4: case VT_R8: case VT_DATE: bstrFind = _T("fValue = ") + bstrKey; break; case VT_BSTR_BLOB: case VT_BSTR: // UNDONE: Handle embedded quotes in bstrKey
bstrFind = _T("sValue = '") + bstrKey + _T("'"); break; }
DeclarePerfTimer("get_ItemWithKey"); PerfTimerReset(); hr = prs->MoveFirst(); hr = prs->Find(bstrFind, 0, ADODB::adSearchForward); if (FAILED(hr)) return hr; PerfTimerDump("MoveFirst + Find");
if (prs->EndOfFile) return E_INVALIDARG;
long idType = prs->Fields->Item["idType"]->Value; long idObj = prs->Fields->Item["id"]->Value;
return m_pdb->CacheObject(idObj, idType, ppobj); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsWithType(BSTR bstrCLSID, IObjects **ppobjs) { ENTER_API { ValidateOutPtr<IObjects>(ppobjs, NULL); CObjectType *pobjtype;
m_pdb->get_ObjectType(bstrCLSID, &pobjtype);
return get_ItemsWithType(pobjtype, ppobjs); } LEAVE_API }
HRESULT CObjects::get_ItemsWithType(CObjectType *pobjtype, IObjects **ppobjs) { ENTER_API { ValidateInPtr<CObjectType>(pobjtype); ValidateOutPtr<IObjects>(ppobjs, NULL);
// Objects can't have two types... if this collection is for objects of
// a specific type, then it contains no objects of the requested type.
_ASSERTE(m_pobjtype != NULL);
long idType; m_pobjtype->get_ID(&idType); if (idType != 0) return E_INVALIDARG; // If there's no related object clause nor a property condition then
// we're after the base collection of objects of the specified type.
// That's cached in by m_pdb.
if ((m_pobjRelated == NULL) && (m_ppropcond == NULL)) return m_pdb->get_ObjectsWithType(pobjtype, ppobjs);
HRESULT hr = pobjtype->get_NewCollection(ppobjs); if (FAILED(hr)) return hr;
CComQIPtr<CObjects> pobjs(*ppobjs);
pobjs->Copy(this);
return S_OK; } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsWithMetaProperty(IMetaProperty *pprop, IObjects **ppobjs) { ENTER_API { ValidateInPtr<IMetaProperty>(pprop); ValidateOutPtr<IObjects>(ppobjs);
HRESULT hr; CComPtr<IMetaPropertyCondition> pcond;
hr = pprop->get_Cond(_bstr_t("="), &pcond); if (FAILED(hr)) return hr; hr = get_ItemsWithMetaPropertyCond(pcond, ppobjs);
return hr; } LEAVE_API }
STDMETHODIMP CObjects::UnreferencedItems(IObjects **ppobjs) { ENTER_API { ValidateOutPtr<IObjects>(ppobjs, NULL); HRESULT hr;
hr = Clone(ppobjs); if (FAILED(hr)) return hr; CComQIPtr<CObjects> pobjs(*ppobjs); if (FAILED(hr)) return hr;
hr = pobjs->put_OnlyUnreferenced(TRUE);
return hr; } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsWithMetaPropertyCond(IMetaPropertyCondition *ppropcond, IObjects **ppobjs) { ENTER_API { ValidateInPtr<IMetaPropertyCondition>(ppropcond); ValidateOutPtr<IObjects>(ppobjs, NULL);
HRESULT hr; CComPtr<IMetaPropertyCondition> ppropcond2;
if (m_ppropcond != NULL) { hr = m_ppropcond->get_And(ppropcond, &ppropcond2); if (FAILED(hr)) return hr; ppropcond = ppropcond2; }
hr = Clone(ppobjs);
CComQIPtr<CObjects> pobjs(*ppobjs);
pobjs->put_MetaPropertyCond(ppropcond); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsByKey(IMetaPropertyType *pproptype, IGuideDataProvider *pprovider, long idLang, long vt, IObjects * *ppobjs) { ENTER_API { ValidateInPtr<IMetaPropertyType>(pproptype); ValidateInPtr_NULL_OK<IGuideDataProvider>(pprovider); ValidateOutPtr<IObjects>(ppobjs, NULL);
switch (vt) { default: return E_INVALIDARG;
case VT_I2: case VT_I4: case VT_R4: case VT_R8: case VT_DATE: case VT_BSTR_BLOB: case VT_BSTR: break; }
HRESULT hr = Clone(ppobjs); if (FAILED(hr)) return hr;
CComQIPtr<CObjects> pobjs(*ppobjs);
pobjs->put_Key(pproptype, pprovider, idLang, vt);
return hr; } LEAVE_API }
STDMETHODIMP CObjects::Reset() { m_cItems = -1; // UNDONE: Is "m_cItems++;" sufficient?
if (m_prs != NULL) m_prs.Release(); return S_OK; }
STDMETHODIMP CObjects::get_AddNew(IUnknown **ppobj) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj, NULL);
HRESULT hr;
// Force the collection to be requeried so the new item shows up.
Reset();
if ((m_pobjRelated == NULL) && (m_ppropcond == NULL)) { // This collection is the base collection for this type.
hr = m_pobjtype->get_New(ppobj); if (FAILED(hr)) return hr;
//UNDONE: Too many AddRef()s?
if (*ppobj != NULL) (*ppobj)->AddRef(); // Only fire the ItemAdded() event when adding to the base collection.
if (SUCCEEDED(hr)) { long id; long idType;
m_pdb->get_IdOf(*ppobj, &id); m_pobjtype->get_ID(&idType); m_pdb->Broadcast_ItemAdded(id, idType); } } else { hr = get_AddNewAt(-1, ppobj); } return hr; } LEAVE_API }
STDMETHODIMP CObjects::get_AddNewAt(long index, IUnknown **ppobj) { ENTER_API { ValidateOutPtr<IUnknown>(ppobj, NULL); HRESULT hr = E_INVALIDARG;
// Can't add items if there is no object type
_ASSERTE(m_pobjtype != NULL);
// Force the collection to be requeried so the new item shows up.
Reset(); if ((m_pobjRelated == NULL) && (m_ppropcond == NULL) && (index != -1)) { hr = get_AddNew(ppobj); } else if (m_pobjRelated != NULL) { // This is a subset of the base collection of items of this type.
// It contains only the items of the specified type which are
// related to m_pobjRelated by the relationship m_idRel.
// We must first create a new item in the base collection
// and then add it to the subset.
CComPtr<IObjects> pobjs; hr = m_pdb->get_ObjectsWithType(m_pobjtype, &pobjs); if (FAILED(hr)) return hr; hr = pobjs->get_AddNew(ppobj); if (FAILED(hr)) return hr; hr = AddAt(*ppobj, index); }
return hr; } LEAVE_API }
STDMETHODIMP CObjects::AddAt(IUnknown *pobj, long index) { ENTER_API { ValidateInPtr<IUnknown>(pobj);
HRESULT hr;
// Can't add an item at a particular index if this is not an ordered collection.
// Order is only expressed for related objects and not for inverse related objects.
if (m_pobjRelated == NULL || m_fInverse) return E_INVALIDARG; m_cItems = -1; // UNDONE: Is "m_cItems++;" sufficient?
if (m_prs != NULL) m_prs.Release(); long idObjRelated;
m_pdb->get_IdOf(m_pobjRelated, &idObjRelated);
long idObj; m_pdb->get_IdOf(pobj, &idObj);
hr = AddRelationshipAt(idObjRelated, m_idRel, index, idObj);
return hr; } LEAVE_API }
STDMETHODIMP CObjects::Remove(VARIANT varIndex) { ENTER_API { HRESULT hr; CComPtr<IUnknown> pobj;
switch (varIndex.vt) { case VT_UNKNOWN: case VT_DISPATCH: { hr = varIndex.punkVal->QueryInterface(__uuidof(IUnknown), (void **) &pobj); if (FAILED(hr)) return hr; } break; default: { hr = get_Item(varIndex, &pobj); if (FAILED(hr)) return hr; } }
return (m_pobjRelated != NULL) ? RemoveFromRelationship(pobj) : Remove(pobj); } LEAVE_API }
HRESULT CObjects::Remove(IUnknown *pobjRemove) { HRESULT hr; CComQIPtr<CObject> pobj(pobjRemove); long idObj; CObjectType *pobjtype;
pobj->get_Type(&pobjtype);
long idtype; m_pobjtype->get_ID(&idtype);
if ((idtype != NULL) && (pobjtype != m_pobjtype)) return E_INVALIDARG;
pobj->get_ID(&idObj);
m_pdb->UncacheObject(idObj);
// Delete all the properties
TCHAR sz[1024];
wsprintf(sz, _T("DELETE * FROM Properties WHERE idObj=%d;"), idObj);
hr = m_pdb->Execute(_bstr_t(sz));
// Remove any properties pointing to the deleted object
wsprintf(sz, _T("DELETE * FROM Properties WHERE (ValueType = 13) AND (lValue = %d);"), idObj);
hr = m_pdb->Execute(_bstr_t(sz));
// Remove the object from all relationships
wsprintf(sz, _T("DELETE * FROM ObjectRelationships") _T(" WHERE (idObj1=%d) OR (idObj2=%d);"), idObj, idObj);
hr = m_pdb->Execute(_bstr_t(sz));
// Remove the object.
wsprintf(sz, _T("DELETE * FROM Objects WHERE id=%d;"), idObj);
hr = m_pdb->Execute(_bstr_t(sz));
if (SUCCEEDED(hr)) { long idType = 0; pobjtype->get_ID(&idType); m_pdb->Broadcast_ItemRemoved(idObj, idType); }
Reset(); return hr; }
STDMETHODIMP CObjects::RemoveAll() { ENTER_API { HRESULT hr; _bstr_t bstrQuery; boolean fTransacted = TRUE;
hr = GetQuery(Delete, &bstrQuery); if (FAILED(hr)) return hr; hr = m_pdb->BeginTrans(); if (FAILED(hr)) fTransacted = FALSE;
hr = m_pdb->Execute(bstrQuery); if (FAILED(hr)) goto Cleanup;
// Delete all the dangling properties
hr = m_pdb->Execute( _bstr_t("DELETE * FROM Properties" " WHERE idObj NOT IN" " (SELECT Objects.id FROM Objects);") ); if (FAILED(hr)) goto Cleanup;
// Remove the object from all relationships
hr = m_pdb->Execute( _bstr_t("DELETE * FROM ObjectRelationships" " WHERE idObj1 NOT IN" " (SELECT Objects.id FROM Objects);") ); if (FAILED(hr)) goto Cleanup; if (!m_fOnlyUnreferenced) { // If this collection only contains unreferenced objects then
// there is no need to execute the following.
// Otherwise...
// Remove dangling object references.
hr = m_pdb->Execute( _bstr_t("DELETE * FROM ObjectRelationships" " WHERE idObj2 NOT IN" " (SELECT Objects.id FROM Objects);") ); if (FAILED(hr)) goto Cleanup;
// Remove any properties pointing to deleted objects
hr = m_pdb->Execute( _bstr_t("DELETE * FROM Properties" " WHERE (ValueType = 13) AND (lValue NOT IN" " (SELECT Objects.id FROM Objects));") ); }
Cleanup: if (fTransacted) { if (FAILED(hr)) m_pdb->RollbackTrans(); else hr = m_pdb->CommitTrans(); } if (SUCCEEDED(hr)) { Reset(); m_pdb->PurgeCachedObjects(); }
return hr; } LEAVE_API }
HRESULT CObjects::RemoveFromRelationship(IUnknown *pobjRemove) { long idObj1; long idObj2;
m_pdb->get_IdOf(m_pobjRelated, &idObj1); m_pdb->get_IdOf(pobjRemove, &idObj2);
if (m_fInverse) swap(idObj1, idObj2);
TCHAR sz[1024];
wsprintf(sz, _T("DELETE *") _T(" FROM ObjectRelationships") _T(" WHERE ((ObjectRelationships.idObj1=%d)") _T(" AND (ObjectRelationships.idRel=%d)") _T(" AND (ObjectRelationships.idObj2=%d));"), idObj1, m_idRel, idObj2);
m_cItems = -1; // UNDONE: Is "m_cItems++;" sufficient?
if (m_prs != NULL) m_prs.Release();
return m_pdb->Execute(_bstr_t(sz)); }
HRESULT CObjects::get_ItemsRelatedToBy(IUnknown *pobj, IMetaPropertyType *pproptype, boolean fInverse, IObjects **ppobjs) { // Can't handle multiple relations yet.
if (m_pobjRelated != NULL) return E_INVALIDARG; CComQIPtr<CMetaPropertyType> pproptypeT(pproptype);
if (pproptypeT == NULL) return E_INVALIDARG; long idRel = pproptypeT->GetID(); HRESULT hr;
hr = Clone(ppobjs); if (FAILED(hr)) return hr;
CComQIPtr<CObjects> pobjs(*ppobjs); if (FAILED(hr)) return hr;
hr = pobjs->InitRelation(pobj, idRel, fInverse);
return hr; }
STDMETHODIMP CObjects::get_ItemsRelatedToBy(IUnknown *pobj, IMetaPropertyType *pproptype, IObjects **ppobjs) { ENTER_API { ValidateInPtr<IUnknown>(pobj); ValidateInPtr<IMetaPropertyType>(pproptype); ValidateOutPtr<IObjects>(ppobjs, NULL);
return get_ItemsRelatedToBy(pobj, pproptype, FALSE, ppobjs); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsInverseRelatedToBy(IUnknown *pobj, IMetaPropertyType *pproptype, IObjects **ppobjs) { ENTER_API { ValidateInPtr<IUnknown>(pobj); ValidateInPtr<IMetaPropertyType>(pproptype); ValidateOutPtr<IObjects>(ppobjs, NULL);
return get_ItemsRelatedToBy(pobj, pproptype, TRUE, ppobjs); } LEAVE_API }
STDMETHODIMP CObjects::get_ItemsInTimeRange(DATE dt1, DATE dt2, IObjects **ppobjs) { ENTER_API { ValidateOutPtr<IObjects>(ppobjs, NULL);
HRESULT hr;
// Ensure that dt1 is less than or equal to dt2
if (dt1 > dt2) swap(dt1, dt2);
_variant_t varT1(dt1, VT_DATE); _variant_t varT2(dt2, VT_DATE);
CComPtr<IMetaPropertyType> pproptypeStartTime = m_pdb->StartMetaPropertyType(); CComPtr<IMetaPropertyType> pproptypeEndTime = m_pdb->EndMetaPropertyType();
CComPtr<IMetaPropertyCondition> ppropcond1; CComPtr<IMetaPropertyCondition> ppropcond2; _bstr_t bstrLT(_T("<")); _bstr_t bstrGT(_T(">")); _bstr_t bstrLE(_T("<="));
if (dt1 < dt2) { // Look for StartTime > dt2 & EndTime < dt1
hr = pproptypeStartTime->get_Cond(bstrLT, 0, varT2, &ppropcond1); if (FAILED(hr)) return hr; hr = pproptypeEndTime->get_Cond(bstrGT, 0, varT1, &ppropcond2); if (FAILED(hr)) return hr; } else { // Look for StartTime <= dt1 & EndTime > dt1
hr = pproptypeStartTime->get_Cond(bstrLE, 0, varT1, &ppropcond1); if (FAILED(hr)) return hr; hr = pproptypeEndTime->get_Cond(bstrGT, 0, varT1, &ppropcond2); if (FAILED(hr)) return hr; }
CComPtr<IMetaPropertyCondition> ppropcond; hr = ppropcond1->get_And(ppropcond2, &ppropcond); if (FAILED(hr)) return hr;
return get_ItemsWithMetaPropertyCond(ppropcond, ppobjs); } LEAVE_API }
IMetaProperty * CObjectPropertyBag::GetProp(_bstr_t bstrPropName, boolean fCreate) { HRESULT hr;
if (m_pproptypes == NULL) return NULL;
CComPtr<IMetaPropertyType> pproptype;
_variant_t varNil; hr = m_pproptypes->get_AddNew(0, bstrPropName, &pproptype);
CComPtr<IMetaProperty> pprop; hr = m_pprops->get_ItemWithTypeProviderLang(pproptype, NULL, 0, &pprop); if (FAILED(hr)) { if (!fCreate) return NULL;
CComQIPtr<CMetaProperties> ppropsT(m_pprops); hr = ppropsT->get_AddNew(pproptype, NULL, NULL, varNil, &pprop); if (FAILED(hr)) return NULL; } return pprop.Detach(); }
STDMETHODIMP CObjectPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pvar, IErrorLog *pErrorLog) { ENTER_API { ValidateOut(pvar);
CComPtr<IMetaProperty> pprop; pprop.Attach(GetProp(_bstr_t(pszPropName), FALSE)); if (pprop == NULL) return E_INVALIDARG;
return pprop->get_Value(pvar); } LEAVE_API }
STDMETHODIMP CObjectPropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pvar) { ENTER_API { CComPtr<IMetaProperty> pprop; pprop.Attach(GetProp(_bstr_t(pszPropName), TRUE)); if (pprop == NULL) return E_FAIL;
CComQIPtr<CMetaProperty> ppropT(pprop);
return ppropT->PutValue(*pvar); } LEAVE_API } void CObjects::Dump() { #ifdef _DEBUG
TCHAR sz[256]; wsprintf(sz, _T("CObjects::Dump(%x)\n"), (long) this); OutputDebugString(sz);
long idType; m_pobjtype->get_ID(&idType); wsprintf(sz, _T(" type == %d\n"), idType); OutputDebugString(sz);
wsprintf(sz, _T(" m_cItems == %d\n"), m_cItems); OutputDebugString(sz);
if (m_idPropTypeKey != 0) { wsprintf(sz, _T(" key == %d:%d:%d:%d\n"), m_idPropTypeKey, m_idProviderKey, m_idLangKey, m_vtKey); OutputDebugString(sz); }
if (m_prs != NULL) { wsprintf(sz, _T(" m_prs == %x\n"), m_prs); OutputDebugString(sz); }
if (m_pobjRelated != NULL) { long id;
m_pdb->get_IdOf(m_pobjRelated,&id); wsprintf(sz, _T(" %s to %d by %d\n"), m_fInverse ? _T("Inverse Related") : _T("Related"), id, m_idRel); OutputDebugString(sz); } if (m_fOnlyUnreferenced) { OutputDebugString(_T(" Only Unreferenced\n")); }
_bstr_t bstr;
GetQuery(Select, &bstr); OutputDebugString(_T(" Query: ")); OutputDebugString(bstr); OutputDebugString(_T("\n")); #endif
}
#if SUPPORT_PROPBAG2
// IPropertyBag2 interface
STDMETHODIMP CObjectPropertyBag::CountProperties(long *plCount) { *plCount = 0; return S_OK; } STDMETHODIMP CObjectPropertyBag::GetPropertyInfo(ULONG iProp, ULONG cProps, PROPBAG2 *ppropbag2, ULONG *pcProps) { return E_NOTIMPL; }
STDMETHODIMP CObjectPropertyBag::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown *punk, IErrorLog *perrlog) { return E_NOTIMPL; }
STDMETHODIMP CObjectPropertyBag::Read(ULONG cProps, PROPBAG2 *ppropbag2, IErrorLog *perrlog, VARIANT *rgvar, HRESULT *phr) { return E_NOTIMPL; }
STDMETHODIMP CObjectPropertyBag::Write(ULONG cProps, PROPBAG2 *ppropbag2, VARIANT *rgvar) { return E_NOTIMPL; } #endif
|