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

2117 lines
42 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: cdomain.cxx
//
// Contents: Microsoft ADs NDS Provider Generic Object
//
//
// History: 01-30-95 krishnag Created.
//
//----------------------------------------------------------------------------
#include "nds.hxx"
#pragma hdrstop
// Class CNDSGenObject
DEFINE_IDispatch_Implementation(CNDSGenObject)
DEFINE_IADs_Implementation(CNDSGenObject)
CNDSGenObject::CNDSGenObject():
_pPropertyCache(NULL)
{
_pOuterUnknown = NULL;
_hADsContext = NULL;
_pszNDSTreeName = _pszNDSDn = NULL;
VariantInit(&_vFilter);
InitSearchPrefs();
ENLIST_TRACKING(CNDSGenObject);
}
HRESULT
CNDSGenObject::CreateGenericObject(
BSTR bstrADsPath,
BSTR ClassName,
CCredentials& Credentials,
DWORD dwObjectState,
REFIID riid,
void **ppvObj
)
{
HRESULT hr = S_OK;
WCHAR szADsParent[MAX_PATH];
WCHAR szCommonName[MAX_PATH];
//
// Determine the parent and rdn name
//
hr = BuildADsParentPath(
bstrADsPath,
szADsParent,
szCommonName
);
//
// call the helper function
//
hr = CNDSGenObject::CreateGenericObject(
szADsParent,
szCommonName,
ClassName,
Credentials,
dwObjectState,
riid,
ppvObj
);
RRETURN(hr);
}
HRESULT
CNDSGenObject::CreateGenericObject(
BSTR Parent,
BSTR CommonName,
BSTR ClassName,
CCredentials& Credentials,
DWORD dwObjectState,
REFIID riid,
void **ppvObj
)
{
CNDSGenObject FAR * pGenObject = NULL;
HRESULT hr = S_OK;
hr = AllocateGenObject(Credentials, &pGenObject);
BAIL_ON_FAILURE(hr);
hr = pGenObject->InitializeCoreObject(
Parent,
CommonName,
ClassName,
L"",
CLSID_NDSGenObject,
dwObjectState
);
BAIL_ON_FAILURE(hr);
hr = BuildNDSPathFromADsPath2(
pGenObject->_ADsPath,
&(pGenObject->_pszNDSTreeName),
&(pGenObject->_pszNDSDn)
);
BAIL_ON_FAILURE(hr);
hr = ADsNdsOpenContext(
pGenObject->_pszNDSTreeName,
Credentials,
&(pGenObject->_hADsContext)
);
BAIL_ON_FAILURE(hr);
hr = pGenObject->QueryInterface(riid, ppvObj);
BAIL_ON_FAILURE(hr);
pGenObject->Release();
RRETURN(hr);
error:
delete pGenObject;
RRETURN(hr);
}
CNDSGenObject::~CNDSGenObject( )
{
VariantClear(&_vFilter);
delete _pDispMgr;
delete _pPropertyCache;
if (_hADsContext) {
ADsNdsCloseContext(_hADsContext);
}
if (_pszNDSTreeName) {
FreeADsMem(_pszNDSTreeName);
}
if (_pszNDSDn) {
FreeADsMem(_pszNDSDn);
}
}
STDMETHODIMP
CNDSGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
{
if (ppv == NULL) {
RRETURN(E_POINTER);
}
if (IsEqualIID(iid, IID_IUnknown))
{
*ppv = (IADs FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsContainer))
{
*ppv = (IADsContainer FAR *) this;
}
else if (IsEqualIID(iid, IID_IADs))
{
*ppv = (IADs FAR *) this;
}
else if (IsEqualIID(iid, IID_IDispatch))
{
*ppv = (IADs FAR *) this;
}
else if (IsEqualIID(iid, IID_IDirectoryObject))
{
*ppv = (IDirectoryObject FAR *) this;
}
else if (IsEqualIID(iid, IID_IDirectorySearch))
{
*ppv = (IDirectorySearch FAR *) this;
}
else if (IsEqualIID(iid, IID_IDirectorySchemaMgmt))
{
*ppv = (IDirectorySchemaMgmt FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsPropertyList))
{
*ppv = (IADsPropertyList FAR *) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
HRESULT
CNDSGenObject::SetInfo()
{
DWORD dwStatus = 0L;
WCHAR szNDSPathName[MAX_PATH];
HANDLE hOperationData = NULL;
HANDLE hObject = NULL;
HRESULT hr = S_OK;
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = NDSCreateObject();
BAIL_ON_FAILURE(hr);
//
// If the create succeded, set the object type to bound
//
SetObjectState(ADS_OBJECT_BOUND);
}else {
hr = NDSSetObject();
BAIL_ON_FAILURE(hr);
}
error:
RRETURN(hr);
}
HRESULT
CNDSGenObject::NDSSetObject()
{
NDS_BUFFER_HANDLE hOperationData = NULL;
HRESULT hr = S_OK;
hr = ADsNdsCreateBuffer(
_hADsContext,
DSV_MODIFY_ENTRY,
&hOperationData
);
BAIL_ON_FAILURE(hr);
hr = _pPropertyCache->NDSMarshallProperties(
_hADsContext,
hOperationData
);
BAIL_ON_FAILURE(hr);
hr = ADsNdsModifyObject(
_hADsContext,
_pszNDSDn,
hOperationData
);
BAIL_ON_FAILURE(hr);
error:
if (hOperationData) {
ADsNdsFreeBuffer(hOperationData);
}
RRETURN(hr);
}
HRESULT
CNDSGenObject::NDSCreateObject()
{
NDS_BUFFER_HANDLE hOperationData = NULL;
HRESULT hr = S_OK;
BOOLEAN fUserObject = FALSE;
BSTR bstrClass = NULL;
hr = ADsNdsCreateBuffer(
_hADsContext,
DSV_ADD_ENTRY,
&hOperationData
);
BAIL_ON_FAILURE(hr);
hr = get_CoreADsClass(&bstrClass);
if (SUCCEEDED(hr)) {
if (_wcsicmp(bstrClass, L"user") == 0) {
fUserObject = TRUE;
}
}
hr = _pPropertyCache->NDSMarshallProperties(
_hADsContext,
hOperationData
);
BAIL_ON_FAILURE(hr);
hr = ADsNdsAddObject(
_hADsContext,
_pszNDSDn,
hOperationData
);
BAIL_ON_FAILURE(hr);
//
// If it is a user object, we'll set the initial password to 'NULL'
//
if (fUserObject) {
hr = ADsNdsGenObjectKey(_hADsContext,
_pszNDSDn);
BAIL_ON_FAILURE(hr);
}
error:
if (bstrClass) {
ADsFreeString(bstrClass);
}
if (hOperationData) {
ADsNdsFreeBuffer(hOperationData);
}
RRETURN(hr);
}
HRESULT
CNDSGenObject::GetInfo()
{
_pPropertyCache->flushpropcache();
RRETURN(GetInfo(TRUE));
}
HRESULT
CNDSGenObject::GetInfo(
BOOL fExplicit
)
{
HRESULT hr = S_OK;
PNDS_ATTR_INFO lpEntries = NULL;
DWORD dwNumEntries = 0, i = 0;
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = E_ADS_OBJECT_UNBOUND;
BAIL_ON_FAILURE(hr);
}
hr = ADsNdsReadObject(
_hADsContext,
_pszNDSDn,
DS_ATTRIBUTE_VALUES,
NULL,
(DWORD) -1, // signifies all attributes need to be returned
NULL,
&lpEntries,
&dwNumEntries
);
BAIL_ON_FAILURE(hr);
for (i = 0; i < dwNumEntries; i++) {
//
// unmarshall this property into the
// property cache
//
//
hr = _pPropertyCache->unmarshallproperty(
lpEntries[i].szAttributeName,
lpEntries[i].lpValue,
lpEntries[i].dwNumberOfValues,
lpEntries[i].dwSyntaxId,
fExplicit
);
CONTINUE_ON_FAILURE(hr);
}
error:
if (_pPropertyCache) {
Reset();
}
FreeNdsAttrInfo( lpEntries, dwNumEntries );
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
{
HRESULT hr = S_OK;
DWORD dwStatus = 0L;
VARIANT *vVarArray = NULL;
DWORD dwNumVariants = 0;
PNDS_ATTR_INFO lpEntries = NULL;
DWORD dwNumEntries = 0, i = 0;
LPWSTR *ppszStrArray = NULL;
UNREFERENCED_PARAMETER(lnReserved);
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = E_ADS_OBJECT_UNBOUND;
BAIL_ON_FAILURE(hr);
}
hr = ConvertSafeArrayToVariantArray(
vProperties,
&vVarArray,
&dwNumVariants
);
BAIL_ON_FAILURE(hr);
hr = ConvertVariantArrayToStringArray(
vVarArray,
&ppszStrArray,
dwNumVariants
);
BAIL_ON_FAILURE(hr);
hr = ADsNdsReadObject(
_hADsContext,
_pszNDSDn,
DS_ATTRIBUTE_VALUES,
ppszStrArray,
dwNumVariants,
NULL,
&lpEntries,
&dwNumEntries
);
BAIL_ON_FAILURE(hr);
for (i = 0; i < dwNumEntries; i++) {
//
// unmarshall this property into the
// property cache
//
// The TRUE is "fExplicit" -- we want to make sure that any
// properties we get back from the server get updated in the
// property cache.
//
hr = _pPropertyCache->unmarshallproperty(
lpEntries[i].szAttributeName,
lpEntries[i].lpValue,
lpEntries[i].dwNumberOfValues,
lpEntries[i].dwSyntaxId,
TRUE
);
CONTINUE_ON_FAILURE(hr);
}
error:
if (ppszStrArray) {
for (DWORD i=0; i < dwNumVariants; i++) {
FreeADsStr(ppszStrArray[i]);
}
FreeADsMem(ppszStrArray);
}
if (vVarArray)
{
DWORD i = 0;
for (i = 0; i < dwNumVariants; i++) {
VariantClear(vVarArray + i);
}
FreeADsMem(vVarArray);
}
FreeNdsAttrInfo( lpEntries, dwNumEntries );
RRETURN(hr);
}
/* IADsContainer methods */
STDMETHODIMP
CNDSGenObject::get_Count(long FAR* retval)
{
RRETURN(E_NOTIMPL);
}
STDMETHODIMP
CNDSGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
{
VariantInit(pVar);
RRETURN(VariantCopy(pVar, &_vFilter));
}
STDMETHODIMP
CNDSGenObject::put_Filter(THIS_ VARIANT Var)
{
VariantClear(&_vFilter);
RRETURN(VariantCopy(&_vFilter, &Var));
}
STDMETHODIMP
CNDSGenObject::put_Hints(THIS_ VARIANT Var)
{
RRETURN( E_NOTIMPL);
}
STDMETHODIMP
CNDSGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
{
RRETURN(E_NOTIMPL);
}
STDMETHODIMP
CNDSGenObject::GetObject(
BSTR ClassName,
BSTR RelativeName,
IDispatch * FAR* ppObject
)
{
HRESULT hr = S_OK;
hr = ::RelativeGetObject(
_ADsPath,
ClassName,
RelativeName,
_Credentials,
ppObject,
FALSE
);
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::get__NewEnum(
THIS_ IUnknown * FAR* retval
)
{
HRESULT hr;
IUnknown FAR* punkEnum=NULL;
IEnumVARIANT * penum = NULL;
*retval = NULL;
hr = CNDSGenObjectEnum::Create(
(CNDSGenObjectEnum **)&penum,
_ADsPath,
_vFilter,
_Credentials
);
BAIL_ON_FAILURE(hr);
hr = penum->QueryInterface(
IID_IUnknown,
(VOID FAR* FAR*)retval
);
BAIL_ON_FAILURE(hr);
if (penum) {
penum->Release();
}
RRETURN(NOERROR);
error:
if (penum) {
delete penum;
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Create(
THIS_ BSTR ClassName,
BSTR RelativeName,
IDispatch * FAR* ppObject
)
{
HRESULT hr = S_OK;
IADs * pADs = NULL;
VARIANT var;
WCHAR szNDSTreeName[MAX_PATH];
DWORD dwSyntaxId = 0;
VARIANT vNewValue;
//
// Get the TreeName for this object
//
hr = BuildNDSTreeNameFromADsPath(
_ADsPath,
szNDSTreeName
);
BAIL_ON_FAILURE(hr);
//
// Validate if this class really exists in the schema
// and validate that this object can be created in this
// container
//
hr = CNDSGenObject::CreateGenericObject(
_ADsPath,
RelativeName,
ClassName,
_Credentials,
ADS_OBJECT_UNBOUND,
IID_IADs,
(void **)&pADs
);
BAIL_ON_FAILURE(hr);
VariantInit(&vNewValue);
V_BSTR(&vNewValue) = ClassName;
V_VT(&vNewValue) = VT_BSTR;
hr = pADs->Put(L"Object Class", vNewValue);
BAIL_ON_FAILURE(hr);
//
// InstantiateDerivedObject should addref this pointer for us.
//
hr = InstantiateDerivedObject(
pADs,
_Credentials,
IID_IDispatch,
(void **)ppObject
);
if (FAILED(hr)) {
hr = pADs->QueryInterface(
IID_IDispatch,
(void **)ppObject
);
BAIL_ON_FAILURE(hr);
}
error:
//
// Free the intermediate pADs pointer.
//
if (pADs) {
pADs->Release();
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Delete(
THIS_ BSTR bstrClassName,
BSTR bstrRelativeName
)
{
HRESULT hr = S_OK;
BSTR bstrChildPath = NULL;
LPWSTR pszNDSTreeName = NULL;
LPWSTR pszChildNDSDn = NULL;
LPWSTR ppszAttrs[] = {L"object Class"};
PNDS_ATTR_INFO pAttrEntries = NULL;
DWORD dwNumEntries = 0;
LPWSTR pszObjectClassName = NULL;
hr = BuildADsPath(
_ADsPath,
bstrRelativeName,
&bstrChildPath
);
BAIL_ON_FAILURE(hr);
hr = BuildNDSPathFromADsPath2(
bstrChildPath,
&pszNDSTreeName,
&pszChildNDSDn
);
BAIL_ON_FAILURE(hr);
hr = ADsNdsReadObject(
_hADsContext,
pszChildNDSDn,
DS_ATTRIBUTE_VALUES,
ppszAttrs,
1,
NULL,
&pAttrEntries,
&dwNumEntries
);
BAIL_ON_FAILURE(hr);
if (dwNumEntries != 1) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PATHNAME);
}
pszObjectClassName = (pAttrEntries[0].lpValue) ?
pAttrEntries[0].lpValue[0].NdsValue.value_20.ClassName :
NULL;
if (!pszObjectClassName) {
BAIL_ON_FAILURE(E_FAIL);
}
if (_wcsicmp(pszObjectClassName, bstrClassName)) {
hr = E_ADS_BAD_PARAMETER;
BAIL_ON_FAILURE(hr);
}
hr = ADsNdsRemoveObject(
_hADsContext,
pszChildNDSDn
);
BAIL_ON_FAILURE(hr);
error:
if (bstrChildPath) {
SysFreeString(bstrChildPath);
}
if (pszNDSTreeName) {
FreeADsStr(pszNDSTreeName);
}
if (pszChildNDSDn) {
FreeADsStr(pszChildNDSDn);
}
if (pAttrEntries) {
FreeNdsAttrInfo(pAttrEntries, dwNumEntries);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::CopyHere(
THIS_ BSTR SourceName,
BSTR NewName,
IDispatch * FAR* ppObject
)
{
HRESULT hr = S_OK;
IUnknown *pUnk = NULL;
hr = CopyObject(
_hADsContext,
SourceName,
_ADsPath,
NewName,
_Credentials,
(void**)&pUnk
);
BAIL_ON_FAILURE(hr);
hr = pUnk->QueryInterface(IID_IDispatch, (void **)ppObject);
error:
if (pUnk) {
pUnk->Release();
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::MoveHere(
THIS_ BSTR SourceName,
BSTR NewName,
IDispatch * FAR* ppObject
)
{
HRESULT hr = S_OK;
IUnknown *pUnk = NULL;
hr = MoveObject(
_hADsContext,
SourceName,
_ADsPath,
NewName,
_Credentials,
(void**)&pUnk
);
BAIL_ON_FAILURE(hr);
if (ppObject) {
hr = pUnk->QueryInterface(IID_IDispatch, (void **)ppObject);
}
error:
if (pUnk) {
pUnk->Release();
}
RRETURN(hr);
}
HRESULT
CNDSGenObject::AllocateGenObject(
CCredentials& Credentials,
CNDSGenObject ** ppGenObject
)
{
CNDSGenObject FAR * pGenObject = NULL;
CDispatchMgr FAR * pDispMgr = NULL;
CPropertyCache FAR * pPropertyCache = NULL;
HRESULT hr = S_OK;
pGenObject = new CNDSGenObject();
if (pGenObject == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pDispMgr = new CDispatchMgr;
if (pDispMgr == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADs,
(IADs *)pGenObject,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADsContainer,
(IADsContainer *)pGenObject,
DISPID_NEWENUM
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pDispMgr,
LIBID_ADs,
IID_IADsPropertyList,
(IADsPropertyList *)pGenObject,
DISPID_VALUE
);
BAIL_ON_FAILURE(hr);
hr = CPropertyCache::createpropertycache(
(CCoreADsObject FAR *)pGenObject,
&pPropertyCache
);
BAIL_ON_FAILURE(hr);
pGenObject->_Credentials = Credentials;
pGenObject->_pPropertyCache = pPropertyCache;
pGenObject->_pDispMgr = pDispMgr;
*ppGenObject = pGenObject;
RRETURN(hr);
error:
delete pDispMgr;
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Get(
THIS_ BSTR bstrName,
VARIANT FAR* pvProp
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId;
DWORD dwNumValues;
LPNDSOBJECT pNdsSrcObjects = NULL;
//
// retrieve data object from cache; if one exists
//
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = _pPropertyCache->unboundgetproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}else {
hr = _pPropertyCache->getproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}
//
// translate the Nds objects to variants
//
hr = NdsTypeToVarTypeCopyConstruct(
pNdsSrcObjects,
dwNumValues,
pvProp,
FALSE
);
BAIL_ON_FAILURE(hr);
error:
if (pNdsSrcObjects) {
NdsTypeFreeNdsObjects(
pNdsSrcObjects,
dwNumValues
);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Put(
THIS_ BSTR bstrName,
VARIANT vProp
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId = 0;
DWORD dwIndex = 0;
LPNDSOBJECT pNdsDestObjects = NULL;
DWORD dwNumValues = 0;
VARIANT * pVarArray = NULL;
VARIANT * pvProp = NULL;
//
// Issue: How do we handle multi-valued support
//
if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp)) {
hr = ConvertSafeArrayToVariantArray(
vProp,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
pvProp = pVarArray;
} else if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp) && V_ISBYREF(&vProp)) {
hr = ConvertByRefSafeArrayToVariantArray(
vProp,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
pvProp = pVarArray;
}else {
dwNumValues = 1;
pvProp = &vProp;
}
//
// check if this is a legal property for this object,
//
hr = ValidatePropertyinCache(
_pszNDSTreeName,
_ADsClass,
bstrName,
_Credentials,
&dwSyntaxId
);
BAIL_ON_FAILURE(hr);
//
// check if the variant maps to the syntax of this property
//
hr = VarTypeToNdsTypeCopyConstruct(
dwSyntaxId,
pvProp,
&dwNumValues,
&pNdsDestObjects
);
BAIL_ON_FAILURE(hr);
//
// Find this property in the cache
//
hr = _pPropertyCache->findproperty(
bstrName,
&dwIndex
);
//
// If this property does not exist in the
// cache, add this property into the cache.
//
if (FAILED(hr)) {
hr = _pPropertyCache->addproperty(
bstrName,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
//
// 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 = _pPropertyCache->putproperty(
bstrName,
CACHE_PROPERTY_MODIFIED,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
BAIL_ON_FAILURE(hr);
error:
if (pNdsDestObjects) {
NdsTypeFreeNdsObjects(
pNdsDestObjects,
dwNumValues
);
}
if (pVarArray) {
DWORD i = 0;
for (i = 0; i < dwNumValues; i++) {
VariantClear(pVarArray + i);
}
FreeADsMem(pVarArray);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::PutEx(
THIS_ long lnControlCode,
BSTR bstrName,
VARIANT vProp
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId = 0;
DWORD dwIndex = 0;
LPNDSOBJECT pNdsDestObjects = NULL;
DWORD dwNumValues = 0;
DWORD dwFlags = 0;
VARIANT * pVarArray = NULL;
VARIANT * pvProp = NULL;
//
// check if this is a legal property for this object,
//
hr = ValidatePropertyinCache(
_pszNDSTreeName,
_ADsClass,
bstrName,
_Credentials,
&dwSyntaxId
);
BAIL_ON_FAILURE(hr);
switch (lnControlCode) {
case ADS_PROPERTY_CLEAR:
dwFlags = CACHE_PROPERTY_CLEARED;
pNdsDestObjects = NULL;
dwNumValues = 0;
break;
case ADS_PROPERTY_UPDATE:
case ADS_PROPERTY_APPEND:
case ADS_PROPERTY_DELETE:
if (lnControlCode == ADS_PROPERTY_UPDATE) {
dwFlags = CACHE_PROPERTY_MODIFIED;
}
else if (lnControlCode == ADS_PROPERTY_APPEND) {
dwFlags = CACHE_PROPERTY_APPENDED;
}
else {
dwFlags = CACHE_PROPERTY_DELETED;
}
//
// Now begin the rest of the processing
//
if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp)) {
hr = ConvertSafeArrayToVariantArray(
vProp,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
pvProp = pVarArray;
} else if ((V_VT(&vProp) & VT_VARIANT) && V_ISARRAY(&vProp) && V_ISBYREF(&vProp)) {
hr = ConvertByRefSafeArrayToVariantArray(
vProp,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
pvProp = pVarArray;
}else {
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
//
// check if the variant maps to the syntax of this property
//
hr = VarTypeToNdsTypeCopyConstruct(
dwSyntaxId,
pvProp,
&dwNumValues,
&pNdsDestObjects
);
BAIL_ON_FAILURE(hr);
break;
default:
RRETURN(hr = E_ADS_BAD_PARAMETER);
}
//
// Find this property in the cache
//
hr = _pPropertyCache->findproperty(
bstrName,
&dwIndex
);
//
// If this property does not exist in the
// cache, add this property into the cache.
//
if (FAILED(hr)) {
hr = _pPropertyCache->addproperty(
bstrName,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
//
// 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 = _pPropertyCache->putproperty(
bstrName,
dwFlags,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
BAIL_ON_FAILURE(hr);
error:
if (pNdsDestObjects) {
NdsTypeFreeNdsObjects(
pNdsDestObjects,
dwNumValues
);
}
if (pVarArray) {
DWORD i = 0;
for (i = 0; i < dwNumValues; i++) {
VariantClear(pVarArray + i);
}
FreeADsMem(pVarArray);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::GetEx(
THIS_ BSTR bstrName,
VARIANT FAR* pvProp
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId;
DWORD dwNumValues;
LPNDSOBJECT pNdsSrcObjects = NULL;
//
// retrieve data object from cache; if one exists
//
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = _pPropertyCache->unboundgetproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}else {
hr = _pPropertyCache->getproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}
//
// translate the Nds objects to variants
//
hr = NdsTypeToVarTypeCopyConstruct(
pNdsSrcObjects,
dwNumValues,
pvProp,
TRUE
);
BAIL_ON_FAILURE(hr);
error:
if (pNdsSrcObjects) {
NdsTypeFreeNdsObjects(
pNdsSrcObjects,
dwNumValues
);
}
RRETURN(hr);
}
void
CNDSGenObject::InitSearchPrefs()
{
_SearchPref._dwSearchScope = DS_SEARCH_SUBTREE;
_SearchPref._fDerefAliases = FALSE;
_SearchPref._fAttrsOnly = FALSE;
_SearchPref._fCacheResults = TRUE;
}
STDMETHODIMP
CNDSGenObject::get_PropertyCount(
THIS_ long FAR *plCount
)
{
HRESULT hr = E_FAIL;
if (_pPropertyCache) {
hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Next(
THIS_ VARIANT FAR *pVariant
)
{
HRESULT hr = E_FAIL;
DWORD dwSyntaxId = 0;
DWORD dwNumValues = 0;
LPNDSOBJECT pNdsSrcObjects = NULL;
VARIANT varData;
IDispatch * pDispatch = NULL;
PADSVALUE pAdsValues = NULL;
if (!_pPropertyCache->index_valid())
RRETURN(E_FAIL);
VariantInit(&varData);
hr = _pPropertyCache->unboundgetproperty(
_pPropertyCache->get_CurrentIndex(),
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
//
// translate the Nds objects to variants
//
hr = ConvertNdsValuesToVariant(
_pPropertyCache->get_CurrentPropName(),
pNdsSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
//
// We're successful so far, now skip by 1
//
hr = Skip(1);
error:
if (pNdsSrcObjects) {
NdsTypeFreeNdsObjects(pNdsSrcObjects, dwNumValues);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Skip(
THIS_ long cElements
)
{
HRESULT hr = S_OK;
hr = _pPropertyCache->skip_propindex(
cElements
);
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Reset(
)
{
_pPropertyCache->reset_propindex();
RRETURN(S_OK);
}
STDMETHODIMP
CNDSGenObject::ResetPropertyItem(THIS_ VARIANT varEntry)
{
HRESULT hr = S_OK;
DWORD dwIndex = 0;
switch (V_VT(&varEntry)) {
case VT_BSTR:
hr = _pPropertyCache->findproperty(
V_BSTR(&varEntry),
&dwIndex
);
BAIL_ON_FAILURE(hr);
break;
case VT_I4:
dwIndex = V_I4(&varEntry);
break;
case VT_I2:
dwIndex = V_I2(&varEntry);
break;
default:
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
hr = _pPropertyCache->deleteproperty(
dwIndex
);
error:
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::GetPropertyItem(
THIS_ BSTR bstrName,
LONG lnType,
VARIANT * pVariant
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId;
DWORD dwNumValues;
LPNDSOBJECT pNdsSrcObjects = NULL;
PADSVALUE pAdsValues = NULL;
//
// retrieve data object from cache; if one exists
//
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = _pPropertyCache->unboundgetproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}else {
hr = _pPropertyCache->getproperty(
bstrName,
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}
//
// translate the Nds objects to variants
//
hr = ConvertNdsValuesToVariant(
bstrName,
pNdsSrcObjects,
dwNumValues,
pVariant
);
error:
if (pNdsSrcObjects) {
NdsTypeFreeNdsObjects(
pNdsSrcObjects,
dwNumValues
);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::PutPropertyItem(THIS_ VARIANT varData)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId = 0;
DWORD dwIndex = 0;
WCHAR szPropertyName[MAX_PATH];
DWORD dwControlCode = 0;
LPNDSOBJECT pNdsDestObjects = NULL;
DWORD dwNumValues = 0;
DWORD dwFlags = 0;
VARIANT * pVarArray = NULL;
VARIANT * pvarData = NULL;
PADSVALUE pAdsValues = NULL;
DWORD dwAdsValues = 0;
DWORD dwSyntaxId2 = 0;
DWORD dwNumNdsValues = 0;
hr = ConvertVariantToNdsValues(
varData,
szPropertyName,
&dwControlCode,
&pNdsDestObjects,
&dwNumValues,
&dwSyntaxId
);
BAIL_ON_FAILURE(hr);
switch (dwControlCode) {
case ADS_PROPERTY_CLEAR:
dwFlags = CACHE_PROPERTY_CLEARED;
pNdsDestObjects = NULL;
dwNumValues = 0;
break;
case ADS_PROPERTY_UPDATE:
dwFlags = CACHE_PROPERTY_MODIFIED;
break;
case ADS_PROPERTY_APPEND:
dwFlags = CACHE_PROPERTY_APPENDED;
break;
case ADS_PROPERTY_DELETE:
dwFlags = CACHE_PROPERTY_DELETED;
break;
default:
RRETURN(hr = E_ADS_BAD_PARAMETER);
}
//
// Find this property in the cache
//
hr = _pPropertyCache->findproperty(
szPropertyName,
&dwIndex
);
//
// If this property does not exist in the
// cache, add this property into the cache.
//
if (FAILED(hr)) {
hr = _pPropertyCache->addproperty(
szPropertyName,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
//
// 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 = _pPropertyCache->putproperty(
szPropertyName,
dwFlags,
dwSyntaxId,
dwNumValues,
pNdsDestObjects
);
BAIL_ON_FAILURE(hr);
error:
if (pNdsDestObjects) {
NdsTypeFreeNdsObjects(
pNdsDestObjects,
dwNumValues
);
}
RRETURN(hr);
}
HRESULT
CreatePropEntry(
LPWSTR szPropName,
DWORD ADsType,
DWORD numValues,
VARIANT varData,
REFIID riid,
LPVOID * ppDispatch
)
{
HRESULT hr = S_OK;
IADsPropertyEntry * pPropEntry = NULL;
hr = CoCreateInstance(
CLSID_PropertyEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsPropertyEntry,
(void **)&pPropEntry
);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_Name(szPropName);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_ADsType(ADsType);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_Values(varData);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->QueryInterface(
riid,
ppDispatch
);
BAIL_ON_FAILURE(hr);
error:
if (pPropEntry) {
pPropEntry->Release();
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::Item(
THIS_ VARIANT varIndex,
VARIANT * pVariant
)
{
HRESULT hr = S_OK;
DWORD dwSyntaxId;
DWORD dwNumValues;
LPNDSOBJECT pNdsSrcObjects = NULL;
PADSVALUE pAdsValues = NULL;
LPWSTR szPropName = NULL;
//
// retrieve data object from cache; if one exis
//
switch (V_VT(&varIndex)) {
case VT_BSTR:
//
// retrieve data object from cache; if one exists
//
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = _pPropertyCache->unboundgetproperty(
V_BSTR(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}else {
hr = _pPropertyCache->getproperty(
V_BSTR(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
}
hr = ConvertNdsValuesToVariant(
V_BSTR(&varIndex),
pNdsSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
break;
case VT_I4:
hr = _pPropertyCache->unboundgetproperty(
V_I4(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
szPropName = _pPropertyCache->get_PropName(V_I4(&varIndex));
hr = ConvertNdsValuesToVariant(
szPropName,
pNdsSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
break;
case VT_I2:
hr = _pPropertyCache->unboundgetproperty(
(DWORD)V_I2(&varIndex),
&dwSyntaxId,
&dwNumValues,
&pNdsSrcObjects
);
BAIL_ON_FAILURE(hr);
szPropName = _pPropertyCache->get_PropName(V_I2(&varIndex));
hr = ConvertNdsValuesToVariant(
szPropName,
pNdsSrcObjects,
dwNumValues,
pVariant
);
BAIL_ON_FAILURE(hr);
break;
default:
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
error:
if (pNdsSrcObjects) {
NdsTypeFreeNdsObjects(
pNdsSrcObjects,
dwNumValues
);
}
RRETURN(hr);
}
STDMETHODIMP
CNDSGenObject::PurgePropertyList()
{
_pPropertyCache->flushpropcache();
RRETURN(S_OK);
}
HRESULT
ConvertVariantToVariantArray(
VARIANT varData,
VARIANT ** ppVarArray,
DWORD * pdwNumValues
)
{
DWORD dwNumValues = 0;
VARIANT * pVarArray = NULL;
HRESULT hr = S_OK;
*ppVarArray = NULL;
*pdwNumValues = 0;
if ((V_VT(&varData) & VT_VARIANT) && V_ISARRAY(&varData) && V_ISBYREF(&varData)){
hr = ConvertByRefSafeArrayToVariantArray(
varData,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
} else if ((V_VT(&varData) & VT_VARIANT) && V_ISARRAY(&varData)) {
hr = ConvertSafeArrayToVariantArray(
varData,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
} else {
pVarArray = NULL;
dwNumValues = 0;
}
*ppVarArray = pVarArray;
*pdwNumValues = dwNumValues;
error:
RRETURN(hr);
}
void
FreeVariantArray(
VARIANT * pVarArray,
DWORD dwNumValues
)
{
if (pVarArray) {
DWORD i = 0;
for (i = 0; i < dwNumValues; i++) {
VariantClear(pVarArray + i);
}
FreeADsMem(pVarArray);
}
}
HRESULT
ConvertVariantToNdsValues(
VARIANT varData,
LPWSTR szPropertyName,
PDWORD pdwControlCode,
PNDSOBJECT * ppNdsDestObjects,
PDWORD pdwNumValues,
PDWORD pdwSyntaxId
)
{
HRESULT hr = S_OK;
IADsPropertyEntry * pPropEntry = NULL;
IDispatch * pDispatch = NULL;
BSTR bstrPropName = NULL;
DWORD dwControlCode = 0;
DWORD dwAdsType = 0;
VARIANT varValues;
VARIANT * pVarArray = NULL;
DWORD dwNumValues = 0;
PADSVALUE pAdsValues = NULL;
DWORD dwAdsValues = 0;
PNDSOBJECT pNdsDestObjects = 0;
DWORD dwNumNdsObjects = 0;
DWORD dwNdsSyntaxId = 0;
if (V_VT(&varData) != VT_DISPATCH) {
RRETURN (hr = DISP_E_TYPEMISMATCH);
}
pDispatch = V_DISPATCH(&varData);
hr = pDispatch->QueryInterface(
IID_IADsPropertyEntry,
(void **)&pPropEntry
);
BAIL_ON_FAILURE(hr);
VariantInit(&varValues);
VariantClear(&varValues);
hr = pPropEntry->get_Name(&bstrPropName);
BAIL_ON_FAILURE(hr);
wcscpy(szPropertyName, bstrPropName);
hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
BAIL_ON_FAILURE(hr);
*pdwControlCode = dwControlCode;
hr = pPropEntry->get_ADsType((long *)&dwAdsType);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->get_Values(&varValues);
BAIL_ON_FAILURE(hr);
hr = ConvertVariantToVariantArray(
varValues,
&pVarArray,
&dwNumValues
);
BAIL_ON_FAILURE(hr);
if (dwNumValues) {
hr = PropVariantToAdsType(
pVarArray,
dwNumValues,
&pAdsValues,
&dwAdsValues
);
BAIL_ON_FAILURE(hr);
hr = AdsTypeToNdsTypeCopyConstruct(
pAdsValues,
dwAdsValues,
&pNdsDestObjects,
&dwNumNdsObjects,
&dwNdsSyntaxId
);
BAIL_ON_FAILURE(hr);
}
*ppNdsDestObjects = pNdsDestObjects;
*pdwNumValues = dwNumNdsObjects;
*pdwSyntaxId = dwNdsSyntaxId;
cleanup:
if (bstrPropName) {
ADsFreeString(bstrPropName);
}
if (pAdsValues) {
AdsFreeAdsValues(
pAdsValues,
dwNumValues
);
FreeADsMem( pAdsValues );
}
if (pVarArray) {
FreeVariantArray(
pVarArray,
dwAdsValues
);
}
if (pPropEntry) {
pPropEntry->Release();
}
RRETURN(hr);
error:
if (pNdsDestObjects) {
NdsTypeFreeNdsObjects(
pNdsDestObjects,
dwNumNdsObjects
);
}
*ppNdsDestObjects = NULL;
*pdwNumValues = 0;
goto cleanup;
}
HRESULT
ConvertNdsValuesToVariant(
BSTR bstrPropName,
LPNDSOBJECT pNdsSrcObjects,
DWORD dwNumValues,
PVARIANT pVarProp
)
{
HRESULT hr = S_OK;
PADSVALUE pAdsValues = NULL;
DWORD dwNumAdsValues = 0;
VARIANT varData;
IDispatch * pDispatch = NULL;
DWORD dwADsType = 0;
VariantInit(&varData);
VariantInit(pVarProp);
//
// translate the Nds objects to variants
//
hr = NdsTypeToAdsTypeCopyConstruct(
pNdsSrcObjects,
dwNumValues,
&pAdsValues
);
if (SUCCEEDED(hr)){
hr = AdsTypeToPropVariant(
pAdsValues,
dwNumValues,
&varData
);
if (SUCCEEDED(hr)) {
dwADsType = pAdsValues->dwType;
}else {
VariantClear(&varData);
hr = S_OK;
}
}else {
VariantClear(&varData);
VariantInit(&varData);
hr = S_OK;
}
hr = CreatePropEntry(
bstrPropName,
dwADsType,
dwNumValues,
varData,
IID_IDispatch,
(void **)&pDispatch
);
BAIL_ON_FAILURE(hr);
V_DISPATCH(pVarProp) = pDispatch;
V_VT(pVarProp) = VT_DISPATCH;
RRETURN(hr);
error:
if (pAdsValues) {
AdsFreeAdsValues(
pAdsValues,
dwNumValues
);
FreeADsMem( pAdsValues );
}
RRETURN(hr);
}