1581 lines
33 KiB
C++
1581 lines
33 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: cprops.cxx
|
|
//
|
|
// Contents: Property Cache functionality for IIS
|
|
//
|
|
// Functions:
|
|
// CPropertyCache::addproperty
|
|
// CPropertyCache::updateproperty
|
|
// CPropertyCache::findproperty
|
|
// CPropertyCache::getproperty
|
|
// CPropertyCache::putproperty
|
|
// CProperyCache::CPropertyCache
|
|
// CPropertyCache::~CPropertyCache
|
|
// CPropertyCache::createpropertycache
|
|
//
|
|
// History: 17-June-1997 sophiac Created.
|
|
// cloned off NT property cache code
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "iis.hxx"
|
|
#pragma hdrstop
|
|
|
|
#if DBG
|
|
DECLARE_INFOLEVEL(IISMarshall);
|
|
DECLARE_DEBUG(IISMarshall);
|
|
#define IISMarshallDebugOut(x) IISMarshallInlineDebugOut x
|
|
#endif
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::addproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [vt] --
|
|
// [vaData] --
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
addproperty(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwSyntaxId,
|
|
DWORD dwNumValues,
|
|
PIISOBJECT pIISObject
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PPROPERTY pNewProperty = NULL;
|
|
|
|
//
|
|
// 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);
|
|
|
|
wcscpy(pNewProperty->szPropertyName, szPropertyName);
|
|
|
|
//
|
|
// Update the index
|
|
//
|
|
|
|
_dwMaxProperties++;
|
|
_cb += sizeof(PROPERTY);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::updateproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [vaData] --
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::updateproperty(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwSyntaxId,
|
|
DWORD dwNumValues,
|
|
PIISOBJECT pIISObject,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex;
|
|
DWORD dwMetaId;
|
|
PIISOBJECT pIISTempObject = NULL;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
if (!fExplicit) {
|
|
if ((PROPERTY_FLAGS(pThisProperty) == CACHE_PROPERTY_MODIFIED) ||
|
|
(PROPERTY_FLAGS(pThisProperty) == CACHE_PROPERTY_CLEARED)) {
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Factor in cases where object state is necessary to
|
|
// decide on update.
|
|
//
|
|
|
|
if (PROPERTY_IISOBJECT(pThisProperty)) {
|
|
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
|
|
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
|
|
PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
|
|
_pSchema->ConvertPropName_To_ID(szPropertyName, &dwMetaId);
|
|
|
|
PROPERTY_METAID(pThisProperty) = dwMetaId;
|
|
|
|
hr = IISTypeCopyConstruct(
|
|
pIISObject,
|
|
dwNumValues,
|
|
&pIISTempObject
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
PROPERTY_IISOBJECT(pThisProperty) = pIISTempObject;
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = CACHE_PROPERTY_INITIALIZED;
|
|
|
|
error:
|
|
|
|
RRETURN(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,
|
|
PIISOBJECT * ppIISObject
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex = 0L;
|
|
PPROPERTY pThisProperty = NULL;
|
|
DWORD dwResult;
|
|
DWORD dwInfoLevel = 0;
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
if (hr == E_ADS_PROPERTY_NOT_FOUND) {
|
|
|
|
//
|
|
// Now call the GetInfo function
|
|
//
|
|
|
|
if (!_bPropsLoaded) {
|
|
hr = _pCoreADsObject->GetInfo(FALSE);
|
|
if (FAILED(hr) && hr != E_ADS_OBJECT_UNBOUND) {
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
}
|
|
}
|
|
if (hr == E_ADS_PROPERTY_NOT_FOUND) {
|
|
LPBYTE propvalue;
|
|
DWORD dwSyntax;
|
|
DWORD dwNumValues;
|
|
|
|
hr = _pSchema->GetDefaultProperty(szPropertyName, &dwNumValues,
|
|
&dwSyntax, &propvalue);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = unmarshallproperty(
|
|
szPropertyName,
|
|
propvalue,
|
|
dwNumValues,
|
|
dwSyntax,
|
|
0
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = findproperty (szPropertyName,
|
|
&dwIndex
|
|
);
|
|
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
if (PROPERTY_IISOBJECT(pThisProperty)) {
|
|
|
|
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
|
|
*pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
|
|
|
|
hr = IISTypeCopyConstruct(PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty),
|
|
ppIISObject );
|
|
BAIL_ON_FAILURE(hr);
|
|
}else {
|
|
|
|
*ppIISObject = NULL;
|
|
*pdwNumValues = 0;
|
|
*pdwSyntaxId = 0;
|
|
hr = E_ADS_PROPERTY_NOT_SET;
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::putproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] -- Clsid index
|
|
// [vaData] -- Matching clsid returned in *pclsid
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CPropertyCache::putproperty(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwFlags,
|
|
DWORD dwSyntaxId,
|
|
DWORD dwNumValues,
|
|
PIISOBJECT pIISObject
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex = 0L;
|
|
DWORD dwMetaId = 0;
|
|
PIISOBJECT pIISTempObject = NULL;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
if (PROPERTY_IISOBJECT(pThisProperty)) {
|
|
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
|
|
_pSchema->ConvertPropName_To_ID(szPropertyName, &dwMetaId);
|
|
|
|
switch (dwFlags) {
|
|
|
|
case CACHE_PROPERTY_MODIFIED:
|
|
|
|
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
|
|
|
|
PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
|
|
|
|
PROPERTY_METAID(pThisProperty) = dwMetaId;
|
|
|
|
hr = IISTypeCopyConstruct(
|
|
pIISObject,
|
|
dwNumValues,
|
|
&pIISTempObject
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
PROPERTY_IISOBJECT(pThisProperty) = pIISTempObject;
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = CACHE_PROPERTY_MODIFIED;
|
|
break;
|
|
|
|
case CACHE_PROPERTY_CLEARED:
|
|
|
|
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
|
|
|
|
PROPERTY_NUMVALUES(pThisProperty) = 0;
|
|
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = CACHE_PROPERTY_CLEARED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
error:
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
CPropertyCache::CPropertyCache():
|
|
_pCoreADsObject(NULL),
|
|
_pSchema(NULL),
|
|
_bPropsLoaded(FALSE),
|
|
_dwMaxProperties(0),
|
|
_dwCurrentIndex(0),
|
|
_pProperties(NULL),
|
|
_cb(0),
|
|
_pDispProperties(NULL),
|
|
_dwDispMaxProperties(0),
|
|
_cbDisp(0),
|
|
_bstrServerName(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// 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 (PROPERTY_IISOBJECT(pThisProperty)) {
|
|
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
}
|
|
|
|
FreeADsMem(_pProperties);
|
|
}
|
|
|
|
|
|
//
|
|
// Free Dynamic Dispid Table
|
|
//
|
|
|
|
if (_pDispProperties) {
|
|
|
|
FreeADsMem(_pDispProperties);
|
|
}
|
|
|
|
if( _bstrServerName )
|
|
{
|
|
ADsFreeString( _bstrServerName );
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::createpropertycache(
|
|
CCoreADsObject FAR * pCoreADsObject,
|
|
CPropertyCache FAR *FAR * ppPropertyCache
|
|
)
|
|
{
|
|
CPropertyCache FAR * pPropertyCache = NULL;
|
|
BSTR serverName=NULL;
|
|
HRESULT hr;
|
|
|
|
hr = pCoreADsObject->get_CoreName(&serverName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pPropertyCache = new CPropertyCache();
|
|
|
|
if (!pPropertyCache) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
pPropertyCache->_pCoreADsObject = pCoreADsObject;
|
|
|
|
*ppPropertyCache = pPropertyCache;
|
|
RRETURN(S_OK);
|
|
|
|
error :
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
unmarshallproperty(
|
|
LPWSTR szPropertyName,
|
|
LPBYTE lpValue,
|
|
DWORD dwNumValues,
|
|
DWORD dwSyntaxId,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
DWORD dwIndex = 0;
|
|
HRESULT hr = S_OK;
|
|
PIISOBJECT pIISObject = NULL;
|
|
|
|
hr = UnMarshallIISToIISSynId(
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
lpValue,
|
|
&pIISObject
|
|
);
|
|
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,
|
|
pIISObject
|
|
);
|
|
|
|
//
|
|
// 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,
|
|
pIISObject,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pIISObject) {
|
|
IISTypeFreeIISObjects(
|
|
pIISObject,
|
|
dwNumValues
|
|
);
|
|
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
IISUnMarshallProperties(
|
|
LPBYTE pBase,
|
|
LPBYTE pBuffer,
|
|
DWORD dwMDNumDataEntries,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PMETADATA_GETALL_RECORD pmdgarData = NULL, pTemp = NULL;
|
|
DWORD i = 0;
|
|
WCHAR szPropertyName[MAX_PATH];
|
|
DWORD dwSyntaxID;
|
|
DWORD dwNumValues;
|
|
|
|
ZeroMemory(szPropertyName, MAX_PATH);
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
_bPropsLoaded = TRUE;
|
|
pmdgarData = (PMETADATA_GETALL_RECORD)pBuffer;
|
|
|
|
for (i = 0; i < dwMDNumDataEntries; i++) {
|
|
|
|
//
|
|
// unmarshall this property into the
|
|
// property cache
|
|
//
|
|
|
|
pTemp = pmdgarData + i;
|
|
|
|
hr = _pSchema->ConvertID_To_PropName(pTemp->dwMDIdentifier,
|
|
szPropertyName);
|
|
|
|
CONTINUE_ON_FAILURE(hr);
|
|
|
|
hr = _pSchema->LookupSyntaxID(szPropertyName, &dwSyntaxID);
|
|
|
|
CONTINUE_ON_FAILURE(hr);
|
|
|
|
//
|
|
// find out number of strings within the multi-sz string
|
|
//
|
|
|
|
if (pTemp->dwMDDataType == MULTISZ_METADATA) {
|
|
LPWSTR pszStr = (LPWSTR) (pBase + pTemp->dwMDDataOffset);
|
|
|
|
if (*pszStr == 0) {
|
|
dwNumValues = 1;
|
|
}
|
|
else {
|
|
dwNumValues = 0;
|
|
}
|
|
|
|
while (*pszStr != L'\0') {
|
|
while (*pszStr != L'\0') {
|
|
pszStr++;
|
|
}
|
|
dwNumValues++;
|
|
pszStr++;
|
|
}
|
|
}
|
|
else if (pTemp->dwMDDataType == BINARY_METADATA) {
|
|
|
|
//
|
|
// if DataType == BINARY, pass the length to dwNumValues
|
|
//
|
|
|
|
dwNumValues = pTemp->dwMDDataLen;
|
|
}
|
|
else {
|
|
dwNumValues = 1;
|
|
}
|
|
|
|
hr = unmarshallproperty(
|
|
szPropertyName,
|
|
pBase + pTemp->dwMDDataOffset,
|
|
dwNumValues,
|
|
dwSyntaxID,
|
|
fExplicit
|
|
);
|
|
|
|
CONTINUE_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
IISMarshallProperties(
|
|
PMETADATA_RECORD * ppMetaDataRecords,
|
|
PDWORD pdwMDNumDataEntries
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
PPROPERTY pThisProperty = NULL;
|
|
PMETADATA_RECORD pMetaDataArray = NULL;
|
|
DWORD dwCount = 0;
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pMetaDataArray = (PMETADATA_RECORD) AllocADsMem(
|
|
_dwMaxProperties * sizeof(METADATA_RECORD));
|
|
if (!pMetaDataArray ) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
*ppMetaDataRecords = pMetaDataArray;
|
|
|
|
for (i = 0; i < _dwMaxProperties ; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
//
|
|
// Bypass any property that has not been
|
|
// modified
|
|
//
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) == 0 ||
|
|
PROPERTY_FLAGS(pThisProperty) == CACHE_PROPERTY_CLEARED) {
|
|
continue;
|
|
}
|
|
|
|
hr = MarshallIISSynIdToIIS(
|
|
_pSchema,
|
|
PROPERTY_SYNTAX(pThisProperty),
|
|
PROPERTY_METAID(pThisProperty),
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty),
|
|
pMetaDataArray
|
|
);
|
|
CONTINUE_ON_FAILURE(hr);
|
|
|
|
pMetaDataArray++;
|
|
dwCount++;
|
|
}
|
|
|
|
*pdwMDNumDataEntries = dwCount;
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// 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 (PROPERTY_IISOBJECT(pThisProperty)) {
|
|
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
}
|
|
|
|
FreeADsMem(_pProperties);
|
|
}
|
|
|
|
//
|
|
// Reset the property cache
|
|
//
|
|
|
|
_pProperties = NULL;
|
|
_dwMaxProperties = 0;
|
|
_cb = 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CPropertyCache::
|
|
index_valid(
|
|
)
|
|
{
|
|
//
|
|
// need to check separately since a negative DWORD is equal to +ve large #
|
|
//
|
|
if (_dwMaxProperties==0)
|
|
return(FALSE);
|
|
|
|
if (_dwCurrentIndex > _dwMaxProperties - 1)
|
|
return(FALSE);
|
|
else
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CPropertyCache::
|
|
index_valid(
|
|
DWORD dwIndex
|
|
)
|
|
{
|
|
//
|
|
// need to check separately since a negative DWORD is equal to +ve large #
|
|
//
|
|
if (_dwMaxProperties==0)
|
|
return(FALSE);
|
|
|
|
if (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(E_ADS_BAD_PARAMETER);
|
|
|
|
if (newIndex > _dwMaxProperties) {
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
}
|
|
|
|
_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(PROPERTY_NAME(pThisProperty));
|
|
|
|
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_IISOBJECT(pThisProperty)) {
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
|
|
FreeADsMem(_pProperties);
|
|
_pProperties = NULL;
|
|
_dwMaxProperties = 0;
|
|
_cb = 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_IISOBJECT(pThisProperty)) {
|
|
IISTypeFreeIISObjects(
|
|
PROPERTY_IISOBJECT(pThisProperty),
|
|
PROPERTY_NUMVALUES(pThisProperty)
|
|
);
|
|
PROPERTY_IISOBJECT(pThisProperty) = NULL;
|
|
}
|
|
FreeADsMem(_pProperties);
|
|
_pProperties = pNewProperties;
|
|
_dwMaxProperties--;
|
|
_cb -= sizeof(PROPERTY);
|
|
error:
|
|
|
|
RRETURN(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 = -1;
|
|
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
DispatchAddProperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwDispid /* optional */
|
|
)
|
|
{
|
|
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwDispid = -1;
|
|
PDISPPROPERTY pNewDispProps = 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) {
|
|
|
|
//
|
|
// 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;
|
|
wcscpy((_pDispProperties+_dwDispMaxProperties)->szPropertyName,
|
|
szPropertyName);
|
|
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;
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
DispatchLocateProperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwDispid
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwSyntaxId; // (dummy)
|
|
BSTR bstrClassName = NULL;
|
|
|
|
//
|
|
// - 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);
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// 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 = _pCoreADsObject->get_CoreADsClass(&bstrClassName);
|
|
BAIL_ON_FAILURE(hr);
|
|
hr = _pSchema->ValidateProperty(bstrClassName, szPropertyName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// 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);
|
|
|
|
}
|
|
}
|
|
|
|
if (bstrClassName) {
|
|
ADsFreeString(bstrClassName);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
if (bstrClassName) {
|
|
ADsFreeString(bstrClassName);
|
|
}
|
|
|
|
*pdwDispid = DISPID_UNKNOWN;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
/* INTRINSA suppress=null_pointers, uninitialized */
|
|
HRESULT
|
|
CPropertyCache::
|
|
DispatchGetProperty(
|
|
DWORD dwDispid,
|
|
VARIANT * pvarVal
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR szPropName = NULL;
|
|
DWORD dwSyntaxId = -1;
|
|
DWORD dwSyntax;
|
|
DWORD dwNumValues = 0;
|
|
PIISOBJECT pIISObjs = NULL;
|
|
WCHAR wchName[MAX_PATH];
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// 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);
|
|
|
|
//
|
|
// lookup ADSI IIS syntax Id
|
|
//
|
|
|
|
hr = _pSchema->LookupSyntaxID(szPropName, &dwSyntax);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if property is BITMASK type;
|
|
// if BITMASK type, get corresponding DWORD flag property
|
|
//
|
|
|
|
if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) {
|
|
hr = _pSchema->LookupFlagPropName(szPropName, (LPWSTR)wchName);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// return value in cache for szPropName; retrieve value from server
|
|
// if not already in cache; fail if none on sever
|
|
//
|
|
if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY)
|
|
{
|
|
hr = getproperty(
|
|
wchName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pIISObjs
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hr = getproperty(
|
|
szPropName,
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pIISObjs
|
|
);
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// reset it to its syntax id if BITMASK type
|
|
//
|
|
|
|
pIISObjs->IISType = dwSyntax;
|
|
|
|
//
|
|
// translate IIS objects into variants
|
|
//
|
|
//
|
|
// always return an array for multisz type
|
|
//
|
|
|
|
if (dwNumValues == 1 && dwSyntax != IIS_SYNTAX_ID_MULTISZ &&
|
|
dwSyntax != IIS_SYNTAX_ID_MIMEMAP ) {
|
|
|
|
hr = IISTypeToVarTypeCopy(
|
|
_pSchema,
|
|
szPropName,
|
|
pIISObjs,
|
|
pvarVal,
|
|
FALSE
|
|
);
|
|
|
|
} else {
|
|
|
|
hr = IISTypeToVarTypeCopyConstruct(
|
|
_pSchema,
|
|
szPropName,
|
|
pIISObjs,
|
|
dwNumValues,
|
|
pvarVal,
|
|
FALSE
|
|
);
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pIISObjs) {
|
|
|
|
IISTypeFreeIISObjects(
|
|
pIISObjs,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
V_VT(pvarVal) = VT_ERROR;
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
DispatchPutProperty(
|
|
DWORD dwDispid,
|
|
VARIANT& varVal
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwSyntaxId = -1;
|
|
DWORD dwIndex = -1;
|
|
LPIISOBJECT pIISObjs = NULL;
|
|
DWORD dwNumValues = 0;
|
|
|
|
VARIANT * pVarArray = NULL; // to be freed
|
|
VARIANT * pvProp = NULL; // do not free
|
|
VARIANT vVar;
|
|
WCHAR wchName[MAX_PATH];
|
|
LPWSTR szPropName = NULL;
|
|
|
|
hr = LoadSchema();
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// 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);
|
|
|
|
//
|
|
// lookup its syntax ID
|
|
//
|
|
|
|
hr = _pSchema->LookupSyntaxID(szPropName, &dwSyntaxId);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
|
|
VariantInit(&vVar);
|
|
VariantCopyInd(&vVar, &varVal);
|
|
|
|
if ((V_VT(&vVar) & VT_VARIANT) && V_ISARRAY(&vVar)) {
|
|
hr = ConvertArrayToVariantArray(
|
|
vVar,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
pvProp = pVarArray;
|
|
}
|
|
else {
|
|
|
|
dwNumValues = 1;
|
|
pvProp = &vVar;
|
|
}
|
|
|
|
//
|
|
// Variant Array to IIS Objects
|
|
//
|
|
hr = VarTypeToIISTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
pvProp,
|
|
dwNumValues,
|
|
&pIISObjs,
|
|
FALSE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if property is BITMASK type;
|
|
// if BITMASK type, get corresponding DWORD flag property
|
|
//
|
|
|
|
if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
|
|
DWORD dwMask;
|
|
DWORD dwFlagValue;
|
|
DWORD Temp;
|
|
LPIISOBJECT pIISObject = NULL;
|
|
|
|
hr = _pSchema->LookupBitMask(szPropName, &dwMask);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// get its corresponding DWORD flag value
|
|
//
|
|
|
|
hr = _pSchema->LookupFlagPropName(szPropName, (LPWSTR)wchName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = getproperty(wchName,
|
|
&Temp,
|
|
&Temp,
|
|
&pIISObject);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwFlagValue = pIISObject->IISValue.value_1.dwDWORD;
|
|
|
|
if (pIISObjs->IISValue.value_1.dwDWORD) {
|
|
dwFlagValue |= dwMask;
|
|
}
|
|
else {
|
|
dwFlagValue &= ~dwMask;
|
|
}
|
|
|
|
pIISObjs->IISValue.value_1.dwDWORD = dwFlagValue;
|
|
pIISObjs->IISType = IIS_SYNTAX_ID_DWORD;
|
|
szPropName = wchName;
|
|
|
|
if (pIISObject) {
|
|
IISTypeFreeIISObjects(
|
|
pIISObject,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
|
|
if (dwSyntaxId == IIS_SYNTAX_ID_BINARY) {
|
|
hr = _pSchema->LookupFlagPropName(szPropName, (LPWSTR)wchName);
|
|
BAIL_ON_FAILURE(hr);
|
|
szPropName = wchName;
|
|
}
|
|
|
|
//
|
|
// 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 == IIS_SYNTAX_ID_BOOL_BITMASK ?
|
|
IIS_SYNTAX_ID_DWORD : dwSyntaxId,
|
|
dwNumValues,
|
|
pIISObjs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// update property value in cache
|
|
//
|
|
|
|
hr = putproperty(
|
|
szPropName,
|
|
CACHE_PROPERTY_MODIFIED,
|
|
dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
|
|
IIS_SYNTAX_ID_DWORD : dwSyntaxId,
|
|
dwNumValues,
|
|
pIISObjs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
error:
|
|
|
|
if (pIISObjs) {
|
|
IISTypeFreeIISObjects(
|
|
pIISObjs,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
if (pVarArray) {
|
|
|
|
DWORD i = 0;
|
|
for (i = 0; i < dwNumValues; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
|
|
VariantClear(&vVar);
|
|
|
|
RRETURN(hr);
|
|
}
|