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.
2415 lines
53 KiB
2415 lines
53 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
|
|
_fIsAggregated = 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];
|
|
|
|
memset(szADsParent, 0, sizeof(szADsParent));
|
|
memset(szCommonName, 0, sizeof(szCommonName));
|
|
|
|
//
|
|
// 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_EXP_IF_ERR(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 = 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;
|
|
}
|
|
|
|
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_ISupportErrorInfo))
|
|
{
|
|
*ppv = (ISupportErrorInfo 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;
|
|
}
|
|
|
|
/* ISupportErrorInfo method */
|
|
HRESULT
|
|
CNDSGenObject::InterfaceSupportsErrorInfo(
|
|
THIS_ REFIID riid
|
|
)
|
|
{
|
|
if (IsEqualIID(riid, IID_IADs) ||
|
|
IsEqualIID(riid, IID_IADsPropertyList) ||
|
|
#if 0
|
|
IsEqualIID(riid, IID_IDirectoryObject) ||
|
|
IsEqualIID(riid, IID_IDirectorySearch) ||
|
|
IsEqualIID(riid, IID_IDirectorySchemaMgmt) ||
|
|
#endif
|
|
IsEqualIID(riid, IID_IADsContainer)) {
|
|
RRETURN(S_OK);
|
|
} else {
|
|
RRETURN(S_FALSE);
|
|
}
|
|
}
|
|
|
|
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_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CNDSGenObject::NDSSetObject()
|
|
{
|
|
DWORD dwStatus = 0L;
|
|
LPWSTR pszNDSPathName = NULL;
|
|
HANDLE hOperationData = NULL;
|
|
HANDLE hObject = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
_ADsPath,
|
|
&pszNDSPathName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSPathName,
|
|
_Credentials,
|
|
&hObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
dwStatus = NwNdsCreateBuffer(
|
|
NDS_OBJECT_MODIFY,
|
|
&hOperationData
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
hr = _pPropertyCache->NDSMarshallProperties(
|
|
hOperationData
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = NwNdsModifyObject(
|
|
hObject,
|
|
hOperationData
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
|
|
error:
|
|
|
|
if (pszNDSPathName) {
|
|
|
|
FreeADsStr(pszNDSPathName);
|
|
}
|
|
|
|
if (hOperationData) {
|
|
|
|
dwStatus = NwNdsFreeBuffer(hOperationData);
|
|
}
|
|
|
|
if (hObject) {
|
|
|
|
dwStatus = NwNdsCloseObject(hObject);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CNDSGenObject::NDSCreateObject()
|
|
{
|
|
DWORD dwStatus = 0L;
|
|
LPWSTR pszNDSParentName = NULL;
|
|
HANDLE hOperationData = NULL;
|
|
HANDLE hObject = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
_Parent,
|
|
&pszNDSParentName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSParentName,
|
|
_Credentials,
|
|
&hObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
dwStatus = NwNdsCreateBuffer(
|
|
NDS_OBJECT_ADD,
|
|
&hOperationData
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
hr = _pPropertyCache->NDSMarshallProperties(
|
|
hOperationData
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = NwNdsAddObject(
|
|
hObject,
|
|
_Name,
|
|
hOperationData
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
error:
|
|
|
|
if (hOperationData) {
|
|
|
|
dwStatus = NwNdsFreeBuffer(hOperationData);
|
|
}
|
|
|
|
if (hObject) {
|
|
|
|
dwStatus = NwNdsCloseObject(hObject);
|
|
}
|
|
|
|
|
|
if (pszNDSParentName) {
|
|
|
|
FreeADsStr(pszNDSParentName);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CNDSGenObject::GetInfo()
|
|
{
|
|
_pPropertyCache->flushpropcache();
|
|
|
|
RRETURN(GetInfo(TRUE));
|
|
}
|
|
|
|
HRESULT
|
|
CNDSGenObject::GetInfo(
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
DWORD dwStatus = 0L;
|
|
HANDLE hObject = NULL;
|
|
HANDLE hOperationData = NULL;
|
|
HRESULT hr = S_OK;
|
|
LPWSTR pszNDSPathName = NULL;
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
hr = E_ADS_OBJECT_UNBOUND;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
_ADsPath,
|
|
&pszNDSPathName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSPathName,
|
|
_Credentials,
|
|
&hObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
hOperationData = NULL;
|
|
|
|
dwStatus = NwNdsReadObject(
|
|
hObject,
|
|
NDS_INFO_ATTR_NAMES_VALUES,
|
|
&hOperationData
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
hr = _pPropertyCache->NDSUnMarshallProperties(
|
|
hOperationData,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (hOperationData) {
|
|
|
|
dwStatus = NwNdsFreeBuffer(hOperationData);
|
|
}
|
|
|
|
if (hObject) {
|
|
|
|
dwStatus = NwNdsCloseObject(hObject);
|
|
}
|
|
|
|
|
|
if (pszNDSPathName) {
|
|
|
|
FreeADsStr(pszNDSPathName);
|
|
}
|
|
|
|
if (_pPropertyCache) {
|
|
Reset();
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = 0L;
|
|
HANDLE hObject = NULL;
|
|
VARIANT *vVarArray = NULL;
|
|
DWORD dwNumVariants = 0;
|
|
HANDLE hOperationData = NULL;
|
|
LPWSTR pszNDSPathName = NULL;
|
|
DWORD i;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(lnReserved);
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
hr = E_ADS_OBJECT_UNBOUND;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = BuildNDSPathFromADsPath(_ADsPath, &pszNDSPathName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ConvertSafeArrayToVariantArray(
|
|
vProperties,
|
|
&vVarArray,
|
|
&dwNumVariants
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSPathName, _Credentials, &hObject, NULL, NULL, NULL, NULL);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
hOperationData = NULL;
|
|
dwStatus = NwNdsCreateBuffer(NDS_OBJECT_READ, &hOperationData);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
//
|
|
// Fill up the buffer with our search parameters.
|
|
//
|
|
for (i = 0; i < dwNumVariants; i++)
|
|
{
|
|
if (!(V_VT(vVarArray + i) == VT_BSTR))
|
|
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
|
|
|
|
dwStatus = NwNdsPutInBuffer(
|
|
V_BSTR(vVarArray + i), 0, NULL, 0, 0, hOperationData);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
}
|
|
|
|
dwStatus = NwNdsReadObject(
|
|
hObject,
|
|
NDS_INFO_ATTR_NAMES_VALUES,
|
|
&hOperationData
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
//
|
|
// 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->NDSUnMarshallProperties(hOperationData, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if (hOperationData)
|
|
dwStatus = NwNdsFreeBuffer(hOperationData);
|
|
|
|
if (vVarArray){
|
|
// Need to free each variants content and then the arrays.
|
|
for (i = 0; i < dwNumVariants; i++) {
|
|
VariantClear(vVarArray + i);
|
|
}
|
|
FreeADsMem(vVarArray);
|
|
}
|
|
|
|
if (hObject)
|
|
dwStatus = NwNdsCloseObject(hObject);
|
|
|
|
if (pszNDSPathName)
|
|
FreeADsStr(pszNDSPathName);
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
/* IADsContainer methods */
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::get_Count(long FAR* retval)
|
|
{
|
|
RRETURN_EXP_IF_ERR(E_NOTIMPL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
|
|
{
|
|
HRESULT hr;
|
|
VariantInit(pVar);
|
|
hr = VariantCopy(pVar, &_vFilter);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::put_Filter(THIS_ VARIANT Var)
|
|
{
|
|
HRESULT hr;
|
|
VariantClear(&_vFilter);
|
|
hr = VariantCopy(&_vFilter, &Var);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::put_Hints(THIS_ VARIANT Var)
|
|
{
|
|
RRETURN_EXP_IF_ERR( E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
|
|
{
|
|
RRETURN_EXP_IF_ERR(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_EXP_IF_ERR(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_EXP_IF_ERR(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_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::Delete(
|
|
THIS_ BSTR bstrClassName,
|
|
BSTR bstrRelativeName
|
|
)
|
|
{
|
|
LPWSTR pszNDSPathName = NULL;
|
|
LPWSTR pszNDSChildPath = NULL;
|
|
WCHAR szChildObjectClassName[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = 0;
|
|
HANDLE hChildObject = NULL;
|
|
HANDLE hParentObject = NULL;
|
|
BSTR bstrChildPath = NULL;
|
|
|
|
hr = BuildADsPath(
|
|
_ADsPath,
|
|
bstrRelativeName,
|
|
&bstrChildPath
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
bstrChildPath,
|
|
&pszNDSChildPath
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSChildPath,
|
|
_Credentials,
|
|
&hChildObject,
|
|
NULL,
|
|
szChildObjectClassName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
if (hChildObject) {
|
|
|
|
NwNdsCloseObject(hChildObject);
|
|
}
|
|
|
|
|
|
if (_wcsicmp(szChildObjectClassName, bstrClassName)) {
|
|
hr = E_ADS_BAD_PARAMETER;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// We now are sure we're deleting an object of the
|
|
// specified class
|
|
//
|
|
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
_ADsPath,
|
|
&pszNDSPathName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSPathName,
|
|
_Credentials,
|
|
&hParentObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
dwStatus = NwNdsRemoveObject(
|
|
hParentObject,
|
|
bstrRelativeName
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
|
|
error:
|
|
|
|
if (bstrChildPath) {
|
|
SysFreeString(bstrChildPath);
|
|
}
|
|
|
|
|
|
if (pszNDSPathName) {
|
|
FreeADsStr(pszNDSPathName);
|
|
|
|
}
|
|
|
|
if (pszNDSChildPath) {
|
|
FreeADsStr(pszNDSChildPath);
|
|
}
|
|
|
|
if (hParentObject) {
|
|
NwNdsCloseObject(
|
|
hParentObject
|
|
);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::CopyHere(
|
|
THIS_ BSTR SourceName,
|
|
BSTR NewName,
|
|
IDispatch * FAR* ppObject
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IUnknown *pUnk = NULL;
|
|
|
|
hr = CopyObject(
|
|
SourceName,
|
|
_ADsPath,
|
|
NewName,
|
|
_Credentials,
|
|
(void**)&pUnk
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pUnk->QueryInterface(IID_IDispatch, (void **)ppObject);
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::MoveHere(
|
|
THIS_ BSTR SourceName,
|
|
BSTR NewName,
|
|
IDispatch * FAR* ppObject
|
|
)
|
|
{
|
|
LPWSTR pszNDSDestPathName = NULL; // Target Parent DN (NDS format)
|
|
LPWSTR pszNDSSrcParent = NULL; // Source Parent DN (NDS format)
|
|
WCHAR szSrcParent[MAX_PATH]; // Source Parent DN (ADSI format)
|
|
WCHAR szCN[MAX_PATH]; // Source RDN
|
|
LPWSTR pszRelativeName = NULL; // Target RDN
|
|
WCHAR szObjectClass[MAX_PATH]; // Object class of object being moved/renamed
|
|
|
|
LPWSTR pszNDSSrcPathName = NULL; // Source DN for move (NDS format)
|
|
BSTR pszADsSrcPathName = NULL; // Source DN for move (ADSI format)
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = 0;
|
|
HANDLE hSrcObject = NULL;
|
|
HANDLE hParentObject = NULL;
|
|
IADs *pADs = NULL;
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
_ADsPath,
|
|
&pszNDSDestPathName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = BuildADsParentPath(
|
|
SourceName,
|
|
szSrcParent,
|
|
szCN
|
|
);
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
szSrcParent,
|
|
&pszNDSSrcParent
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (NewName)
|
|
pszRelativeName = NewName;
|
|
else
|
|
pszRelativeName = szCN;
|
|
|
|
BuildADsPath(szSrcParent, pszRelativeName, &pszADsSrcPathName);
|
|
|
|
hr = BuildNDSPathFromADsPath(
|
|
pszADsSrcPathName,
|
|
&pszNDSSrcPathName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// Get the value of the new and old name
|
|
//
|
|
if ( NewName != NULL) {
|
|
//
|
|
// Get the value from the NewName if user supplies 'CN=xxx'
|
|
//
|
|
LPWSTR pszCN = NewName;
|
|
|
|
while (*pszCN != '\0' && *pszCN != '=') {
|
|
pszCN++;
|
|
}
|
|
if (*pszCN != '\0') {
|
|
NewName = ++pszCN;
|
|
}
|
|
|
|
//
|
|
// Getting the value from the CN since it is always in the format 'CN=xxx'
|
|
//
|
|
LPWSTR pszRDN = szCN;
|
|
while (*pszRDN != '\0' && *pszRDN != '=') {
|
|
pszRDN++;
|
|
}
|
|
if (*pszRDN == '\0') {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
else {
|
|
pszRDN++;
|
|
}
|
|
|
|
//
|
|
// Only carry out rename if the names are different
|
|
//
|
|
if (wcscmp(pszRDN,NewName) != 0) {
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSSrcParent,
|
|
_Credentials,
|
|
&hParentObject,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
dwStatus = NwNdsRenameObject(
|
|
hParentObject,
|
|
pszRDN,
|
|
NewName,
|
|
FALSE);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Only carry out move if the two parents are different
|
|
//
|
|
dwStatus = ADsNwNdsOpenObject(
|
|
pszNDSSrcPathName,
|
|
_Credentials,
|
|
&hSrcObject,
|
|
NULL,
|
|
szObjectClass,
|
|
NULL,
|
|
NULL
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
|
|
|
|
if (wcscmp(pszNDSDestPathName, pszNDSSrcParent) != 0) {
|
|
|
|
dwStatus = NwNdsMoveObject(
|
|
hSrcObject,
|
|
pszNDSDestPathName
|
|
);
|
|
CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr);
|
|
}
|
|
|
|
if (ppObject) {
|
|
|
|
hr = CNDSGenObject::CreateGenericObject(
|
|
_ADsPath,
|
|
pszRelativeName,
|
|
szObjectClass,
|
|
_Credentials,
|
|
ADS_OBJECT_BOUND,
|
|
IID_IADs,
|
|
(void **)&pADs
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// InstantiateDerivedObject should add-ref 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:
|
|
if (hSrcObject) {
|
|
NwNdsCloseObject(hSrcObject);
|
|
}
|
|
if (hParentObject) {
|
|
NwNdsCloseObject(hParentObject);
|
|
}
|
|
if (pszNDSSrcParent) {
|
|
FreeADsMem(pszNDSSrcParent);
|
|
}
|
|
if (pszNDSDestPathName) {
|
|
FreeADsMem(pszNDSDestPathName);
|
|
}
|
|
if (pszNDSSrcPathName) {
|
|
FreeADsMem(pszNDSSrcPathName);
|
|
}
|
|
if (pszADsSrcPathName) {
|
|
ADsFreeString(pszADsSrcPathName);
|
|
}
|
|
if (pADs) {
|
|
pADs->Release();
|
|
}
|
|
RRETURN_EXP_IF_ERR(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 pGenObject;
|
|
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_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::Put(
|
|
THIS_ BSTR bstrName,
|
|
VARIANT vProp
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = 0;
|
|
DWORD dwIndex = 0;
|
|
LPNDSOBJECT pNdsDestObjects = NULL;
|
|
WCHAR szNDSTreeName[MAX_PATH];
|
|
DWORD dwNumValues = 0, dwNumVariants = 0;
|
|
|
|
VARIANT * pVarArray = NULL;
|
|
VARIANT * pvProp = NULL;
|
|
VARIANT vDefProp;
|
|
|
|
VariantInit(&vDefProp);
|
|
|
|
//
|
|
// Issue: How do we handle multi-valued support
|
|
//
|
|
//
|
|
// 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 = &vProp;
|
|
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
|
|
pvProp = V_VARIANTREF(&vProp);
|
|
}
|
|
|
|
if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
|
|
(V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
|
|
|
|
hr = ConvertByRefSafeArrayToVariantArray(
|
|
*pvProp,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
pvProp = pVarArray;
|
|
|
|
}else {
|
|
|
|
//
|
|
// If pvProp is a reference to a fundamental type,
|
|
// we have to dereference it once.
|
|
//
|
|
if (V_ISBYREF(pvProp)) {
|
|
hr = VariantCopyInd(&vDefProp, pvProp);
|
|
BAIL_ON_FAILURE(hr);
|
|
pvProp = &vDefProp;
|
|
}
|
|
|
|
dwNumValues = 1;
|
|
}
|
|
|
|
//
|
|
// Save it in case dwNumValues changes below (as in the case of ACLs)
|
|
//
|
|
dwNumVariants = dwNumValues;
|
|
|
|
//
|
|
// 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,
|
|
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
|
|
);
|
|
//
|
|
// 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:
|
|
|
|
VariantClear(&vDefProp);
|
|
|
|
if (pNdsDestObjects) {
|
|
NdsTypeFreeNdsObjects(
|
|
pNdsDestObjects,
|
|
dwNumValues
|
|
);
|
|
|
|
}
|
|
|
|
|
|
if (pVarArray) {
|
|
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < dwNumVariants; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::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];
|
|
DWORD dwNumValues = 0, dwNumVariants = 0;
|
|
DWORD dwFlags = 0;
|
|
|
|
VARIANT * pVarArray = NULL;
|
|
VARIANT * pvProp = NULL;
|
|
|
|
|
|
//
|
|
// 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);
|
|
|
|
|
|
|
|
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
|
|
//
|
|
//
|
|
// 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 = &vProp;
|
|
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
|
|
pvProp = V_VARIANTREF(&vProp);
|
|
}
|
|
|
|
if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
|
|
(V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
|
|
|
|
hr = ConvertByRefSafeArrayToVariantArray(
|
|
*pvProp,
|
|
&pVarArray,
|
|
&dwNumValues
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
pvProp = pVarArray;
|
|
|
|
}else {
|
|
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Save it in case dwNumValues changes below (as in the case of ACLs)
|
|
//
|
|
dwNumVariants = dwNumValues;
|
|
|
|
//
|
|
// check if the variant maps to the syntax of this property
|
|
//
|
|
|
|
hr = VarTypeToNdsTypeCopyConstruct(
|
|
dwSyntaxId,
|
|
pvProp,
|
|
&dwNumValues,
|
|
&pNdsDestObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
default:
|
|
RRETURN_EXP_IF_ERR(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
|
|
);
|
|
//
|
|
// 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 < dwNumVariants; i++) {
|
|
VariantClear(pVarArray + i);
|
|
}
|
|
FreeADsMem(pVarArray);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(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_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
void
|
|
CNDSGenObject::InitSearchPrefs()
|
|
{
|
|
_SearchPref._iScope = 1;
|
|
_SearchPref._fDerefAliases = FALSE;
|
|
_SearchPref._fAttrsOnly = FALSE;
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::get_PropertyCount(
|
|
THIS_ long FAR *plCount
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (_pPropertyCache) {
|
|
hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
|
|
}
|
|
RRETURN_EXP_IF_ERR(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_EXP_IF_ERR(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,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
error:
|
|
|
|
//
|
|
// - goto next one even if error to avoid infinite looping at a property
|
|
// which we cannot convert (e.g. schemaless server property.)
|
|
// - do not return the result of Skip() as current operation does not
|
|
// depend on the sucess of Skip().
|
|
//
|
|
|
|
Skip(1);
|
|
|
|
if (pNdsSrcObjects) {
|
|
NdsTypeFreeNdsObjects(pNdsSrcObjects, dwNumValues);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::Skip(
|
|
THIS_ long cElements
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = _pPropertyCache->skip_propindex(
|
|
cElements
|
|
);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::Reset(
|
|
|
|
)
|
|
{
|
|
_pPropertyCache->reset_propindex();
|
|
|
|
RRETURN_EXP_IF_ERR(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_EXP_IF_ERR(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,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
|
|
error:
|
|
if (pNdsSrcObjects) {
|
|
|
|
NdsTypeFreeNdsObjects(
|
|
pNdsSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(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:
|
|
BAIL_ON_FAILURE(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
|
|
);
|
|
//
|
|
// 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_EXP_IF_ERR(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;
|
|
VARIANT * pvVar = &varIndex;
|
|
|
|
//
|
|
// retrieve data object from cache; if one exis
|
|
//
|
|
|
|
if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
|
|
//
|
|
// The value is being passed in byref so we need to
|
|
// deref it for vbs stuff to work
|
|
//
|
|
pvVar = V_VARIANTREF(&varIndex);
|
|
}
|
|
|
|
switch (V_VT(pvVar)) {
|
|
|
|
case VT_BSTR:
|
|
|
|
//
|
|
// retrieve data object from cache; if one exists
|
|
//
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
|
|
hr = _pPropertyCache->unboundgetproperty(
|
|
V_BSTR(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNdsSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = _pPropertyCache->getproperty(
|
|
V_BSTR(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNdsSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = ConvertNdsValuesToVariant(
|
|
V_BSTR(pvVar),
|
|
pNdsSrcObjects,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
case VT_I4:
|
|
|
|
hr = _pPropertyCache->unboundgetproperty(
|
|
V_I4(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNdsSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
szPropName = _pPropertyCache->get_PropName(V_I4(pvVar));
|
|
|
|
hr = ConvertNdsValuesToVariant(
|
|
szPropName,
|
|
pNdsSrcObjects,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
break;
|
|
|
|
case VT_I2:
|
|
|
|
hr = _pPropertyCache->unboundgetproperty(
|
|
(DWORD)V_I2(pvVar),
|
|
&dwSyntaxId,
|
|
&dwNumValues,
|
|
&pNdsSrcObjects
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
szPropName = _pPropertyCache->get_PropName(V_I2(pvVar));
|
|
|
|
hr = ConvertNdsValuesToVariant(
|
|
szPropName,
|
|
pNdsSrcObjects,
|
|
dwSyntaxId,
|
|
dwNumValues,
|
|
pVariant
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
|
|
error:
|
|
if (pNdsSrcObjects) {
|
|
|
|
NdsTypeFreeNdsObjects(
|
|
pNdsSrcObjects,
|
|
dwNumValues
|
|
);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNDSGenObject::PurgePropertyList()
|
|
{
|
|
_pPropertyCache->flushpropcache();
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
ConvertVariantToVariantArray(
|
|
VARIANT varData,
|
|
VARIANT ** ppVarArray,
|
|
DWORD * pdwNumValues
|
|
)
|
|
{
|
|
DWORD dwNumValues = 0;
|
|
VARIANT * pVarArray = NULL;
|
|
VARIANT * pVarData = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
*ppVarArray = NULL;
|
|
*pdwNumValues = 0;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
pVarData = &varData;
|
|
if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
|
|
pVarData = V_VARIANTREF(&varData);
|
|
}
|
|
|
|
if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
|
|
(V_VT(pVarData) == (VT_VARIANT|VT_ARRAY))) {
|
|
|
|
hr = ConvertSafeArrayToVariantArray(
|
|
*pVarData,
|
|
&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();
|
|
}
|
|
|
|
VariantClear(&varValues);
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
if (pNdsDestObjects) {
|
|
|
|
NdsTypeFreeNdsObjects(
|
|
pNdsDestObjects,
|
|
dwNumNdsObjects
|
|
);
|
|
}
|
|
|
|
*ppNdsDestObjects = NULL;
|
|
*pdwNumValues = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConvertNdsValuesToVariant(
|
|
BSTR bstrPropName,
|
|
LPNDSOBJECT pNdsSrcObjects,
|
|
DWORD dwSyntaxId,
|
|
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 = (dwSyntaxId >= g_cMapNdsTypeToADsType) ?
|
|
ADSTYPE_INVALID :
|
|
g_MapNdsTypeToADsType[dwSyntaxId];
|
|
}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;
|
|
|
|
error:
|
|
|
|
if (pAdsValues) {
|
|
AdsFreeAdsValues(
|
|
pAdsValues,
|
|
dwNumValues
|
|
);
|
|
FreeADsMem( pAdsValues );
|
|
}
|
|
|
|
VariantClear(&varData);
|
|
|
|
RRETURN(hr);
|
|
}
|