windows-nt/Source/XPSP1/NT/ds/adsi/winnt/cprops.cxx
2020-09-26 16:20:57 +08:00

1838 lines
39 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: cprops.cxx
//
// Contents: Property Cache functionality for NT
//
// Functions:
// CPropertyCache::addproperty
// CPropertyCache::updateproperty
// CPropertyCache::findproperty
// CPropertyCache::getproperty
// CPropertyCache::putproperty
// CProperyCache::CPropertyCache
// CPropertyCache::~CPropertyCache
// CPropertyCache::createpropertycache
//
// History: 17-June-1996 RamV Created.
// cloned off NT property cache code
//
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
#pragma hdrstop
#define INITGUID
#if DBG
DECLARE_INFOLEVEL(NTMarshall);
DECLARE_DEBUG(NTMarshall);
#define NTMarshallDebugOut(x) NTMarshallInlineDebugOut x
#endif
void
ADsECodesToDispECodes(
HRESULT *pHr
);
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::addproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] --
// [vt] --
// [vaData] --
//
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
addproperty(
LPWSTR szPropertyName,
DWORD dwSyntaxId,
DWORD dwNumValues,
PNTOBJECT pNtObject
)
{
HRESULT hr = S_OK;
PPROPERTY pNewProperty = NULL;
LPWSTR tempString = NULL;
//
// Allocate the string first
//
tempString = AllocADsStr(szPropertyName);
if (!tempString)
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
//
// extend the property cache by adding a new property entry
//
_pProperties = (PPROPERTY)ReallocADsMem(
_pProperties,
_cb,
_cb + sizeof(PROPERTY)
);
if (!_pProperties) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pNewProperty = (PPROPERTY)((LPBYTE)_pProperties + _cb);
if (pNewProperty->szPropertyName) {
FreeADsStr(pNewProperty->szPropertyName);
pNewProperty->szPropertyName = NULL;
}
pNewProperty->szPropertyName = tempString;
//
// Update the index
//
_dwMaxProperties++;
_cb += sizeof(PROPERTY);
//
// add to dynamic dispatch table now ???
// - don't check schema here, is it more efficient at all? inconsistency
// ???
//
/*
hr = DispatchAddProperty(
szPropertyName
);
BAIL_ON_FAILURE(hr);
*/
RRETURN(hr);
error:
if (tempString)
FreeADsStr(tempString);
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::updateproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] --
// [vaData] --
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::updateproperty(
LPWSTR szPropertyName,
DWORD dwSyntaxId,
DWORD dwNumValues,
PNTOBJECT pNtObject,
BOOL fExplicit
)
{
HRESULT hr;
DWORD dwIndex;
PNTOBJECT pNtTempObject = NULL;
PPROPERTY pThisProperty = NULL;
hr = findproperty(
szPropertyName,
&dwIndex
);
BAIL_ON_FAILURE(hr);
pThisProperty = _pProperties + dwIndex;
if (!fExplicit) {
if (PROPERTY_FLAGS(pThisProperty) & CACHE_PROPERTY_MODIFIED) {
hr = S_OK;
goto error;
}
}
//
// Factor in cases where object state is necessary to
// decide on update.
//
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
hr = NtTypeCopyConstruct(
pNtObject,
dwNumValues,
&pNtTempObject
);
BAIL_ON_FAILURE(hr);
PROPERTY_NTOBJECT(pThisProperty) = pNtTempObject;
PROPERTY_FLAGS(pThisProperty) &= ~PROPERTY_MODIFIED;
error:
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::findproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] --
// [pdwIndex] --
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::findproperty(
LPWSTR szPropertyName,
PDWORD pdwIndex
)
{
DWORD i = 0;
PPROPERTY pThisProperty = NULL;
for (i = 0; i < _dwMaxProperties; i++) {
pThisProperty = _pProperties + i;
if (!_wcsicmp(pThisProperty->szPropertyName, szPropertyName)) {
*pdwIndex = i;
RRETURN(S_OK);
}
}
*pdwIndex = 0;
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::getproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] -- Property to retrieve from the cache
// [pvaData] -- Data returned in a variant
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
getproperty(
LPWSTR szPropertyName,
PDWORD pdwSyntaxId,
PDWORD pdwNumValues,
PNTOBJECT * ppNtObject,
BOOL *pfModified
)
{
HRESULT hr;
DWORD dwIndex = 0L;
PPROPERTY pThisProperty = NULL;
DWORD dwResult;
DWORD dwInfoLevel = 0;
hr = findproperty(
szPropertyName,
&dwIndex
);
// don't do implicit GetInfo if there is no ADSI object backing the
// property cache. This will be true for UMI interafec properties.
if ((hr == E_ADS_PROPERTY_NOT_FOUND) && (_pCoreADsObject != NULL)) {
hr = GetPropertyInfoLevel(
szPropertyName,
_pSchemaClassProps,
_dwNumProperties,
&dwInfoLevel
);
BAIL_ON_FAILURE(hr);
//
// Now call the GetInfo function
//
hr = _pCoreADsObject->GetInfo(
dwInfoLevel,
FALSE
);
BAIL_ON_FAILURE(hr);
hr = findproperty(
szPropertyName,
&dwIndex
);
}
BAIL_ON_FAILURE(hr);
pThisProperty = _pProperties + dwIndex;
if (PROPERTY_NTOBJECT(pThisProperty)) {
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
*pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
if(pfModified != NULL) { // caller wants to know if prop. was modified
if(PROPERTY_FLAGS(pThisProperty) & CACHE_PROPERTY_MODIFIED)
*pfModified = TRUE;
else
*pfModified = FALSE;
}
hr = NtTypeCopyConstruct(PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty),
ppNtObject );
BAIL_ON_FAILURE(hr);
}else {
*ppNtObject = NULL;
*pdwNumValues = 0;
*pdwSyntaxId = 0;
hr = E_FAIL;
}
error:
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::marshallgetproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] -- Property to retrieve from the cache
// [pvaData] -- Data returned in a variant
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
marshallgetproperty(
LPWSTR szPropertyName,
PDWORD pdwSyntaxId,
PDWORD pdwNumValues,
PNTOBJECT * ppNtObject
)
{
HRESULT hr;
DWORD dwIndex = 0L;
PPROPERTY pThisProperty = NULL;
DWORD dwResult;
DWORD dwInfoLevel = 0;
hr = findproperty(
szPropertyName,
&dwIndex
);
BAIL_ON_FAILURE(hr);
pThisProperty = _pProperties + dwIndex;
//
// If the data has not changed, then do not
// return data from the cache
//
if (PROPERTY_FLAGS(pThisProperty) == 0) {
hr = E_ADS_PROPERTY_NOT_MODIFIED;
BAIL_ON_FAILURE(hr);
}
if (PROPERTY_NTOBJECT(pThisProperty)) {
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
*pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
hr = NtTypeCopyConstruct(PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty),
ppNtObject );
BAIL_ON_FAILURE(hr);
}else {
*ppNtObject = NULL;
*pdwNumValues = 0;
*pdwSyntaxId = 0;
hr = E_FAIL;
}
error:
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::putproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] -- Clsid index
// [vaData] -- Matching clsid returned in *pclsid
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::putproperty(
LPWSTR szPropertyName,
DWORD dwSyntaxId,
DWORD dwNumValues,
PNTOBJECT pNtObject,
BOOL fMarkAsClean
)
{
HRESULT hr;
DWORD dwIndex = 0L;
PNTOBJECT pNtTempObject = NULL;
PPROPERTY pThisProperty = NULL;
hr = findproperty(
szPropertyName,
&dwIndex
);
BAIL_ON_FAILURE(hr);
pThisProperty = _pProperties + dwIndex;
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
hr = NtTypeCopyConstruct(
pNtObject,
dwNumValues,
&pNtTempObject
);
BAIL_ON_FAILURE(hr);
PROPERTY_NTOBJECT(pThisProperty) = pNtTempObject;
if(FALSE == fMarkAsClean)
PROPERTY_FLAGS(pThisProperty) |= CACHE_PROPERTY_MODIFIED;
error:
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
CPropertyCache::CPropertyCache():
_pCoreADsObject(NULL),
_pSchemaClassProps(NULL),
_dwMaxProperties(0),
_dwCurrentIndex(0),
_pProperties(NULL),
_cb(0),
_pDispProperties(NULL),
_dwDispMaxProperties(0),
_cbDisp(0)
{
}
//+------------------------------------------------------------------------
//
// Function: ~CPropertyCache
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
CPropertyCache::
~CPropertyCache()
{
DWORD i = 0;
PPROPERTY pThisProperty = NULL;
PDISPPROPERTY pThisDispProperty = NULL;
if (_pProperties) {
for (i = 0; i < _dwMaxProperties; i++) {
pThisProperty = _pProperties + i;
if (pThisProperty->szPropertyName) {
FreeADsStr(pThisProperty->szPropertyName);
pThisProperty->szPropertyName = NULL;
}
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
}
FreeADsMem(_pProperties);
}
//
// Free Dynamic Dispid Table
//
if (_pDispProperties) {
for ( DWORD i = 0; i < _dwDispMaxProperties; i++ ) {
pThisDispProperty = _pDispProperties + i;
if (pThisDispProperty->szPropertyName) {
FreeADsStr(pThisDispProperty->szPropertyName);
pThisDispProperty->szPropertyName = NULL;
}
}
FreeADsMem(_pDispProperties);
}
}
//+------------------------------------------------------------------------
//
// Function:
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
createpropertycache(
PPROPERTYINFO pSchemaClassProps,
DWORD dwNumProperties,
CCoreADsObject FAR * pCoreADsObject,
CPropertyCache FAR *FAR * ppPropertyCache
)
{
CPropertyCache FAR * pPropertyCache = NULL;
pPropertyCache = new CPropertyCache();
if (!pPropertyCache) {
RRETURN_EXP_IF_ERR(E_OUTOFMEMORY);
}
pPropertyCache->_pCoreADsObject = pCoreADsObject;
pPropertyCache->_pSchemaClassProps = pSchemaClassProps;
pPropertyCache->_dwNumProperties = dwNumProperties;
*ppPropertyCache = pPropertyCache;
RRETURN(S_OK);
}
//+------------------------------------------------------------------------
//
// Function:
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
unmarshallproperty(
LPWSTR szPropertyName,
LPBYTE lpValue,
DWORD dwNumValues,
DWORD dwSyntaxId,
BOOL fExplicit
)
{
DWORD dwIndex = 0;
HRESULT hr = S_OK;
PNTOBJECT pNTObject = NULL;
hr = UnMarshallNTToNTSynId(
dwSyntaxId,
dwNumValues,
lpValue,
&pNTObject
);
BAIL_ON_FAILURE(hr);
//
// Find this property in the cache
//
hr = findproperty(
szPropertyName,
&dwIndex
);
//
// If this property does not exist in the
// cache, add this property into the cache.
//
if (FAILED(hr)) {
hr = addproperty(
szPropertyName,
dwSyntaxId,
dwNumValues,
pNTObject
);
//
// If the operation fails for some reason
// move on to the next property
//
BAIL_ON_FAILURE(hr);
}
//
// Now update the property in the cache
//
hr = updateproperty(
szPropertyName,
dwSyntaxId,
dwNumValues,
pNTObject,
fExplicit
);
BAIL_ON_FAILURE(hr);
error:
if (pNTObject) {
NTTypeFreeNTObjects(
pNTObject,
dwNumValues
);
}
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
ValidatePropertyinSchemaClass(
PPROPERTYINFO pSchemaClassProps,
DWORD dwNumProperties,
LPWSTR pszPropName,
PDWORD pdwSyntaxId
)
{
DWORD i = 0;
PPROPERTYINFO pThisSchProperty = NULL;
for (i = 0; i < dwNumProperties; i++) {
pThisSchProperty = (pSchemaClassProps + i);
if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
*pdwSyntaxId = pThisSchProperty->dwSyntaxId;
RRETURN (S_OK);
}
}
RRETURN(E_ADS_SCHEMA_VIOLATION);
}
HRESULT
ValidateIfWriteableProperty(
PPROPERTYINFO pSchemaClassProps,
DWORD dwNumProperties,
LPWSTR pszPropName
)
{
DWORD i = 0;
PPROPERTYINFO pThisSchProperty = NULL;
for (i = 0; i < dwNumProperties; i++) {
pThisSchProperty = (pSchemaClassProps + i);
if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
RRETURN((pThisSchProperty->dwFlags & PROPERTY_WRITEABLE)
? S_OK : E_ADS_SCHEMA_VIOLATION);
}
}
RRETURN(E_ADS_SCHEMA_VIOLATION);
// for winnt & nw312, return E_ADS_SCHEMA_VIOLATION if not ok even
// if just try to write to cache only
}
HRESULT
GetPropertyInfoLevel(
LPWSTR pszPropName,
PPROPERTYINFO pSchemaClassProps,
DWORD dwNumProperties,
PDWORD pdwInfoLevel
)
{
DWORD i = 0;
PPROPERTYINFO pThisSchProperty = NULL;
for (i = 0; i < dwNumProperties; i++) {
pThisSchProperty = (pSchemaClassProps + i);
if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
*pdwInfoLevel = pThisSchProperty->dwInfoLevel;
RRETURN(S_OK);
}
}
//
// Returning E_ADS_PROPERTY_NOT_FOUND so that implicit
// GetInfo fails gracefully
//
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
//+------------------------------------------------------------------------
//
// Function: ~CPropertyCache
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
void
CPropertyCache::
flushpropcache()
{
DWORD i = 0;
PPROPERTY pThisProperty = NULL;
if (_pProperties) {
for (i = 0; i < _dwMaxProperties; i++) {
pThisProperty = _pProperties + i;
if (pThisProperty->szPropertyName) {
FreeADsStr(pThisProperty->szPropertyName);
pThisProperty->szPropertyName = NULL;
}
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
}
FreeADsMem(_pProperties);
}
//
// Reset the property cache
//
_pProperties = NULL;
_dwMaxProperties = 0;
_cb = 0;
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::getproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] -- Property to retrieve from the cache
// [pvaData] -- Data returned in a variant
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
unboundgetproperty(
LPWSTR szPropertyName,
PDWORD pdwSyntaxId,
PDWORD pdwNumValues,
PNTOBJECT * ppNtObject
)
{
HRESULT hr;
DWORD dwIndex = 0L;
PPROPERTY pThisProperty = NULL;
hr = findproperty(
szPropertyName,
&dwIndex
);
BAIL_ON_FAILURE(hr);
pThisProperty = _pProperties + dwIndex;
if (PROPERTY_NTOBJECT(pThisProperty)) {
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
*pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
hr = NtTypeCopyConstruct(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty),
ppNtObject
);
BAIL_ON_FAILURE(hr);
}else {
*ppNtObject = NULL;
*pdwNumValues = 0;
*pdwSyntaxId = 0;
hr = E_FAIL;
}
error:
RRETURN_EXP_IF_ERR(hr);
}
//+------------------------------------------------------------------------
//
// Function: CPropertyCache::getproperty
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] -- Property to retrieve from the cache
// [pvaData] -- Data returned in a variant
//
//-------------------------------------------------------------------------
HRESULT
CPropertyCache::
unboundgetproperty(
DWORD dwIndex,
PDWORD pdwSyntaxId,
PDWORD pdwNumValues,
PNTOBJECT * ppNtObject
)
{
HRESULT hr;
PPROPERTY pThisProperty = NULL;
if (!index_valid(dwIndex)) {
RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_FOUND);
}
pThisProperty = _pProperties + dwIndex;
if (PROPERTY_NTOBJECT(pThisProperty)) {
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
*pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
hr = NtTypeCopyConstruct(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty),
ppNtObject
);
BAIL_ON_FAILURE(hr);
}else {
*ppNtObject = NULL;
*pdwNumValues = 0;
*pdwSyntaxId = 0;
hr = E_FAIL;
}
error:
RRETURN_EXP_IF_ERR(hr);
}
BOOL
CPropertyCache::
index_valid(
)
{
//
// need to check _dwMaxProperties==0 separately since a negative
// DWORD is equal to +ve large #
//
if (_dwMaxProperties==0 || (_dwCurrentIndex>_dwMaxProperties-1) )
return(FALSE);
else
return(TRUE);
}
BOOL
CPropertyCache::
index_valid(
DWORD dwIndex
)
{
//
// need to check _dwMaxProperties==0 separately since a negative
// DWORD is equal to +ve large #
//
if (_dwMaxProperties==0 || (dwIndex>_dwMaxProperties-1) )
return(FALSE);
else
return(TRUE);
}
void
CPropertyCache::
reset_propindex(
)
{
_dwCurrentIndex = 0;
}
HRESULT
CPropertyCache::
skip_propindex(
DWORD dwElements
)
{
DWORD newIndex = _dwCurrentIndex + dwElements;
if (!index_valid())
RRETURN_EXP_IF_ERR(E_FAIL);
//
// - allow current index to go from within range to out of range by 1
// - by 1 since initial state is out of range by 1
//
if (newIndex>_dwMaxProperties) {
RRETURN_EXP_IF_ERR(E_FAIL);
}
_dwCurrentIndex = newIndex;
RRETURN(S_OK);
}
HRESULT
CPropertyCache::
get_PropertyCount(
PDWORD pdwMaxProperties
)
{
*pdwMaxProperties = _dwMaxProperties;
RRETURN(S_OK);
}
DWORD
CPropertyCache::
get_CurrentIndex(
)
{
return(_dwCurrentIndex);
}
LPWSTR
CPropertyCache::
get_CurrentPropName(
)
{
PPROPERTY pThisProperty = NULL;
if (!_dwMaxProperties) // if !_dwMaxProperties, pThisProperty=NULL, AV
return NULL; // in PROPERTY_NAME(pThisProperty)
if (!index_valid())
return(NULL);
pThisProperty = _pProperties + _dwCurrentIndex;
return(PROPERTY_NAME(pThisProperty));
}
LPWSTR
CPropertyCache::
get_PropName(
DWORD dwIndex
)
{
PPROPERTY pThisProperty = NULL;
if (!index_valid(dwIndex))
return(NULL);
pThisProperty = _pProperties + dwIndex;
return(PROPERTY_NAME(pThisProperty));
}
HRESULT
CPropertyCache::
deleteproperty(
DWORD dwIndex
)
{
HRESULT hr = S_OK;
PPROPERTY pNewProperties = NULL;
PPROPERTY pThisProperty = _pProperties + dwIndex;
if (!index_valid(dwIndex)) {
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
if (_dwMaxProperties == 1) {
//
// Deleting everything
//
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
FreeADsMem(_pProperties);
_pProperties = NULL;
_dwMaxProperties = 0;
_cb = 0;
//
// Reset the current index just in case
//
_dwCurrentIndex = 0;
RRETURN(hr);
}
pNewProperties = (PPROPERTY)AllocADsMem(
_cb - sizeof(PROPERTY)
);
if (!pNewProperties) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
//
// Copying the memory before the deleted item
//
if (dwIndex != 0) {
memcpy( pNewProperties,
_pProperties,
dwIndex * sizeof(PROPERTY));
}
//
// Copying the memory following the deleted item
//
if (dwIndex != (_dwMaxProperties-1)) {
memcpy( pNewProperties + dwIndex,
_pProperties + dwIndex + 1,
(_dwMaxProperties - dwIndex - 1) * sizeof(PROPERTY));
}
if (PROPERTY_NTOBJECT(pThisProperty)) {
NTTypeFreeNTObjects(
PROPERTY_NTOBJECT(pThisProperty),
PROPERTY_NUMVALUES(pThisProperty)
);
PROPERTY_NTOBJECT(pThisProperty) = NULL;
}
FreeADsMem(_pProperties);
_pProperties = pNewProperties;
_dwMaxProperties--;
_cb -= sizeof(PROPERTY);
//
// Reset the current index if necesary so we do not skip a property.
//
if (_dwCurrentIndex > dwIndex) {
_dwCurrentIndex--;
}
error:
RRETURN_EXP_IF_ERR(hr);
}
////////////////////////////////////////////////////////////////////////
//
// IPropertyCache
//
HRESULT
CPropertyCache::
locateproperty(
LPWSTR szPropertyName,
PDWORD pdwDispid
)
{
HRESULT hr;
hr = DispatchLocateProperty(
szPropertyName,
pdwDispid
);
RRETURN(hr);
}
HRESULT
CPropertyCache::
putproperty(
DWORD dwDispid,
VARIANT varValue
)
{
HRESULT hr;
hr = DispatchPutProperty(
dwDispid,
varValue
);
RRETURN(hr);
}
HRESULT
CPropertyCache::
getproperty(
DWORD dwDispid,
VARIANT * pvarValue
)
{
HRESULT hr;
hr = DispatchGetProperty(
dwDispid,
pvarValue
);
RRETURN(hr);
}
////////////////////////////////////////////////////////////////////////
//
// Dynamic Dispid Table
//
HRESULT
CPropertyCache::
DispatchFindProperty(
LPWSTR szPropertyName,
PDWORD pdwDispid
)
{
DWORD i = 0;
PDISPPROPERTY pDispProp = NULL;
//
// use ADs Error codes since this funct'n does not go directly into
// the dispatch interface
//
if (!pdwDispid || !szPropertyName)
RRETURN(E_ADS_BAD_PARAMETER);
for (i=0; i<_dwDispMaxProperties; i++) {
pDispProp = _pDispProperties + i;
if (!_wcsicmp(DISPATCH_NAME(pDispProp), szPropertyName)) {
*pdwDispid=i;
RRETURN(S_OK);
}
}
*pdwDispid = (DWORD) -1;
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
}
HRESULT
CPropertyCache::
DispatchAddProperty(
LPWSTR szPropertyName,
PDWORD pdwDispid /* optional */
)
{
HRESULT hr = E_FAIL;
DWORD dwDispid = (DWORD) -1;
PDISPPROPERTY pNewDispProps = NULL;
LPWSTR pszTempName = NULL;
//
// use ADs Error codes since this funct'n does not go directly into
// the dispatch interface
//
if (!szPropertyName)
RRETURN(E_ADS_BAD_PARAMETER);
hr = DispatchFindProperty(
szPropertyName,
&dwDispid
);
if (hr==E_ADS_PROPERTY_NOT_FOUND) {
pszTempName = AllocADsStr(szPropertyName);
if (!pszTempName)
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
//
// increase the size of Dynamic Dispid Table by 1 property
//
pNewDispProps = (PDISPPROPERTY) ReallocADsMem(
_pDispProperties,
_cbDisp,
_cbDisp + sizeof(DISPPROPERTY)
);
if (!pNewDispProps)
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
//
// must succeeded at this pt. okay to change table & indexes
//
_pDispProperties = pNewDispProps;
DISPATCH_NAME(_pDispProperties+_dwDispMaxProperties) = pszTempName;
dwDispid = _dwDispMaxProperties++;
_cbDisp += sizeof(DISPPROPERTY);
hr = S_OK;
}
//
// return valid, or invalid (-1) in case of failure, dispid of
// szProperty iff asked for
//
if (pdwDispid)
*pdwDispid = dwDispid;
RRETURN(hr);
error:
if (pszTempName)
FreeADsStr(pszTempName);
RRETURN(hr);
}
HRESULT
CPropertyCache::
DispatchLocateProperty(
LPWSTR szPropertyName,
PDWORD pdwDispid
)
{
HRESULT hr;
DWORD dwSyntaxId; // (dummy)
//
// - pdwDispid not optional here
// - Use DISP_E_ERROR codes since this function directly called by
// the dispatch manager
//
if (!pdwDispid || !szPropertyName)
RRETURN(DISP_E_PARAMNOTOPTIONAL);
//
// return dispid of property if already in table;
//
hr = DispatchFindProperty(
szPropertyName,
pdwDispid
);
if (hr==E_ADS_PROPERTY_NOT_FOUND) {
//
// check if property in schema
// - this is necessary; otherwise, property not in schema will
// be allowed to be added to cache and will not be given the
// chance to be handled by 3rd party extension.
// - note that property not in schema but added to the cache
// thru' IADsProperty list will not be handled by 3rd
// party extension either.
//
hr = ValidatePropertyinSchemaClass(
_pSchemaClassProps,
_dwNumProperties,
szPropertyName,
&dwSyntaxId
);
//
// Add property that is in the schema but not in the cache to
// the dynamic dispid table. That is, property which is in the
// schema will always be handled by the cache/server thur ADSI but
// will NOT be handled by 3rd party extension.
//
if (SUCCEEDED(hr)) {
hr = DispatchAddProperty(
szPropertyName,
pdwDispid
);
BAIL_ON_FAILURE(hr);
}
//
// Property Not in the schema will nto be added to the dynamic
// dispid table and could be handled by 3rd party extension.
//
else {
hr = DISP_E_MEMBERNOTFOUND;
BAIL_ON_FAILURE(hr);
}
}
RRETURN(hr);
error:
//
// translate E_ADS_ error codes to DISP_E if appropriate, see above
//
ADsECodesToDispECodes(&hr);
*pdwDispid = (DWORD) DISPID_UNKNOWN;
RRETURN(hr);
}
HRESULT
CPropertyCache::
DispatchGetProperty(
DWORD dwDispid,
VARIANT * pvarVal
)
{
HRESULT hr;
LPWSTR szPropName = NULL;
DWORD dwSyntaxId = (DWORD) -1;
DWORD dwNumValues = 0;
PNTOBJECT pNtObjs = NULL;
//
// Use DISP_E_ERROR codes since this function directly called by
// the dispatch manager
//
if (!pvarVal)
RRETURN(DISP_E_PARAMNOTOPTIONAL);
if (!DISPATCH_INDEX_VALID(dwDispid))
RRETURN(DISP_E_MEMBERNOTFOUND);
szPropName = DISPATCH_PROPERTY_NAME(dwDispid);
//
// return value in cache for szPropName; retrieve value from server
// if not already in cache; fail if none on sever
//
hr = getproperty(
szPropName,
&dwSyntaxId,
&dwNumValues,
&pNtObjs
);
BAIL_ON_FAILURE(hr);
//
// translate NT objects into variants
//
if (dwNumValues == 1) {
hr = NtTypeToVarTypeCopy(
pNtObjs,
pvarVal
);
} else {
hr = NtTypeToVarTypeCopyConstruct(
pNtObjs,
dwNumValues,
pvarVal
);
}
BAIL_ON_FAILURE(hr);
error:
if (pNtObjs) {
NTTypeFreeNTObjects(
pNtObjs,
dwNumValues
);
}
if (FAILED(hr)) {
//
// return DISP_E errors instead E_ADS_ errors , see above
//
ADsECodesToDispECodes(&hr);
V_VT(pvarVal) = VT_ERROR;
}
RRETURN(hr);
}
HRESULT
CPropertyCache::
DispatchPutProperty(
DWORD dwDispid,
VARIANT& varVal
)
{
HRESULT hr;
LPWSTR szPropName = NULL;
VARIANT * pvProp = NULL; // do not free
DWORD dwNumValues = 0;
VARIANT * pTempVarArray = NULL; // to be freed
DWORD dwSyntaxId = (DWORD) -1;
LPNTOBJECT pNtObjs = NULL;
DWORD dwIndex = (DWORD) -1;
//
// Use DISP_E_ERROR codes since this function directly called by
// the dispatch manager
//
if (!DISPATCH_INDEX_VALID(dwDispid))
RRETURN(DISP_E_MEMBERNOTFOUND);
//
// retreive property name from Dynamic Dispatch Table
//
szPropName = DISPATCH_PROPERTY_NAME(dwDispid);
//
// translate variant to NT Objects
//
//
// A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
// We should dereference a VT_BYREF|VT_VARIANT once and see
// what's inside. ??
//
pvProp = &varVal;
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
pvProp = V_VARIANTREF(pvProp);
}
if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
(V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
hr = ConvertByRefSafeArrayToVariantArray(
varVal,
&pTempVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
if(NULL == pTempVarArray) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
pvProp = pTempVarArray;
}else {
//
// Single value NOT stored in array MUST BE ALLOWED since clients
// would expect Put() to behave the same whether the dipatch
// manager is invoked or not. (This funct'n has to be consitent
// GenericPutPropertyManager(), but NOT GenericPutExProperty...)
dwNumValues = 1;
}
//
// Need the syntax of this property on the cache.
//
hr = ValidatePropertyinSchemaClass(
_pSchemaClassProps,
_dwNumProperties,
szPropName,
&dwSyntaxId
);
BAIL_ON_FAILURE(hr);
//
// check if this is a writeable property in schema
//
hr = ValidateIfWriteableProperty(
_pSchemaClassProps,
_dwNumProperties,
szPropName
);
BAIL_ON_FAILURE(hr);
//
// Variant Array to Nt Objects
//
hr = VarTypeToNtTypeCopyConstruct(
dwSyntaxId,
pvProp,
dwNumValues,
&pNtObjs
);
BAIL_ON_FAILURE(hr);
//
// add the property to cache if not already in since DispatchAddProperty
// does not addproperty
//
hr = findproperty(
szPropName,
&dwIndex
);
if (FAILED(hr)) {
hr = addproperty(
szPropName,
dwSyntaxId,
dwNumValues,
pNtObjs
);
BAIL_ON_FAILURE(hr);
}
//
// update property value in cache
//
hr = putproperty(
szPropName,
dwSyntaxId,
dwNumValues,
pNtObjs
);
BAIL_ON_FAILURE(hr);
error:
if (pNtObjs) {
NTTypeFreeNTObjects(
pNtObjs,
dwNumValues
);
}
if (pTempVarArray) {
DWORD i = 0;
for (i = 0; i < dwNumValues; i++) {
VariantClear(pTempVarArray + i);
}
FreeADsMem(pTempVarArray);
}
if (FAILED(hr)) {
//
// return DISP_E errors instead E_ADS_ errors , see above
//
ADsECodesToDispECodes(&hr);
}
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: GetPropNames
//
// Synopsis: Returns the names of all properties in the cache.
//
// Arguments:
//
// pProps Returns the names of the properties, without any data
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pProps to return the property names
//
//----------------------------------------------------------------------------
HRESULT CPropertyCache::GetPropNames(
UMI_PROPERTY_VALUES **pProps
)
{
UMI_PROPERTY_VALUES *pUmiPropVals = NULL;
UMI_PROPERTY *pUmiProps = NULL;
HRESULT hr = UMI_S_NO_ERROR;
ULONG ulIndex = 0;
PPROPERTY pNextProperty = NULL;
ADsAssert(pProps != NULL);
pUmiPropVals = (UMI_PROPERTY_VALUES *) AllocADsMem(
sizeof(UMI_PROPERTY_VALUES));
if(NULL == pUmiPropVals)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
memset(pUmiPropVals, 0, sizeof(UMI_PROPERTY_VALUES));
if(0 == _dwMaxProperties) {
// no properties in cache
*pProps = pUmiPropVals;
RRETURN(UMI_S_NO_ERROR);
}
pUmiProps = (UMI_PROPERTY *) AllocADsMem(
_dwMaxProperties * sizeof(UMI_PROPERTY));
if(NULL == pUmiProps)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
memset(pUmiProps, 0, _dwMaxProperties * sizeof(UMI_PROPERTY));
for(ulIndex = 0; ulIndex < _dwMaxProperties; ulIndex++) {
pNextProperty = _pProperties + ulIndex;
pUmiProps[ulIndex].pszPropertyName =
(LPWSTR) AllocADsStr(pNextProperty->szPropertyName);
if(NULL == pUmiProps[ulIndex].pszPropertyName)
BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
}
pUmiPropVals->uCount = _dwMaxProperties;
pUmiPropVals->pPropArray = pUmiProps;
*pProps = pUmiPropVals;
RRETURN(UMI_S_NO_ERROR);
error:
if(pUmiProps != NULL) {
for(ulIndex = 0; ulIndex < _dwMaxProperties; ulIndex++)
if(pUmiProps[ulIndex].pszPropertyName != NULL)
FreeADsStr(pUmiProps[ulIndex].pszPropertyName);
FreeADsMem(pUmiProps);
}
if(pUmiPropVals != NULL)
FreeADsMem(pUmiPropVals);
RRETURN(hr);
}
//----------------------------------------------------------------------------
// Function: ClearModifiedFlag
//
// Synopsis: Clears the modified flag for all properties in the cache. This
// is done after a successful SetInfo so that subsequent Get
// operations return the correct state of the property.
//
// Arguments:
//
// None
//
// Returns: Nothing
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
void
CPropertyCache::ClearModifiedFlags(void)
{
DWORD i = 0;
PPROPERTY pThisProperty = NULL;
for (i = 0; i < _dwMaxProperties; i++) {
pThisProperty = _pProperties + i;
if (PROPERTY_NTOBJECT(pThisProperty))
PROPERTY_FLAGS(pThisProperty) &= ~CACHE_PROPERTY_MODIFIED;
}
}
//
// Move This function out of this file, out of adsnt in fact. LATER
// Moving it out may make the conversion more difficult since each
// provider return error codes in its own way. May be local is better.
//
void
ADsECodesToDispECodes(
HRESULT *pHr
)
{
DWORD dwADsErr = *pHr;
switch (dwADsErr) {
case E_ADS_UNKNOWN_OBJECT:
case E_ADS_PROPERTY_NOT_SUPPORTED:
case E_ADS_PROPERTY_INVALID:
case E_ADS_PROPERTY_NOT_FOUND:
*pHr = DISP_E_MEMBERNOTFOUND;
break;
case E_ADS_BAD_PARAMETER:
//*pHr = DISP_E_PARAMNOTOPTIONAL;
break;
case E_ADS_CANT_CONVERT_DATATYPE:
*pHr = DISP_E_TYPEMISMATCH;
//*pHr = DISP_E_BADVARTYPE;
break;
case E_ADS_SCHEMA_VIOLATION:
// depends
break;
default:
break;
// should make it s.t. E_ADS_xxx -> E_FAIL and no changes on others
// LATER
};
}