// prop.cpp : Implementation of CMetaPropertySet #include "stdafx.h" #include "Property.h" #include "util.h" HRESULT SaveObjectToField(VARIANT var, ADODB::Field *pfield) { HRESULT hr; if ((var.vt != VT_UNKNOWN) && (var.vt != VT_DISPATCH)) return E_INVALIDARG; CComPtr pstream; hr = CreateStreamOnHGlobal(NULL, TRUE, &pstream); if (FAILED(hr)) return hr; CComQIPtr ppersiststream(var.punkVal); if (ppersiststream != NULL) { // 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; hr = OleSaveToStream(ppersiststream, pstream); if (FAILED(hr)) return hr; } else { CComQIPtr ppersistpropbag(var.punkVal); if (ppersistpropbag == NULL) return E_INVALIDARG; // Write a tag to indicate IPersistPropertyBag was used. char ch = Format_IPersistPropertyBag; ULONG cb = sizeof(ch); hr = pstream->Write(&ch, cb, &cb); if (FAILED(hr)) return hr; hr = SaveToPropBagInStream(ppersistpropbag, pstream); if (FAILED(hr)) return hr; } HANDLE hdata; hr = GetHGlobalFromStream(pstream, &hdata); if (FAILED(hr)) return hr; long cb = GlobalSize(hdata); SAFEARRAY *parray = SafeArrayCreateVector(VT_UI1, 0, cb); 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, cb); GlobalUnlock(hdata); SafeArrayUnaccessData(parray); _variant_t varT; varT.vt = VT_ARRAY | VT_UI1; varT.parray = parray; hr = pfield->AppendChunk(varT); if (FAILED(hr)) return hr; return S_OK; } HRESULT LoadObjectFromField(ADODB::Field *pfield, VARIANT *pvar) { HRESULT hr; long cb; 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 punk; { CComPtr 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 = OleLoadFromStream(pstream, __uuidof(IUnknown), (void **) &punk); break; case Format_IPersistPropertyBag: hr = LoadFromPropBagInStream(pstream, &punk); break; default: return STG_E_DOCFILECORRUPT; } } SafeArrayUnaccessData(varData.parray); if (FAILED(hr)) return hr; pvar->vt = VT_UNKNOWN; pvar->punkVal = punk.Detach(); return S_OK; } HRESULT SeekPropsRS(ADODB::_RecordsetPtr prs, boolean fSQLServer, long idObj, long idPropType, boolean fAnyProvider, long idProvider, long idLang) { _ASSERTE(idObj != 0); HRESULT hr; if (fAnyProvider && idProvider != NULL) { // First try to find the specified provider, only if it is not found // do we look for any provider. hr = SeekPropsRS(prs, fSQLServer, idObj, idPropType, FALSE, idProvider, idLang); if (SUCCEEDED(hr)) return hr; idProvider = NULL; } try { TCHAR szFind[32]; DeclarePerfTimerOff(perf, "SeekPropsRS"); #if 1 { static bool fDump= FALSE; if (fDump) { prs->MoveFirst(); while (!prs->EndOfFile) { long idObjCur = prs->Fields->Item["idObj"]->Value; long idPropTypeCur = prs->Fields->Item["idPropType"]->Value; TRACE("idObj = %d idPropType = %d\n", idObjCur, idPropTypeCur); prs->MoveNext(); } } } #endif PerfTimerReset(); if (fSQLServer) { prs->MoveFirst(); wsprintf(szFind, _T("idObj = %d"), idObj); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); wsprintf(szFind, _T("idPropType = %d"), idPropType); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); } else { // Create elements used in the array _variant_t varCriteria[4]; varCriteria[0] = idObj; varCriteria[1] = idPropType; varCriteria[2] = idProvider; varCriteria[3] = idLang; const int nCrit = sizeof varCriteria / sizeof varCriteria[0]; // Create SafeArray Bounds and initialize the array SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = nCrit; SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); hr = S_OK; // Set the values for each element of the array for( long i = 0 ; i < nCrit && SUCCEEDED( hr );i++) { hr = SafeArrayPutElement(psa, &i,&varCriteria[i]); } // Initialize and fill the SafeArray VARIANT var; var.vt = VT_VARIANT | VT_ARRAY; V_ARRAY(&var) = psa; hr = prs->Seek(var, fAnyProvider ? ADODB::adSeekAfterEQ : ADODB::adSeekFirstEQ); if (FAILED(hr)) return hr; if (prs->EndOfFile) return E_INVALIDARG; if (!fAnyProvider) return S_OK; } while (TRUE) { if (prs->EndOfFile) break; long idObjCur = prs->Fields->Item["idObj"]->Value; if (idObjCur != idObj) break; long idPropTypeCur = prs->Fields->Item["idPropType"]->Value; if (idPropTypeCur != idPropType) break; long idLang2 = prs->Fields->Item["idLanguage"]->Value; long idProvider2 = prs->Fields->Item["idProvider"]->Value; if ((idLang == idLang2) && (fAnyProvider || (idProvider == idProvider2))) { PerfTimerDump("Successful seek"); return S_OK; } prs->MoveNext(); } PerfTimerDump("Failed seek"); return E_INVALIDARG; } catch (_com_error & e) { TCHAR sz[1024]; wsprintf(sz, _T("Error: %s"), e.ErrorMessage()); return e.Error(); } } ///////////////////////////////////////////////////////////////////////////// // CMetaPropertySet HRESULT CMetaPropertySet::Load() { HRESULT hr; ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropTypesRS(&prs); if (FAILED(hr)) return hr; if (!CreatePropTypes()) return E_OUTOFMEMORY; prs->MoveFirst(); TCHAR szFind[20]; wsprintf(szFind, _T("idPropSet = %d"), m_id); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); while (!prs->EndOfFile) { CComPtr pproptype; long idPropSet = prs->Fields->Item["idPropSet"]->Value; if (idPropSet != m_id) break; bstr_t bstrName = prs->Fields->Item["Name"]->Value; long idPropType = prs->Fields->Item["idProp"]->Value; long id = prs->Fields->Item["id"]->Value; variant_t varNil; hr = m_pproptypes->Cache(id, idPropType, bstrName, &pproptype); prs->MoveNext(); } return S_OK; } STDMETHODIMP CMetaPropertySet::get_Name(BSTR *pbstrName) { ENTER_API { ValidateOut(pbstrName); *pbstrName = m_bstrName.copy(); return S_OK; } LEAVE_API } bool CMetaPropertySet::CreatePropTypes() { if (m_pproptypes == NULL) { CComPtr pproptypes = NewComObject(CMetaPropertyTypes); if (pproptypes == NULL) return FALSE; pproptypes->Init(m_pdb, this); m_pproptypes = pproptypes; } return TRUE; } STDMETHODIMP CMetaPropertySet::get_MetaPropertyTypes(IMetaPropertyTypes **ppproptypes) { ENTER_API { ValidateOutPtr(ppproptypes, NULL); if (!CreatePropTypes()) return E_OUTOFMEMORY; (*ppproptypes = m_pproptypes)->AddRef(); return S_OK; } LEAVE_API } ///////////////////////////////////////////////////////////////////////////// // CMetaPropertySets HRESULT CMetaPropertySets::Load() { HRESULT hr; ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropSetsRS(&prs); if (FAILED(hr)) return hr; prs->MoveFirst(); while (!prs->EndOfFile) { // Read in all the records CComPtr ppropset; long id = prs->Fields->Item["id"]->Value; bstr_t bstrName = prs->Fields->Item["Name"]->Value; hr = Cache(id, bstrName, &ppropset); if (SUCCEEDED(hr) && ppropset != NULL) { ppropset->Load(); } prs->MoveNext(); } return S_OK; } STDMETHODIMP CMetaPropertySets::get_Count(long *plCount) { ENTER_API { ValidateOut(plCount); *plCount = m_map.size(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertySets::get_Item(VARIANT varIndex, IMetaPropertySet **pppropset) { ENTER_API { ValidateOutPtr(pppropset, NULL); if (varIndex.vt == VT_BSTR) return get_ItemWithName(varIndex.bstrVal, pppropset); _variant_t var(varIndex); try { var.ChangeType(VT_I4); } catch (_com_error &) { return E_INVALIDARG; } long i = var.lVal; if ((i < 0) || (i >= m_map.size())) return E_INVALIDARG; t_map::iterator it = m_map.begin(); while (i--) it++; *pppropset = (*it).second; if (*pppropset != NULL) (*pppropset)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertySets::get_ItemWithName(BSTR bstrName, IMetaPropertySet **pppropset) { ENTER_API { ValidateIn(bstrName); ValidateOutPtr(pppropset, NULL); t_map::iterator it = m_map.find(bstrName); if (it == m_map.end()) return E_INVALIDARG; *pppropset = (*it).second; (*pppropset)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertySets::get_Lookup(BSTR bstrName, IMetaPropertyType **ppproptype) { ENTER_API { HRESULT hr; ValidateIn(bstrName); ValidateOutPtr(ppproptype, NULL); if (bstrName == NULL) return E_INVALIDARG; wchar_t *szDot = wcschr(bstrName, L'.'); if (szDot == NULL) return E_INVALIDARG; _bstr_t bstrPropTypeName(szDot+1); _bstr_t bstrPropSetName = SysAllocStringLen(bstrName, szDot - bstrName); CComPtr ppropset; hr = get_AddNew(bstrPropSetName, &ppropset); if (FAILED(hr)) return hr; CComPtr pproptypes; hr = ppropset->get_MetaPropertyTypes(&pproptypes); if (FAILED(hr)) return hr; CComPtr pproptype; _variant_t varNil; hr = pproptypes->get_AddNew(0, bstrPropTypeName, &pproptype); if (FAILED(hr)) return hr; *ppproptype = pproptype.Detach(); return S_OK; } LEAVE_API } HRESULT CMetaPropertySets::Cache(long id, BSTR bstrName, CMetaPropertySet **pppropset) { CComPtr ppropset = NULL; t_map::iterator it = m_map.find(bstrName); if (it != m_map.end()) { ppropset = (*it).second; } else { ppropset = NewComObject(CMetaPropertySet); if (ppropset == NULL) return E_OUTOFMEMORY; ppropset->Init(m_pdb, id, bstrName); BSTR bstrNameT = SysAllocString(bstrName); if (bstrNameT == NULL) return E_OUTOFMEMORY; ppropset.CopyTo(&m_map[bstrNameT]); } *pppropset = ppropset.Detach(); return S_OK; } STDMETHODIMP CMetaPropertySets::get_AddNew(BSTR bstrName, IMetaPropertySet **pppropset) { ENTER_API { ValidateIn(bstrName); ValidateOutPtr(pppropset, NULL); HRESULT hr; hr = get_ItemWithName(bstrName, pppropset); if (SUCCEEDED(hr)) return hr; static long idCur = 1; long id; if (m_pdb == NULL) id = idCur++; else { ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropSetsRS(&prs); if (FAILED(hr)) return hr; // Create a new record. hr = prs->AddNew(); prs->Fields->Item["Name"]->Value = bstrName; hr = prs->Update(); id = prs->Fields->Item["id"]->Value; } CMetaPropertySet *ppropset; hr = Cache(id, bstrName, &ppropset); *pppropset = ppropset; return hr; } LEAVE_API } ///////////////////////////////////////////////////////////////////////////// // CMetaPropertyType STDMETHODIMP CMetaPropertyType::get_MetaPropertySet(IMetaPropertySet **pppropset) { ENTER_API { ValidateOutPtr(pppropset, m_ppropset); (*pppropset)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyType::get_ID(long *pid) { ENTER_API { ValidateOut(pid, m_idPropType); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyType::get_Name(BSTR *pbstrName) { ENTER_API { ValidateOut(pbstrName); *pbstrName = m_bstrName.copy(); return S_OK; } LEAVE_API } HRESULT CMetaPropertyType::GetNew(long idProvider, long lang, VARIANT varValue, IMetaProperty **ppprop) { ENTER_API { ValidateOutPtr(ppprop, NULL); CComPtr pprop = NewComObject(CMetaProperty); if (pprop == NULL) return E_OUTOFMEMORY; pprop->Init(m_pdb, m_id, idProvider, lang, varValue); *ppprop = pprop.Detach(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyType::get_Cond(BSTR bstrCond, long lang, VARIANT varValue, IMetaPropertyCondition **pppropcond) { ENTER_API { ValidateIn(bstrCond); ValidateOutPtr(pppropcond, NULL); if (bstrCond == NULL) return E_INVALIDARG; HRESULT hr; CComPtr pprop; hr = get_New(lang, varValue, &pprop); if (FAILED(hr)) return hr; return pprop->get_Cond(bstrCond, pppropcond); } LEAVE_API } ///////////////////////////////////////////////////////////////////////////// // CMetaPropertyTypes STDMETHODIMP CMetaPropertyTypes::get_Count(long *plCount) { ENTER_API { ValidateOut(plCount, m_map.size()); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyTypes::get_Item(VARIANT varIndex, IMetaPropertyType **ppproptype) { ENTER_API { ValidateOutPtr(ppproptype, NULL); if (varIndex.vt == VT_BSTR) return get_ItemWithName(varIndex.bstrVal, ppproptype); _variant_t var(varIndex); try { var.ChangeType(VT_I4); } catch (_com_error &) { return E_INVALIDARG; } long i = var.lVal; if ((i < 0) || (i >= m_map.size())) return E_INVALIDARG; t_map::iterator it = m_map.begin(); while (i--) it++; *ppproptype = (*it).second; if (*ppproptype != NULL) (*ppproptype)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyTypes::get_MetaPropertySet(IMetaPropertySet **pppropset) { ENTER_API { ValidateOutPtr(pppropset, m_ppropset); if (*pppropset != NULL) (*pppropset)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyTypes::get_ItemWithName(BSTR bstrName, IMetaPropertyType **ppproptype) { ENTER_API { ValidateIn(bstrName); ValidateOutPtr(ppproptype, NULL); t_map::iterator it = m_map.find(bstrName); if (it == m_map.end()) return E_INVALIDARG; (*ppproptype = (*it).second)->AddRef(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyTypes::get_ItemWithID(long id, IMetaPropertyType **ppproptype) { ENTER_API { ValidateOutPtr(ppproptype, NULL); for (t_map::iterator it = m_map.begin(); it != m_map.end(); it++) { CComPtr pproptype = (*it).second; long idCur; pproptype->get_ID(&idCur); if (idCur == id) { *ppproptype = pproptype.Detach(); return S_OK; } } return E_INVALIDARG; } LEAVE_API } HRESULT CMetaPropertyTypes::Cache(long id, long idPropType, BSTR bstrName, CMetaPropertyType **ppproptype) { CComPtr pproptype; t_map::iterator it = m_map.find(bstrName); if (it != m_map.end()) { pproptype = (*it).second; } else { pproptype = NewComObject(CMetaPropertyType); if (pproptype == NULL) return E_OUTOFMEMORY; pproptype->Init(m_pdb, m_ppropset, id, idPropType, bstrName); BSTR bstrT = SysAllocString(bstrName); pproptype.CopyTo(&m_map[bstrT]); m_pdb->put_MetaPropertyType(id, pproptype); } *ppproptype = pproptype.Detach(); return S_OK; } STDMETHODIMP CMetaPropertyTypes::get_AddNew(long idProp, BSTR bstrName, IMetaPropertyType **ppproptype) { ENTER_API { ValidateIn(bstrName); ValidateOutPtr(ppproptype, NULL); HRESULT hr; hr = get_ItemWithName(bstrName, ppproptype); if (SUCCEEDED(hr)) return hr; CComPtr pproptype; static long idCur = 1; long id; if (m_pdb == NULL) id = idCur++; else { ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropTypesRS(&prs); if (FAILED(hr)) return hr; // Create a new record. hr = prs->AddNew(); prs->Fields->Item["idPropSet"]->Value = m_ppropset->GetID(); prs->Fields->Item["idProp"]->Value = idProp; prs->Fields->Item["Name"]->Value = bstrName; hr = prs->Update(); id = prs->Fields->Item["id"]->Value; } hr = Cache(id, idProp, bstrName, &pproptype); if (FAILED(hr)) return hr; *ppproptype = pproptype.Detach(); return S_OK; } LEAVE_API } ///////////////////////////////////////////////////////////////////////////// // CMetaProperty STDMETHODIMP CMetaProperty::get_MetaPropertyType(IMetaPropertyType **ppproptype) { ENTER_API { ValidateOutPtr(ppproptype, NULL); return m_pdb->get_MetaPropertyType(m_idPropType, ppproptype); } LEAVE_API } STDMETHODIMP CMetaProperty::get_Language(long *pidLang) { ENTER_API { ValidateOut(pidLang, m_idLang); return S_OK; } LEAVE_API } STDMETHODIMP CMetaProperty::get_Value(VARIANT *pvarValue) { ENTER_API { ValidateOut(pvarValue); return VariantCopy(pvarValue, &m_varValue); } LEAVE_API } STDMETHODIMP CMetaProperty::put_Value(VARIANT varValue) { ENTER_API { // Changing the value, so must reset the provider. m_idProvider = m_pdb->GetIDGuideDataProvider(); return PutValue(varValue); } LEAVE_API } STDMETHODIMP CMetaProperty::PutValue(VARIANT varValue) { HRESULT hr; ADODB::_RecordsetPtr prs; m_varValue = varValue; hr = m_pdb->get_PropsIndexed(&prs); if (FAILED(hr)) return hr; hr = SeekPropsRS(prs, m_pdb->FSQLServer(), m_idObj, m_idPropType, FALSE, m_idProvider, m_idLang); if (FAILED(hr)) { hr = AddNew(prs); if (FAILED(hr)) return hr; } hr = SaveValue(prs); if (FAILED(hr)) { prs->CancelUpdate(); return hr; } hr = prs->Update(); if (FAILED(hr)) return hr; m_pdb->Broadcast_ItemChanged(m_idObj); return hr; } STDMETHODIMP CMetaProperty::get_QueryClause(long &i, TCHAR *szOp, _bstr_t *pbstr) { TCHAR *szFieldName; TCHAR *szValue = NULL; switch (m_varValue.vt) { default: return E_INVALIDARG; case VT_EMPTY: return E_NOTIMPL; //Special case case VT_I2: case VT_I4: { szFieldName = _T("lValue"); int cb = 32; szValue = new TCHAR [cb]; if (szValue == NULL) return E_OUTOFMEMORY; _sntprintf(szValue, cb, _T("%d"), (long) m_varValue); } break; case VT_R4: case VT_R8: { szFieldName = _T("fValue"); int cb = 32; szValue = new TCHAR [cb]; if (szValue == NULL) return E_OUTOFMEMORY; _sntprintf(szValue, cb, _T("%.17f"), (double) m_varValue); } break; case VT_DATE: { szFieldName = _T("fValue"); _variant_t varT; ::VariantChangeTypeEx(&varT, &m_varValue, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, VT_BSTR); long cb = SysStringLen(varT.bstrVal) + 3; szValue = new TCHAR [cb]; if (szValue == NULL) return E_OUTOFMEMORY; _sntprintf(szValue, cb, _T("#%s#"), (const TCHAR *) varT.bstrVal); } break; case VT_BSTR: { _bstr_t bstr = m_varValue.bstrVal; int cb = bstr.length() + 3; // Add on 2 quotes and null terminator szValue = new TCHAR [cb]; if (szValue == NULL) return E_OUTOFMEMORY; if (bstr.length() < 255) { szFieldName = _T("sValue"); _sntprintf(szValue, cb, _T("\"%s\""), (const TCHAR *) bstr); } else { delete [] szValue; return E_INVALIDARG; //UNDONE: What to do? } } break; } int cb = -1; int cbBuf = 128; TCHAR *sz = NULL; while (cb < 0) { delete [] sz; sz = new TCHAR [cbBuf]; if (sz == NULL) return E_OUTOFMEMORY; cb = _sntprintf(sz, cbBuf, _T("(Props_%i.idPropType = %i) AND (Props_%i.%s %s %s)"), i, m_idPropType, i, szFieldName, szOp, szValue); cbBuf *= 2; } i++; *pbstr = sz; delete [] sz; delete [] szValue; return S_OK; } STDMETHODIMP CMetaProperty::get_Cond(BSTR bstrCond, IMetaPropertyCondition **pppropcond) { ENTER_API { ValidateIn(bstrCond); ValidateOutPtr(pppropcond, NULL); if (bstrCond == NULL) return E_INVALIDARG; CComPtr ppropcond = NULL; if (wcscmp(bstrCond, L"=") == 0) { ppropcond = NewComObject(CMetaPropertyConditionEQ); } else if ((wcscmp(bstrCond, L"!=") == 0) || (wcscmp(bstrCond, L"<>") == 0)) { ppropcond = NewComObject(CMetaPropertyConditionNE); } else if (_wcsicmp(bstrCond, L"LIKE") == 0) { ppropcond = NewComObject(CMetaPropertyConditionLike); } else if (_wcsicmp(bstrCond, L"NOT LIKE") == 0) { ppropcond = NewComObject(CMetaPropertyConditionNotLike); } else if (wcscmp(bstrCond, L"<") == 0) { ppropcond = NewComObject(CMetaPropertyConditionLT); } else if (wcscmp(bstrCond, L"<=") == 0) { ppropcond = NewComObject(CMetaPropertyConditionLE); } else if (wcscmp(bstrCond, L">") == 0) { ppropcond = NewComObject(CMetaPropertyConditionGT); } else if (wcscmp(bstrCond, L">=") == 0) { ppropcond = NewComObject(CMetaPropertyConditionGE); } else { return E_INVALIDARG; } if (ppropcond == NULL) return E_OUTOFMEMORY; ppropcond->Init(this); *pppropcond = ppropcond.Detach(); return S_OK; } LEAVE_API } HRESULT CMetaProperty::AddNew(ADODB::_RecordsetPtr prs) { HRESULT hr; // Create a new record. hr = prs->AddNew(); if (FAILED(hr)) return hr; prs->Fields->Item["idObj"]->Value = m_idObj; prs->Fields->Item["idPropType"]->Value = m_idPropType; prs->Fields->Item["idProvider"]->Value = m_idProvider; prs->Fields->Item["idLanguage"]->Value = m_idLang; return S_OK; } HRESULT CMetaProperty::SaveValue(ADODB::_RecordsetPtr prs) { HRESULT hr; try { VARTYPE vt = m_varValue.vt; IUnknown *punk; switch (vt) { default: return E_INVALIDARG; case VT_EMPTY: break; case VT_I2: case VT_I4: prs->Fields->Item["lValue"]->Value = m_varValue; break; case VT_R4: case VT_R8: case VT_DATE: prs->Fields->Item["fValue"]->Value = m_varValue; break; case VT_BSTR_BLOB: case VT_BSTR: prs->Fields->Item["sValue"]->Value = m_varValue; break; case VT_DISPATCH: case VT_UNKNOWN: #if 0 hr = SaveObjectToField(m_varValue, prs->Fields->Item["oValue"]); if (FAILED(hr)) return hr; #else punk = m_varValue.punkVal; goto SaveObj; #endif break; case VT_BYREF | VT_UNKNOWN: punk = *m_varValue.ppunkVal; vt = VT_UNKNOWN; SaveObj: { // Temporarily set to NULL prs->Fields->Item["ValueType"]->Value = _variant_t((long) VT_UNKNOWN); prs->Fields->Item["lValue"]->Value = _variant_t((long) NULL); if (punk != NULL) { hr = prs->Update(); long idObj; hr = m_pdb->SaveObject(punk, &idObj); if (FAILED(hr)) return hr; // Seek back and fix it up. hr = SeekPropsRS(prs, m_pdb->FSQLServer(), m_idObj, m_idPropType, FALSE, m_idProvider, m_idLang); if (FAILED(hr)) return hr; prs->Fields->Item["lValue"]->Value = idObj; } } break; } prs->Fields->Item["ValueType"]->Value = _variant_t((long) vt); } catch (_com_error & e) { return e.Error(); } return S_OK; } HRESULT CMetaProperty::LoadValue(ADODB::_RecordsetPtr prs) { HRESULT hr; _variant_t varType = prs->Fields->Item["ValueType"]->Value; try { varType.ChangeType(VT_I4); } catch (_com_error &) { return E_INVALIDARG; } switch (varType.lVal) { default: return E_INVALIDARG; case VT_EMPTY: m_varValue.Clear(); break; case VT_I2: case VT_I4: m_varValue = prs->Fields->Item["lValue"]->Value; break; case VT_R4: case VT_R8: case VT_DATE: m_varValue = prs->Fields->Item["fValue"]->Value; break; case VT_BSTR_BLOB: case VT_BSTR: m_varValue = prs->Fields->Item["sValue"]->Value; m_varValue.vt = varType.lVal; break; case VT_UNKNOWN: #if 0 hr = LoadObjectFromField(prs->Fields->Item["oValue"], &m_varValue); if (FAILED(hr)) return hr; #else { CComPtr punk; long idObj = prs->Fields->Item["lValue"]->Value; if (idObj != NULL) { hr = m_pdb->CacheObject(idObj, (long) 0, &punk); if (FAILED(hr)) return hr; } m_varValue = punk; } #endif break; } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // CMetaProperties STDMETHODIMP CMetaProperties::get_Count(long *plCount) { ENTER_API { ValidateOut(plCount, 0); HRESULT hr; ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropsIndexed(&prs); prs->MoveFirst(); TCHAR szFind[32]; wsprintf(szFind, _T("idObj = %d"), m_idObj); hr = prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); if (FAILED(hr)) return S_OK; if (m_idPropType != 0) { wsprintf(szFind, _T("idPropType = %d"), m_idPropType); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); if (prs->EndOfFile) return S_OK; } // UNDONE: This is not the most efficient, but it's what works for now. while (!prs->EndOfFile) { long idObj2 = prs->Fields->Item["idObj"]->Value; if (m_idObj != idObj2) break; if (m_idPropType != 0) { long idPropType = prs->Fields->Item["idPropType"]->Value; if (m_idPropType != idPropType) break; } (*plCount)++; hr = prs->MoveNext(); if (FAILED(hr)) return hr; } return S_OK; } LEAVE_API } HRESULT CMetaProperties::Load(long idPropType, ADODB::_RecordsetPtr prs, IMetaProperty **ppprop) { HRESULT hr; CComPtr pproptype; CComPtr pprop; hr = m_pdb->get_MetaPropertyType(idPropType, &pproptype); if (FAILED(hr)) return hr; long idLang = prs->Fields->Item["idLanguage"]->Value; long idProvider = prs->Fields->Item["idProvider"]->Value; CComQIPtr pproptypeT(pproptype); _variant_t varValue; hr = pproptypeT->GetNew(idProvider, idLang, varValue, &pprop); if (FAILED(hr)) return hr; CComQIPtr ppropT(pprop); ppropT->SetObjectID(m_idObj); hr = ppropT->LoadValue(prs); if (FAILED(hr)) return hr; *ppprop = pprop.Detach(); return S_OK; } STDMETHODIMP CMetaProperties::get_Item(VARIANT varIndex, IMetaProperty **ppprop) { ENTER_API { ValidateOutPtr(ppprop, NULL); HRESULT hr; if (varIndex.vt == VT_BSTR) { CComPtr pproptype; hr = m_pdb->get_MetaPropertyType(varIndex.bstrVal, &pproptype); if (FAILED(hr)) return E_INVALIDARG; hr = get_ItemWith(pproptype, 0, ppprop); if (FAILED(hr)) { CComPtr pprovider; m_pdb->get_GuideDataProvider(&pprovider); _variant_t varNil; hr = get_AddNew(pproptype, pprovider, 0, varNil, ppprop); } return hr; } _variant_t var(varIndex); try { var.ChangeType(VT_I4); } catch (_com_error &) { return E_INVALIDARG; } if (var.lVal < 0) return E_INVALIDARG; ADODB::_RecordsetPtr prs; hr = m_pdb->get_PropsIndexed(&prs); prs->MoveFirst(); TCHAR szFind[32]; wsprintf(szFind, _T("idObj = %d"), m_idObj); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); if (prs->EndOfFile) return E_INVALIDARG; if (m_idPropType != 0) { wsprintf(szFind, _T("idPropType = %d"), m_idPropType); prs->Find(_bstr_t(szFind), 0, ADODB::adSearchForward); if (prs->EndOfFile) return E_INVALIDARG; } if (var.lVal > 0) { hr = prs->Move(var.lVal); if (FAILED(hr)) return hr; } if (prs->EndOfFile) return E_INVALIDARG; long idObj2 = prs->Fields->Item["idObj"]->Value; if (m_idObj != idObj2) return E_INVALIDARG; long idPropType = prs->Fields->Item["idPropType"]->Value; if (m_idPropType != 0 && (m_idPropType != idPropType)) return E_INVALIDARG; return Load(idPropType, prs, ppprop); } LEAVE_API } HRESULT CMetaProperties::get_AddNew(IMetaPropertyType *pproptype, IGuideDataProvider *pprovider, long lang, VARIANT varValue, IMetaProperty **ppprop) { ENTER_API { ValidateInPtr(pproptype); ValidateOutPtr(ppprop, NULL); HRESULT hr; CComQIPtr pproptypeT(pproptype); long idProvider = 0; if (pprovider != NULL) pprovider->get_ID(&idProvider); hr = pproptypeT->GetNew(idProvider, lang, varValue, ppprop); if (FAILED(hr)) return hr; return Add(*ppprop); } LEAVE_API } STDMETHODIMP CMetaProperties::get_AddNew(IMetaPropertyType *pproptype, long lang, VARIANT varValue, IMetaProperty **ppprop) { ENTER_API { ValidateInPtr(pproptype); ValidateOutPtr(ppprop, NULL); HRESULT hr = pproptype->get_New(lang, varValue, ppprop); if (FAILED(hr)) return hr; return Add(*ppprop); } LEAVE_API } #if 0 STDMETHODIMP CMetaProperties::get_UpdateOrAddNew(IMetaPropertyType *pproptype, long lang, VARIANT varValue, IMetaProperty **ppprop) { HRESULT hr; CComPtr pprop; hr = get_ItemWith(pproptype, lang, &pprop); if (FAILED(hr)) return AddNew(pproptype, lang, varValue, ppprop); hr = pprop->put_Value(varValue); if (FAILED(hr)) return hr; *ppprop = pprop.Detach(); return S_OK; } #endif STDMETHODIMP CMetaProperties::Add(IMetaProperty *pprop) { HRESULT hr; if (pprop == NULL) return E_FAIL; ADODB::_RecordsetPtr prs; m_pdb->get_PropsRS(&prs); CComQIPtr ppropT(pprop); hr = ppropT->SetObjectID(m_idObj); if (FAILED(hr)) return hr; hr = ppropT->AddNew(prs); if (FAILED(hr)) return hr; hr = ppropT->SaveValue(prs); if (FAILED(hr)) { prs->CancelUpdate(); return hr; } hr = prs->Update(); if (FAILED(hr)) return hr; m_pdb->Broadcast_ItemChanged(m_idObj); return hr; } STDMETHODIMP CMetaProperties::get_ItemWithTypeProviderLang(IMetaPropertyType *pproptype, IGuideDataProvider *pprovider, long idLang, IMetaProperty **ppprop) { ENTER_API { ValidateInPtr(pproptype); ValidateOutPtr(ppprop, NULL); long idProvider = 0; if (pprovider != NULL) pprovider->get_ID(&idProvider); return get_ItemWithTypeProviderLang(pproptype, FALSE, idProvider, idLang, ppprop); } LEAVE_API } HRESULT CMetaProperties::get_ItemWithTypeProviderLang(IMetaPropertyType *pproptype, boolean fAnyProvider, long idProvider, long idLang, IMetaProperty **ppprop) { HRESULT hr; ADODB::_RecordsetPtr prs; CComQIPtr pproptypeT(pproptype); long idPropType = pproptypeT->GetID(); hr = m_pdb->get_PropsIndexed(&prs); hr = SeekPropsRS(prs, m_pdb->FSQLServer(), m_idObj, idPropType, fAnyProvider, idProvider, idLang); if (FAILED(hr)) return hr; return Load(idPropType, prs, ppprop); } STDMETHODIMP CMetaProperties::get_ItemWith(IMetaPropertyType *pproptype, long idLang, IMetaProperty **ppprop) { ENTER_API { ValidateInPtr(pproptype); ValidateOutPtr(ppprop); long idProvider = m_pdb->GetIDGuideDataProvider(); return get_ItemWithTypeProviderLang(pproptype, TRUE, idProvider, idLang, ppprop); } LEAVE_API } STDMETHODIMP CMetaProperties::get_ItemsWithMetaPropertyType(IMetaPropertyType *ptype, IMetaProperties **ppprops) { ENTER_API { ValidateInPtr(ptype); ValidateOutPtr(ppprops, NULL); CComQIPtr ptypeT(ptype); if (ptypeT == NULL) return E_POINTER; long idPropType; idPropType = ptypeT->GetID(); CComPtr pprops = NewComObject(CMetaProperties); if (pprops != NULL) pprops->Init(m_idObj, idPropType, m_pdb); *ppprops = pprops.Detach(); return S_OK; } LEAVE_API } ///////////////////////////////////////////////////////////////////////////// // CMetaPropertyCondition STDMETHODIMP CMetaPropertyCondition::get_And(IMetaPropertyCondition *ppropcond2, IMetaPropertyCondition **pppropcond) { ENTER_API { ValidateInPtr(ppropcond2); ValidateOutPtr(pppropcond, NULL); CComPtr ppropcond = NewComObject(CMetaPropertyConditionAnd); if (ppropcond == NULL) return E_OUTOFMEMORY; ppropcond->Init(this, ppropcond2); *pppropcond = ppropcond.Detach(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyCondition::get_Or(IMetaPropertyCondition *ppropcond2, IMetaPropertyCondition **pppropcond) { ENTER_API { ValidateInPtr(ppropcond2); ValidateOutPtr(pppropcond, NULL); CComPtr ppropcond = NewComObject(CMetaPropertyConditionOr); if (ppropcond == NULL) return E_OUTOFMEMORY; ppropcond->Init(this, ppropcond2); *pppropcond = ppropcond.Detach(); return S_OK; } LEAVE_API } #if 0 STDMETHODIMP CMetaPropertyCondition::get_Not(IMetaPropertyCondition **pppropcond) { ENTER_API { ValidateOutPtr(pppropcond, NULL); CComPtr ppropcond = NewComObject(CMetaPropertyConditionNot); if (ppropcond == NULL) return E_OUTOFMEMORY; ppropcond->Init(this); *pppropcond = ppropcond.Detach(); return S_OK; } LEAVE_API } STDMETHODIMP CMetaPropertyCondition::get_Test(IMetaProperties *pprops, BOOL *pfOk) { ENTER_API { ValidateInPtr(pprops); ValidateOut(pfOk, FALSE); return S_OK; } LEAVE_API } #endif