1486 lines
38 KiB
C++
1486 lines
38 KiB
C++
/*---------------------------------------------------------------------------
|
|
File: VSet.cpp
|
|
|
|
Comments: Implementation of IVarSet interface.
|
|
|
|
(c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 11/19/98 19:44:06
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
// VSet.cpp : Implementation of CVSet
|
|
#include "stdafx.h"
|
|
|
|
#ifdef STRIPPED_VARSET
|
|
#include "NoMcs.h"
|
|
#include <comdef.h>
|
|
#include "Err.hpp"
|
|
#include "Varset.h"
|
|
#else
|
|
#endif
|
|
|
|
#include "VarSetI.h"
|
|
#include "VSet.h"
|
|
#include "VarMap.h"
|
|
#include "DotStr.hpp"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CVSet
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// IVarSet
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Gets the number of items in the map and all sub-maps
|
|
STDMETHODIMP CVSet::get_Count(/* [retval][out] */long* retval)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_Count");
|
|
|
|
if (retval == NULL)
|
|
{
|
|
MCSVERIFYSZ(FALSE,"get_Count: output pointer was null, returning E_POINTER");
|
|
return E_POINTER;
|
|
}
|
|
|
|
m_cs.Lock();
|
|
*retval = m_nItems;
|
|
MCSASSERTSZ(! m_nItems || m_nItems == m_data->CountItems() - (m_data->HasData()?0:1),"get_Count:Item count consistency check failed.");
|
|
m_cs.Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::get_NumChildren(/* [in] */BSTR parentKey,/* [out,retval] */long*count)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_NumChildren");
|
|
|
|
HRESULT hr = S_OK;
|
|
CVarData * pVar;
|
|
CString parent;
|
|
|
|
parent = parentKey;
|
|
if ( count == NULL )
|
|
{
|
|
MCSVERIFYSZ(FALSE,"get_NumChildren: output pointer was null, returning E_POINTER");
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
pVar = GetItem(parent,FALSE);
|
|
if ( pVar )
|
|
{
|
|
if ( pVar->HasChildren() )
|
|
{
|
|
(*count) = pVar->GetChildren()->GetCount();
|
|
}
|
|
else
|
|
{
|
|
(*count) = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The parent key does not exist
|
|
(*count) = 0;
|
|
}
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Adds or changes a value in the map
|
|
STDMETHODIMP CVSet::putObject(/* [in] */BSTR property,/* [in] */VARIANT value)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::putObject");
|
|
|
|
CVarData * pVar = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEDATA )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
m_bNeedToSave = TRUE;
|
|
pVar = GetItem(property,TRUE);
|
|
if ( pVar )
|
|
{
|
|
MC_LOG("set value for " << McString::String(property));
|
|
m_nItems+=pVar->SetData("",&value,FALSE,&hr);
|
|
}
|
|
else
|
|
{
|
|
MCSASSERTSZ(FALSE,"VarSet internal error creating or retrieving node");
|
|
// GetItem failed - cannot add item to property
|
|
hr = E_FAIL;
|
|
}
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Adds or changes a value in the map
|
|
STDMETHODIMP CVSet::put(/* [in] */BSTR property,/* [in] */VARIANT value)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::put");
|
|
|
|
CVarData * pVar = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEDATA )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
m_bNeedToSave = TRUE;
|
|
pVar = GetItem(property,TRUE);
|
|
if ( pVar )
|
|
{
|
|
MC_LOG("set value for " << McString::String(property));
|
|
m_nItems+=pVar->SetData("",&value,TRUE,&hr);
|
|
}
|
|
else
|
|
{
|
|
MCSASSERTSZ(FALSE,"VarSet internal error creating or retrieving node");
|
|
// GetItem failed - cannot add item to property
|
|
hr = E_FAIL;
|
|
}
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
CVarData * // ret- pointer to item in varset
|
|
CVSet::GetItem(
|
|
CString str, // in - key to look for
|
|
BOOL addToMap, // in - if TRUE, adds the key to the map if it does not exist
|
|
CVarData * base // in - starting point
|
|
)
|
|
{
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_INTERNAL,"CVSet::GetItem");
|
|
|
|
CVarData * curr = base;
|
|
CVarData * result = NULL;
|
|
CDottedString s(str);
|
|
CString seg;
|
|
CString next;
|
|
|
|
if ( ! curr )
|
|
{
|
|
curr = m_data;
|
|
MC_LOG("No basepoint provided, using root element");
|
|
}
|
|
|
|
if ( str.IsEmpty() )
|
|
{
|
|
result = curr;
|
|
MC_LOG("Returning current node");
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 0 ; curr && i < s.NumSegments(); i++ )
|
|
{
|
|
s.GetSegment(i,seg);
|
|
MC_LOG("Looking for key segment "<< McString::String(seg) );
|
|
curr->SetCaseSensitive(m_CaseSensitive);
|
|
if ( ! curr->Lookup(seg,result) )
|
|
{
|
|
if ( addToMap )
|
|
{
|
|
MC_LOG(McString::String(seg) << " not found, creating new node");
|
|
result = new CVarData;
|
|
if (!result)
|
|
break;
|
|
result->SetCaseSensitive(m_CaseSensitive);
|
|
result->SetIndexed(m_Indexed);
|
|
curr->SetAt(seg,result);
|
|
m_nItems++;
|
|
}
|
|
else
|
|
{
|
|
MC_LOG(McString::String(seg) << " not found, aborting");
|
|
result = NULL;
|
|
break;
|
|
}
|
|
}
|
|
curr = result;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Retrieves a value from the map
|
|
STDMETHODIMP CVSet::get(/* [in] */BSTR property,/* [retval][out] */VARIANT * value)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get");
|
|
|
|
CVarData * pVar;
|
|
HRESULT hr = S_OK;
|
|
CComVariant var;
|
|
CString s;
|
|
|
|
if (property == NULL )
|
|
{
|
|
MCSVERIFYSZ(FALSE,"CVSet::get - output pointer is NULL, returning E_POINTER");
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
s = property;
|
|
pVar = GetItem(s);
|
|
var.Attach(value);
|
|
if ( pVar )
|
|
{
|
|
MC_LOG("got value for " << McString::String(property));
|
|
var.Copy(pVar->GetData());
|
|
}
|
|
else
|
|
{
|
|
MC_LOG("CVSet::get " << McString::String(property) << " was not found, returning empty variant");
|
|
}
|
|
// if the item was not found, set the variant to VT_EMPTY
|
|
var.Detach(value);
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::put_CaseSensitive(/* [in] */BOOL newVal)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::put_CaseSensitive");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEPROPS )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
m_bNeedToSave = TRUE;
|
|
m_CaseSensitive = newVal;
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::get_CaseSensitive(/* [retval][out] */BOOL * isCaseSensitive)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_CaseSensitive");
|
|
|
|
if ( ! isCaseSensitive )
|
|
{
|
|
MCSVERIFYSZ(FALSE,"CVSet::get_CaseSensitive - output pointer is NULL, returning E_POINTER");
|
|
return E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
(*isCaseSensitive) = m_CaseSensitive;
|
|
m_cs.Unlock();
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// This function is used to sort the keys being returned from an enum.
|
|
int __cdecl SortComVariantStrings(const void * v1, const void * v2)
|
|
{
|
|
CComVariant * var1 = (CComVariant*)v1;
|
|
CComVariant * var2 = (CComVariant*)v2;
|
|
|
|
if ( var1->vt == VT_BSTR && var2->vt == VT_BSTR )
|
|
{
|
|
return wcscmp(var1->bstrVal,var2->bstrVal);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// This returns an IEnumVARIANT interface. It is used by the VB For Each command.
|
|
// This enumerates only the keys, not the values. It is not very efficient, especially for large sets.
|
|
STDMETHODIMP CVSet::get__NewEnum(/* [retval][out] */IUnknown** retval)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_NewEnum");
|
|
|
|
if (retval == NULL)
|
|
{
|
|
MCSVERIFYSZ(FALSE,"CVSet::get_NewEnum - output pointer is NULL, returning E_POINTER");
|
|
return E_POINTER;
|
|
}
|
|
|
|
// initialize output parameter
|
|
(*retval) = NULL;
|
|
|
|
typedef CComObject<CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
|
|
_Copy<VARIANT> > > enumvar;
|
|
|
|
HRESULT hRes = S_OK;
|
|
|
|
enumvar * p = new enumvar;
|
|
|
|
if (p == NULL)
|
|
{
|
|
MCSVERIFYSZ(FALSE,"CVSet::get_NewEnum - Could not create IEnumVARIANT object");
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hRes = p->FinalConstruct();
|
|
if (hRes == S_OK)
|
|
{
|
|
m_cs.Lock();
|
|
|
|
CVarData * map = m_data;
|
|
CString start;
|
|
CString seg;
|
|
|
|
// Build an array of variants to hold the keys
|
|
CComVariant * pVars = new CComVariant[m_data->CountItems()+1];
|
|
CString key;
|
|
int offset = 0;
|
|
|
|
key = _T("");
|
|
if ( map->GetData() && map->GetData()->vt != VT_EMPTY )
|
|
{
|
|
pVars[offset] = key;
|
|
offset++;
|
|
}
|
|
if ( map->HasChildren() )
|
|
{
|
|
BuildVariantKeyArray(key,map->GetChildren(),pVars,&offset);
|
|
}
|
|
|
|
if ( ! m_Indexed )
|
|
{
|
|
// Sort the results
|
|
qsort(pVars,offset,(sizeof CComVariant),&SortComVariantStrings);
|
|
}
|
|
|
|
hRes = p->Init(pVars, &pVars[offset], NULL,AtlFlagCopy);
|
|
if (hRes == S_OK)
|
|
hRes = p->QueryInterface(IID_IUnknown, (void**)retval);
|
|
|
|
delete [] pVars;
|
|
m_cs.Unlock();
|
|
}
|
|
}
|
|
if (hRes != S_OK)
|
|
delete p;
|
|
|
|
return hRes;
|
|
}
|
|
|
|
// Helper function for get__NewEnum
|
|
// copies all the keys in the map, and all sub-maps, into a CComVariant array.
|
|
// the values are then sorted if necessary.
|
|
void
|
|
CVSet::BuildVariantKeyArray(
|
|
CString prefix, // in - string to tack on to the beginning of each key (used when enumerating subkeys)
|
|
CMapStringToVar * map, // in - map containing data
|
|
CComVariant * pVars, // i/o- array that will contain all the keys
|
|
int * offset // i/o- number of keys copied to pVars (index to use for next insertion)
|
|
)
|
|
{
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_INTERNAL,"CVSet::BuildVariantKeyArray");
|
|
|
|
int i;
|
|
int nItems;
|
|
CVarData * pObj;
|
|
CString key;
|
|
CComVariant var;
|
|
CString val;
|
|
|
|
if ( ! map )
|
|
return; // no data =>no work to do
|
|
|
|
nItems = map->GetCount();
|
|
|
|
if ( ! m_Indexed )
|
|
{
|
|
POSITION pos;
|
|
|
|
pos = map->GetStartPosition();
|
|
for ( i = 0 ; pos && i < nItems ; i++ )
|
|
{
|
|
map->GetNextAssoc(pos,key,pObj);
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
var = prefix + L"." + key;
|
|
}
|
|
else
|
|
{
|
|
var = key;
|
|
}
|
|
// add each key to the array
|
|
var.Detach(&pVars[(*offset)]);
|
|
(*offset)++;
|
|
if ( pObj->HasChildren() )
|
|
{
|
|
// Recursively do the sub-map
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyArray(prefix+L"."+key,pObj->GetChildren(),pVars,offset);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyArray(key,pObj->GetChildren(),pVars,offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CIndexItem * item;
|
|
CIndexTree * index = map->GetIndex();
|
|
|
|
ASSERT(index);
|
|
|
|
if ( ! index )
|
|
return;
|
|
|
|
item = index->GetFirstItem();
|
|
|
|
for ( i = 0 ; item && i < nItems ; i++ )
|
|
{
|
|
key = item->GetKey();
|
|
pObj = item->GetValue();
|
|
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
var = prefix + L"." + key;
|
|
}
|
|
else
|
|
{
|
|
var = key;
|
|
}
|
|
// add each key to the array
|
|
var.Detach(&pVars[(*offset)]);
|
|
(*offset)++;
|
|
if ( pObj->HasChildren() )
|
|
{
|
|
// Recursively do the sub-map
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyArray(prefix+L"."+key,pObj->GetChildren(),pVars,offset);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyArray(key,pObj->GetChildren(),pVars,offset);
|
|
}
|
|
}
|
|
item = index->GetNextItem(item);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CVSet::getItems2(
|
|
/* [in] */VARIANT basepoint, // in - if specified, only children of this node will be enumerated
|
|
/* [in] */VARIANT startAfter, // in - the enumeration will begin with the next item in the map following this key.
|
|
/* [in] */VARIANT bRecursive, // in - TRUE includes all sub-items, FALSE enumerates one level only.
|
|
/* [in] */VARIANT bSize, // in - max number of elements to return (the size of the arrays)
|
|
/* [out] */VARIANT * keyVar, // out- array of keys
|
|
/* [out] */VARIANT * valVar, // out- array of values
|
|
/* [in,out] */VARIANT* nReturned // out- number of items copied
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::getItems2");
|
|
|
|
HRESULT hr = S_OK;
|
|
LONG n = 0;
|
|
LONG size = bSize.pvarVal->iVal;
|
|
|
|
// TODO: Verify that all the arguments are the correct type!
|
|
|
|
// Allocate SAFEARRAYs for the keys and values
|
|
SAFEARRAY * keys = NULL;
|
|
SAFEARRAY * values= NULL;
|
|
_variant_t key;
|
|
_variant_t val;
|
|
_variant_t num;
|
|
|
|
if ( ! keys || !values )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hr = getItems(basepoint.bstrVal,startAfter.bstrVal,bRecursive.boolVal,size,&keys,&values,&n);
|
|
key.vt = VT_ARRAY | VT_VARIANT;
|
|
key.parray = keys;
|
|
val.vt = VT_ARRAY | VT_VARIANT;
|
|
val.parray = values;
|
|
num.vt = VT_I4;
|
|
num.lVal = n;
|
|
(*keyVar) = key.Detach();
|
|
(*valVar) = val.Detach();
|
|
(*nReturned) = num.Detach();
|
|
}
|
|
return hr;
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CVSet::getItems(
|
|
/* [in] */BSTR basepoint, // in - if specified, only children of this node will be enumerated
|
|
/* [in] */BSTR startAfter, // in - the enumeration will begin with the next item in the map following this key.
|
|
/* [in] */BOOL bRecursive, // in - TRUE includes all sub-items, FALSE enumerates one level only.
|
|
/* [in] */ULONG bSize, // in - max number of elements to return (the size of the arrays)
|
|
/* [out] */SAFEARRAY ** keys, // out- array of keys
|
|
/* [out] */SAFEARRAY ** values, // out- array of values
|
|
/* [out] */LONG * nReturned // out- number of items copied
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::getItems");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
(*nReturned) = 0;
|
|
(*keys) = 0;
|
|
(*values) = 0;
|
|
|
|
m_cs.Lock();
|
|
|
|
CVarData * map = m_data;
|
|
CString base;
|
|
CString start;
|
|
CString seg;
|
|
|
|
|
|
// Find the map to enumerate
|
|
base = basepoint;
|
|
if ( base.GetLength() > 0 )
|
|
{
|
|
map = GetItem(base);
|
|
}
|
|
|
|
if ( ! map )
|
|
{
|
|
// not found
|
|
(*nReturned) = 0;
|
|
}
|
|
else
|
|
{
|
|
// Build an array of variants to hold the keys
|
|
int offset = 0;
|
|
|
|
SAFEARRAYBOUND bound[1];
|
|
LONG n = 0;
|
|
LONG size = bSize;
|
|
|
|
bound[0].lLbound = 0;
|
|
bound[0].cElements = size;
|
|
|
|
|
|
// Allocate SAFEARRAYs for the keys and values
|
|
(*keys) = SafeArrayCreate(VT_VARIANT, 1, bound);
|
|
(*values) = SafeArrayCreate(VT_VARIANT, 1, bound);
|
|
|
|
start = startAfter;
|
|
|
|
if ( base.GetLength() && start.GetLength() )
|
|
{
|
|
// ASSERT( that LEFT(start,LEN(base)) = base
|
|
//start = start.Right(start.GetLength() - base.GetLength() - 1);
|
|
}
|
|
|
|
if ( base.IsEmpty() && start.IsEmpty() )
|
|
{
|
|
if ( map->GetData() && map->GetData()->vt != VT_EMPTY )
|
|
{
|
|
long index[1];
|
|
|
|
index[0] = 0;
|
|
// add the root element to the results
|
|
if ( (*keys)->fFeatures & FADF_BSTR )
|
|
{
|
|
SafeArrayPutElement((*keys),index,_T(""));
|
|
}
|
|
else
|
|
{
|
|
// VBScript can only use VARIANT arrays (see getItems2)
|
|
_variant_t tempKey;
|
|
tempKey = _T("");
|
|
SafeArrayPutElement((*keys),index,&tempKey);
|
|
}
|
|
|
|
SafeArrayPutElement((*values),index,map->GetData());
|
|
offset++;
|
|
}
|
|
|
|
}
|
|
if ( map->HasChildren() )
|
|
{
|
|
BuildVariantKeyValueArray(base,start,map->GetChildren(),(*keys),
|
|
(*values),&offset,bSize,bRecursive);
|
|
}
|
|
(*nReturned) = offset;
|
|
}
|
|
m_cs.Unlock();
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
// helper function for getItems. Fills SAFEARRAYs of keys and values
|
|
// if the varset is indexed, the items will be returned in sorted order, o.w. they will be in arbitrary (but consistent) order.
|
|
void
|
|
CVSet::BuildVariantKeyValueArray(
|
|
CString prefix, // in - string to tack on to the beginning of each key (used when enumerating subkeys)
|
|
CString startAfter, // in - optional, enumerates only those items that alphabetically follow this one.
|
|
CMapStringToVar * map, // in - map containing the data
|
|
SAFEARRAY * keys, // i/o- array that will contain the key values for the requested items
|
|
SAFEARRAY * pVars, // i/o- array that will contain the data values for the requested items
|
|
int * offset, // i/o- number of items copied to the arrays (index to use for next insertion)
|
|
int maxOffset, // in - allocated size of the arrays
|
|
BOOL bRecurse // in - whether to recursively process children
|
|
)
|
|
{
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_INTERNAL,"CVSet::BuildVariantKeyValueArray");
|
|
|
|
int i;
|
|
int nItems;
|
|
CVarData * pObj;
|
|
CString key; // last segment of key name
|
|
POSITION pos;
|
|
|
|
CComBSTR val; // fully qualified key name to add to array (val = prefix.key)
|
|
CComVariant var; // value to add to array
|
|
BOOL includeSomeChildrenOnly;
|
|
|
|
CDottedString dBase(prefix);
|
|
CDottedString dStartItem(startAfter);
|
|
|
|
int depth = dBase.NumSegments();
|
|
|
|
if ( ! map )
|
|
return; // no data => nothing to do
|
|
|
|
if ( (*offset) >= maxOffset )
|
|
return; // the arrays are full
|
|
|
|
includeSomeChildrenOnly = dStartItem.NumSegments() > depth;
|
|
|
|
nItems = map->GetCount();
|
|
// If we're not using an index, the items will be returned in arbitrary order
|
|
if ( ! m_Indexed )
|
|
{
|
|
if ( includeSomeChildrenOnly && bRecurse )
|
|
{
|
|
// the startAfter item is in a subtree. Find the appropriate element at this level and recursively continue the search
|
|
dStartItem.GetSegment(depth,key);
|
|
if ( map->Lookup(key,pObj) )
|
|
{
|
|
// found the object
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyValueArray(prefix+_T(".")+key,startAfter,pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyValueArray(key,startAfter,pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
}
|
|
// we've included the children of this item that come after 'startAfter',
|
|
// now process the rest of the items at this level
|
|
// make sure there's still room
|
|
if ( (*offset) >= maxOffset )
|
|
return; // the arrays are full
|
|
}
|
|
|
|
// this is the usual case. process the items at this level, starting with the element following StartAfter.
|
|
|
|
// Get a pointer to that first element
|
|
if ( startAfter.GetLength() > prefix.GetLength())
|
|
{
|
|
CString startItem;
|
|
dStartItem.GetSegment(depth,startItem);
|
|
// this returns the position before startItem
|
|
pos = (POSITION)map->GetPositionAt(startItem);
|
|
if (!pos)
|
|
return;
|
|
map->GetNextAssoc(pos,key,pObj);
|
|
}
|
|
else
|
|
{
|
|
pos = map->GetStartPosition();
|
|
}
|
|
|
|
for ( i = 0 ; pos && i < nItems ; i++ )
|
|
{
|
|
map->GetNextAssoc(pos,key,pObj);
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
val = prefix + L"." + key;
|
|
}
|
|
else
|
|
{
|
|
val = key;
|
|
}
|
|
// copy each item into the arrays
|
|
ASSERT((*offset) < maxOffset);
|
|
var.Copy(pObj->GetData());
|
|
LONG index[1];
|
|
index[0] = (*offset);
|
|
SafeArrayPutElement(pVars,index,&var);
|
|
if ( keys->fFeatures & FADF_BSTR )
|
|
{
|
|
SafeArrayPutElement(keys,index,val);
|
|
}
|
|
else
|
|
{
|
|
// VBScript can only use VARIANT arrays (see getItems2)
|
|
_variant_t tempKey;
|
|
tempKey = val;
|
|
SafeArrayPutElement(keys,index,&tempKey);
|
|
}
|
|
|
|
var.Clear();
|
|
(*offset)++;
|
|
if ( *offset >= maxOffset )
|
|
break; // arrays are full - stop
|
|
|
|
if ( bRecurse && pObj->HasChildren() )
|
|
{
|
|
// Recursively do the sub-map
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyValueArray(prefix+L"."+key,"",pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyValueArray(key,"",pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
if ( *offset >= maxOffset )
|
|
break; // arrays are full - stop
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Use the index to enumerate the items in alphabetical order
|
|
|
|
CIndexItem * curr;
|
|
CIndexTree * ndx = map->GetIndex();
|
|
|
|
ASSERT (ndx != NULL);
|
|
|
|
if ( includeSomeChildrenOnly && bRecurse )
|
|
{
|
|
// the startAfter item is in a subtree. Find the appropriate element at this level and recursively continue the search
|
|
dStartItem.GetSegment(depth,key);
|
|
if ( map->Lookup(key,pObj) )
|
|
{
|
|
// found the object
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyValueArray(prefix+_T(".")+key,startAfter,pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyValueArray(key,startAfter,pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
}
|
|
// we've included the children of this item that come after 'startAfter',
|
|
// now process the rest of the items at this level
|
|
// make sure there's still room
|
|
if ( (*offset) >= maxOffset )
|
|
return; // the arrays are full
|
|
}
|
|
|
|
// Get a pointer to the first item at this level AFTER startAfter
|
|
if ( startAfter.GetLength() > prefix.GetLength() )
|
|
{
|
|
CString startItem;
|
|
dStartItem.GetSegment(depth,startItem);
|
|
// if a starting item is specified, try using the hash function to find it in the table
|
|
curr = map->GetIndexAt(startItem);
|
|
if ( curr )
|
|
{
|
|
curr = ndx->GetNextItem(curr);
|
|
}
|
|
else
|
|
{
|
|
// The startAfter item is not in the table. Search the tree to find
|
|
// the first item that would follow it if it were there
|
|
curr = ndx->GetFirstAfter(startItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curr = ndx->GetFirstItem();
|
|
}
|
|
// Process all the items
|
|
while ( curr )
|
|
{
|
|
pObj = curr->GetValue();
|
|
key = curr->GetKey();
|
|
|
|
curr = ndx->GetNextItem(curr);
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
val = prefix + L"." + key;
|
|
}
|
|
else
|
|
{
|
|
val = key;
|
|
}
|
|
// add each item to the arrays
|
|
ASSERT((*offset) < maxOffset);
|
|
|
|
var.Copy(pObj->GetData());
|
|
|
|
LONG index[1];
|
|
|
|
index[0] = (*offset);
|
|
SafeArrayPutElement(pVars,index,&var);
|
|
if ( keys->fFeatures & FADF_BSTR )
|
|
{
|
|
SafeArrayPutElement(keys,index,val);
|
|
}
|
|
else
|
|
{
|
|
// VBScript can only use VARIANT arrays (see getItems2)
|
|
_variant_t tempKey;
|
|
tempKey = val;
|
|
SafeArrayPutElement(keys,index,&tempKey);
|
|
}
|
|
|
|
var.Clear();
|
|
(*offset)++;
|
|
|
|
if ( *offset >= maxOffset )
|
|
break; // arrays are full - stop
|
|
|
|
if ( bRecurse && pObj->HasChildren() )
|
|
{
|
|
// Recursively do the sub-map
|
|
if ( ! prefix.IsEmpty() )
|
|
{
|
|
BuildVariantKeyValueArray(prefix+L"."+key,"",pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
else
|
|
{
|
|
BuildVariantKeyValueArray(key,"",pObj->GetChildren(),keys,pVars,offset,maxOffset,bRecurse);
|
|
}
|
|
if ( *offset >= maxOffset )
|
|
break; // arrays are full - stop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP CVSet::Clear()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::Clear");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEDATA )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
m_bNeedToSave = TRUE;
|
|
m_data->RemoveAll();
|
|
m_data->GetData()->Clear();
|
|
m_data->GetData()->ChangeType(VT_EMPTY);
|
|
m_nItems = 0;
|
|
m_cs.Unlock();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////IPersistStreamInit//////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CVSet::GetClassID(CLSID __RPC_FAR *pClassID)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
(*pClassID) = CLSID_VarSet;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::IsDirty()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
if ( m_bNeedToSave )
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CVSet::Load(LPSTREAM pStm)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
ULONG result = 0;
|
|
HRESULT hr;
|
|
|
|
m_cs.Lock();
|
|
|
|
do { // once
|
|
|
|
hr = pStm->Read(&m_nItems,(sizeof m_nItems),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pStm->Read(&m_CaseSensitive,(sizeof m_CaseSensitive),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pStm->Read(&m_Indexed,(sizeof m_Indexed),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = m_data->ReadFromStream(pStm);
|
|
m_bNeedToSave = FALSE;
|
|
m_bLoaded = TRUE;
|
|
}
|
|
while (FALSE);
|
|
|
|
m_cs.Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::Save(LPSTREAM pStm,BOOL fClearDirty)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
ULONG result = 0;
|
|
HRESULT hr;
|
|
|
|
m_cs.Lock();
|
|
|
|
do { // once
|
|
hr = pStm->Write(&m_nItems,(sizeof m_nItems),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pStm->Write(&m_CaseSensitive,(sizeof m_CaseSensitive),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = pStm->Write(&m_Indexed,(sizeof m_Indexed),&result);
|
|
if ( FAILED(hr) )
|
|
break;
|
|
hr = m_data->WriteToStream(pStm);
|
|
if ( fClearDirty )
|
|
{
|
|
m_bNeedToSave = FALSE;
|
|
}
|
|
}while (FALSE);
|
|
|
|
m_cs.Unlock();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::GetSizeMax(ULARGE_INTEGER __RPC_FAR *pCbSize)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_INTERNAL,"VarSet GetSizeMax");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( pCbSize == NULL )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
LPSTREAM pStr = NULL;
|
|
DWORD rc;
|
|
STATSTG stats;
|
|
DWORD requiredLength = 0;
|
|
|
|
|
|
rc = CreateStreamOnHGlobal(NULL,TRUE,&pStr);
|
|
if ( ! rc )
|
|
{
|
|
hr = Save(pStr,FALSE);
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
hr = pStr->Stat(&stats,STATFLAG_NONAME);
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
requiredLength = stats.cbSize.LowPart;
|
|
}
|
|
}
|
|
pStr->Release();
|
|
}
|
|
|
|
pCbSize->LowPart = requiredLength;
|
|
MC_LOG("Size is " << McString::makeStr(requiredLength) );
|
|
pCbSize->HighPart = 0;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::InitNew()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
if ( m_bLoaded )
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
InitProperties();
|
|
m_cs.Unlock();
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CVSet::ImportSubTree(/*[in] */ BSTR key, /* [in] */ IVarSet * pVarSet)
|
|
{
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::ImportSubTree");
|
|
|
|
HRESULT hr = S_OK;
|
|
VARIANT value;
|
|
ULONG nGot;
|
|
_bstr_t keyB;
|
|
_bstr_t newkey;
|
|
// make sure the varset is valid
|
|
|
|
// enumerate the varset, inserting each item into the tree as key.item
|
|
IEnumVARIANT * varEnum = NULL;
|
|
IUnknown * pUnk = NULL;
|
|
|
|
// TODO: need to speed this up by using getItems
|
|
hr = pVarSet->get__NewEnum(&pUnk);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&varEnum);
|
|
pUnk->Release();
|
|
}
|
|
if ( SUCCEEDED(hr))
|
|
{
|
|
value.vt = VT_EMPTY;
|
|
while ( SUCCEEDED(hr = varEnum->Next(1,&value,&nGot)) )
|
|
{
|
|
if ( nGot==1 )
|
|
{
|
|
keyB = value.bstrVal;
|
|
newkey = key;
|
|
if ( newkey.length() )
|
|
{
|
|
newkey += _T(".");
|
|
}
|
|
newkey += keyB;
|
|
hr = pVarSet->get(keyB,&value);
|
|
if ( SUCCEEDED(hr ) )
|
|
{
|
|
hr = put(newkey,value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
if ( FAILED(hr) )
|
|
break;
|
|
}
|
|
if ( varEnum )
|
|
varEnum->Release();
|
|
}
|
|
varEnum = NULL;
|
|
// clean up
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::getReference( /* [in] */ BSTR key, /* [out,retval] */IVarSet ** ppVarSet)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::getReference");
|
|
|
|
HRESULT hr = S_OK;
|
|
CVarData * item = GetItem(key);
|
|
|
|
typedef CComObject<CVSet> myvset;
|
|
|
|
myvset * pVarSet;
|
|
|
|
if ( ! ppVarSet )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
if ( item )
|
|
{
|
|
pVarSet = new myvset;
|
|
AddRef();
|
|
((CVSet*)pVarSet)->SetData(this,item,m_Restrictions);
|
|
hr = pVarSet->QueryInterface(IID_IVarSet,(void**)ppVarSet);
|
|
}
|
|
else
|
|
{
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::DumpToFile(BSTR filename)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
#ifdef STRIPPED_VARSET
|
|
|
|
USES_CONVERSION;
|
|
|
|
TError errLog;
|
|
|
|
errLog.LogOpen((WCHAR*)filename,1,0);
|
|
|
|
errLog.MsgWrite(0,L"VarSet");
|
|
errLog.MsgWrite(0,L"Case Sensitive: %s, Indexed: %s",(m_CaseSensitive ? L"Yes" : L"No"),(m_Indexed ? L"Yes" : L"No") );
|
|
errLog.MsgWrite(0,L"User Data ( %ld ) items",m_nItems);
|
|
#else
|
|
|
|
#endif
|
|
m_cs.Lock();
|
|
|
|
CVarData * map = m_data;
|
|
CString start;
|
|
CString seg;
|
|
|
|
// Build an array of variants to hold the keys
|
|
CComVariant * pVars = new CComVariant[m_data->CountItems()+1];
|
|
CString key;
|
|
int offset = 1;
|
|
|
|
key = _T("");
|
|
|
|
if (!pVars)
|
|
{
|
|
m_cs.Unlock();
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
// include the root item in the list
|
|
|
|
pVars[0] = key;
|
|
if ( map->HasChildren() )
|
|
{
|
|
BuildVariantKeyArray(key,map->GetChildren(),pVars,&offset);
|
|
}
|
|
|
|
m_cs.Unlock();
|
|
|
|
if ( ! m_Indexed )
|
|
{
|
|
// Sort the results
|
|
qsort(pVars,offset,(sizeof CComVariant),&SortComVariantStrings);
|
|
}
|
|
|
|
|
|
for ( int i = 0 ; i < offset ; i++ )
|
|
{
|
|
CVarData * data;
|
|
CString value;
|
|
CString key;
|
|
|
|
key = pVars[i].bstrVal;
|
|
|
|
data = GetItem(key);
|
|
|
|
if ( data )
|
|
{
|
|
switch ( data->GetData()->vt )
|
|
{
|
|
case VT_EMPTY:
|
|
value = _T("<Empty>");
|
|
break;
|
|
case VT_NULL:
|
|
value = _T("<Null>");
|
|
break;
|
|
case VT_I2:
|
|
value.Format(_T("%ld"),data->GetData()->iVal);
|
|
break;
|
|
case VT_I4:
|
|
value.Format(_T("%ld"),data->GetData()->lVal);
|
|
break;
|
|
case VT_BSTR:
|
|
value = data->GetData()->bstrVal;
|
|
break;
|
|
default:
|
|
value.Format(_T("variant type=0x%lx"),data->GetData()->vt);
|
|
break;
|
|
}
|
|
#ifdef STRIPPED_VARSET
|
|
errLog.MsgWrite(0,L" [%ls] %ls",key.GetBuffer(0),value.GetBuffer(0));
|
|
#else
|
|
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef STRIPPED_VARSET
|
|
errLog.MsgWrite(0,L" [%ls] <No Value>",key.GetBuffer(0));
|
|
#else
|
|
#endif
|
|
}
|
|
}
|
|
delete [] pVars;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::get_Indexed(BOOL *pVal)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_Indexed");
|
|
if ( pVal == NULL )
|
|
return E_POINTER;
|
|
|
|
m_cs.Lock();
|
|
(*pVal) = m_Indexed;
|
|
m_cs.Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::put_Indexed(BOOL newVal)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::put_Indexed");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEPROPS )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
m_cs.Lock();
|
|
m_bNeedToSave = TRUE;
|
|
m_Indexed = newVal;
|
|
m_data->SetIndexed(m_Indexed);
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CVSet::get_AllowRehashing(BOOL *pVal)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::get_AllowRehashing");
|
|
if ( pVal == NULL )
|
|
return E_POINTER;
|
|
|
|
m_cs.Lock();
|
|
(*pVal) = m_AllowRehashing;
|
|
m_cs.Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::put_AllowRehashing(BOOL newVal)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
MC_LOGBLOCKIF(VARSET_LOGLEVEL_CLIENT,"CVSet::put_AllowRehashing");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_Restrictions & VARSET_RESTRICT_NOCHANGEPROPS )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else
|
|
{
|
|
|
|
m_cs.Lock();
|
|
|
|
m_bNeedToSave = TRUE;
|
|
|
|
m_AllowRehashing = newVal;
|
|
m_data->SetAllowRehashing(newVal);
|
|
|
|
m_cs.Unlock();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::get_Restrictions(DWORD * restrictions)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( restrictions == NULL )
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
(*restrictions) = m_Restrictions;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::put_Restrictions(DWORD newRestrictions)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD rAdding = newRestrictions & ~m_Restrictions;
|
|
DWORD rRemoving = ~newRestrictions & m_Restrictions;
|
|
|
|
|
|
// Can't remove any restrictions passed down from parent.
|
|
if ( ( rRemoving & m_ImmutableRestrictions) )
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
else if ( rAdding & ! VARSET_RESTRICT_ALL )
|
|
{
|
|
hr = E_NOTIMPL;
|
|
}
|
|
else
|
|
{
|
|
// the change is OK.
|
|
m_Restrictions = newRestrictions;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// IMarshal implemention
|
|
// This marshals the varset to a stream that is then sent across the wire
|
|
STDMETHODIMP CVSet::GetUnmarshalClass(REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
*pCid = GetObjectCLSID();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::GetMarshalSizeMax(REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
ULARGE_INTEGER uli;
|
|
|
|
hr = GetSizeMax(&uli);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pSize = uli.LowPart;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::MarshalInterface(IStream *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestCtx, DWORD mshlflags)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Save the varset's data to a stream
|
|
hr = Save(pStm, FALSE);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::UnmarshalInterface(IStream *pStm, REFIID riid, void **ppv)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Load up the data from the stream using our IPersistStream implementation
|
|
hr = Load(pStm);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = QueryInterface(riid,ppv);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::ReleaseMarshalData(IStream * /*pStmNotNeeded*/)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
// we don't keep any state data, so there's nothing to release
|
|
// since we just read the object from the stream, the stream's pointer should already be at the end,
|
|
// so there's nothing left for us to do here
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CVSet::DisconnectObject(DWORD /*dwReservedNotUsed*/)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
return S_OK;
|
|
}
|