mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1077 lines
19 KiB
1077 lines
19 KiB
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: cdomain.cxx
|
|
//
|
|
// Contents: Microsoft ADs NDS Provider Tree Object
|
|
//
|
|
//
|
|
// History: 01-30-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include "nds.hxx"
|
|
#pragma hdrstop
|
|
|
|
// Class CNDSTree
|
|
|
|
DEFINE_IDispatch_Implementation(CNDSTree)
|
|
DEFINE_IADs_Implementation(CNDSTree)
|
|
|
|
|
|
CNDSTree::CNDSTree():
|
|
_pPropertyCache(NULL)
|
|
{
|
|
|
|
VariantInit(&_vFilter);
|
|
_hADsContext = NULL;
|
|
_pszNDSTreeName = _pszNDSDn = NULL;
|
|
|
|
ENLIST_TRACKING(CNDSTree);
|
|
}
|
|
|
|
HRESULT
|
|
CNDSTree::CreateTreeObject(
|
|
BSTR bstrADsPath,
|
|
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 = CNDSTree::CreateTreeObject(
|
|
szADsParent,
|
|
szCommonName,
|
|
L"user",
|
|
Credentials,
|
|
dwObjectState,
|
|
riid,
|
|
ppvObj
|
|
);
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CNDSTree::CreateTreeObject(
|
|
BSTR Parent,
|
|
BSTR CommonName,
|
|
BSTR ClassName,
|
|
CCredentials& Credentials,
|
|
DWORD dwObjectState,
|
|
REFIID riid,
|
|
void **ppvObj
|
|
)
|
|
{
|
|
CNDSTree FAR * pTree = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = AllocateTree(Credentials, &pTree);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pTree->InitializeCoreObject(
|
|
Parent,
|
|
CommonName,
|
|
ClassName,
|
|
L"",
|
|
CLSID_NDSTree,
|
|
dwObjectState
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = BuildNDSPathFromADsPath2(
|
|
pTree->_ADsPath,
|
|
&(pTree->_pszNDSTreeName),
|
|
&(pTree->_pszNDSDn)
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsNdsOpenContext(
|
|
pTree->_pszNDSTreeName,
|
|
Credentials,
|
|
&(pTree->_hADsContext)
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pTree->QueryInterface(riid, ppvObj);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pTree->Release();
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
delete pTree;
|
|
RRETURN(hr);
|
|
}
|
|
|
|
CNDSTree::~CNDSTree( )
|
|
{
|
|
VariantClear(&_vFilter);
|
|
|
|
if (_hADsContext) {
|
|
ADsNdsCloseContext(_hADsContext);
|
|
}
|
|
|
|
if (_pszNDSTreeName) {
|
|
FreeADsMem(_pszNDSTreeName);
|
|
}
|
|
|
|
if (_pszNDSDn) {
|
|
FreeADsMem(_pszNDSDn);
|
|
}
|
|
|
|
delete _pDispMgr;
|
|
|
|
delete _pPropertyCache;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::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
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT
|
|
CNDSTree::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
|
|
CNDSTree::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
|
|
CNDSTree::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 (fUserObject) {
|
|
hr = ADsNdsGenObjectKey(_hADsContext,
|
|
_pszNDSDn);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
if (bstrClass) {
|
|
ADsFreeString(bstrClass);
|
|
}
|
|
if (hOperationData) {
|
|
|
|
ADsNdsFreeBuffer(hOperationData);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CNDSTree::GetInfo()
|
|
{
|
|
RRETURN(GetInfo(TRUE));
|
|
}
|
|
|
|
HRESULT
|
|
CNDSTree::GetInfo(
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
NDS_CONTEXT_HANDLE hADsContext = NULL;
|
|
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:
|
|
|
|
FreeNdsAttrInfo( lpEntries, dwNumEntries );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
|
|
{
|
|
RRETURN(E_NOTIMPL);
|
|
}
|
|
|
|
/* IADsContainer methods */
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::get_Count(long FAR* retval)
|
|
{
|
|
RRETURN(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::get_Filter(THIS_ VARIANT FAR* pVar)
|
|
{
|
|
VariantInit(pVar);
|
|
RRETURN(VariantCopy(pVar, &_vFilter));
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::put_Filter(THIS_ VARIANT Var)
|
|
{
|
|
VariantClear(&_vFilter);
|
|
RRETURN(VariantCopy(&_vFilter, &Var));
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::put_Hints(THIS_ VARIANT Var)
|
|
{
|
|
RRETURN( E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::get_Hints(THIS_ VARIANT FAR* pVar)
|
|
{
|
|
RRETURN(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::GetObject(
|
|
BSTR ClassName,
|
|
BSTR RelativeName,
|
|
IDispatch * FAR* ppObject
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = ::RelativeGetObject(
|
|
_ADsPath,
|
|
ClassName,
|
|
RelativeName,
|
|
_Credentials,
|
|
ppObject,
|
|
FALSE
|
|
);
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::get__NewEnum(
|
|
THIS_ IUnknown * FAR* retval
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IUnknown FAR* punkEnum=NULL;
|
|
IEnumVARIANT * penum = NULL;
|
|
|
|
|
|
*retval = NULL;
|
|
|
|
hr = CNDSTreeEnum::Create(
|
|
(CNDSTreeEnum **)&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
|
|
CNDSTree::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;
|
|
|
|
//
|
|
// 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_IDispatch,
|
|
(void **)ppObject
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::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
|
|
CNDSTree::CopyHere(
|
|
THIS_ BSTR SourceName,
|
|
BSTR NewName,
|
|
IDispatch * FAR* ppObject
|
|
)
|
|
{
|
|
RRETURN(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::MoveHere(
|
|
THIS_ BSTR SourceName,
|
|
BSTR NewName,
|
|
IDispatch * FAR* ppObject
|
|
)
|
|
{
|
|
RRETURN(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CNDSTree::AllocateTree(
|
|
CCredentials& Credentials,
|
|
CNDSTree ** ppTree
|
|
)
|
|
{
|
|
CNDSTree FAR * pTree = NULL;
|
|
CDispatchMgr FAR * pDispMgr = NULL;
|
|
CPropertyCache FAR * pPropertyCache = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
pTree = new CNDSTree();
|
|
if (pTree == 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 *)pTree,
|
|
DISPID_REGULAR
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LoadTypeInfoEntry(pDispMgr,
|
|
LIBID_ADs,
|
|
IID_IADsContainer,
|
|
(IADsContainer *)pTree,
|
|
DISPID_NEWENUM
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = CPropertyCache::createpropertycache(
|
|
(CCoreADsObject FAR *)pTree,
|
|
&pPropertyCache
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
|
|
pTree->_Credentials = Credentials;
|
|
pTree->_pPropertyCache = pPropertyCache;
|
|
pTree->_pDispMgr = pDispMgr;
|
|
*ppTree = pTree;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
delete pDispMgr;
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::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
|
|
//
|
|
|
|
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
|
|
CNDSTree::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
|
|
//
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::Put(
|
|
THIS_ BSTR bstrName,
|
|
VARIANT vProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
LPNDSOBJECT pNdsDestObjects = NULL;
|
|
WCHAR szNDSTreeName[MAX_PATH];
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
DWORD dwNumValues = 1;
|
|
|
|
//
|
|
// Get the TreeName for this object
|
|
//
|
|
|
|
hr = BuildNDSTreeNameFromADsPath(
|
|
_ADsPath,
|
|
szNDSTreeName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if this is a legal property for this object,
|
|
//
|
|
|
|
hr = ValidatePropertyinCache(
|
|
szNDSTreeName,
|
|
_ADsClass,
|
|
bstrName,
|
|
_Credentials,
|
|
&dwSyntaxId
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if the variant maps to the syntax of this property
|
|
//
|
|
|
|
hr = VarTypeToNdsTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
&vProp,
|
|
&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
|
|
);
|
|
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSTree::PutEx(
|
|
THIS_ long lnControlCode,
|
|
BSTR bstrName,
|
|
VARIANT vProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
LPNDSOBJECT pNdsDestObjects = NULL;
|
|
WCHAR szNDSTreeName[MAX_PATH];
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
DWORD dwNumValues = 1;
|
|
|
|
//
|
|
// Get the TreeName for this object
|
|
//
|
|
|
|
hr = BuildNDSTreeNameFromADsPath(
|
|
_ADsPath,
|
|
szNDSTreeName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if this is a legal property for this object,
|
|
//
|
|
|
|
hr = ValidatePropertyinCache(
|
|
szNDSTreeName,
|
|
_ADsClass,
|
|
bstrName,
|
|
_Credentials,
|
|
&dwSyntaxId
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// check if the variant maps to the syntax of this property
|
|
//
|
|
|
|
hr = VarTypeToNdsTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
&vProp,
|
|
&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
|
|
);
|
|
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|