//---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1995
//
//  File:  cggi.cxx
//
//  Contents:  This file contains the Group Object's
               IADsGroup and IADsGroupOperation methods
//
//  History:   11-1-95     krishnag    Created.
//
//----------------------------------------------------------------------------
#include "nds.hxx"
#pragma hdrstop


BOOL
VerifyIfMember(
    BSTR bstrMember,
    VARIANT * VariantArray,
    ULONG cElementFetched
    );




//  Class CNDSGroup


STDMETHODIMP CNDSGroup::get_Description(THIS_ BSTR FAR* retval)
{
    GET_PROPERTY_BSTR((IADsGroup *)this,Description);
}

STDMETHODIMP CNDSGroup::put_Description(THIS_ BSTR bstrDescription)
{
    PUT_PROPERTY_BSTR((IADsGroup *)this,Description);
}


STDMETHODIMP
CNDSGroup::Members(
    THIS_ IADsMembers FAR* FAR* ppMembers
    )
{
    VARIANT varProp;
    HRESULT hr = S_OK;
    BSTR bstrADsPath = NULL;

    if (!ppMembers) {
        RRETURN(E_ADS_BAD_PARAMETER);
    }

    VariantInit(&varProp);

    hr = _pADs->GetEx(L"Member", &varProp);

    //
    // Do not bail out on failure here if you could not find
    // any data set for the Members property. You need to
    // pass it all the way through and on enumeration
    // return nothing.
    //

    if (hr == E_ADS_PROPERTY_NOT_FOUND) {
        SAFEARRAY *aList = NULL;

        VariantInit(&varProp);
    
        SAFEARRAYBOUND aBound;
    
        aBound.lLbound = 0;
        aBound.cElements = 0;
    
        aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
    
        if ( aList == NULL ) {
            hr = E_OUTOFMEMORY;
            BAIL_ON_FAILURE(hr);
        }
    
        V_VT(&varProp) = VT_ARRAY | VT_VARIANT;
        V_ARRAY(&varProp) = aList;
    }
    else {
        BAIL_ON_FAILURE(hr);
    }

    hr = _pADs->get_ADsPath(&bstrADsPath);

    hr = CNDSGroupCollection::CreateGroupCollection(
                    bstrADsPath,
                    varProp,
                    _Credentials,
                    IID_IADsMembers,
                    (void **)ppMembers
                    );

    BAIL_ON_FAILURE(hr);

error:

    if (bstrADsPath) {
        ADsFreeString(bstrADsPath);
    }

    VariantClear(&varProp);

    RRETURN(hr);
}




STDMETHODIMP
CNDSGroup::IsMember(
    THIS_ BSTR bstrMember,
    VARIANT_BOOL FAR* bMember
    )
{
    IADsMembers FAR * pMembers = NULL;
    IUnknown FAR * pUnknown = NULL;
    IEnumVARIANT FAR * pEnumVar = NULL;
    DWORD i = 0;
    HRESULT hr = S_OK;
    VARIANT_BOOL fMember = FALSE;
    VARIANT VariantArray[10];
    BOOL fContinue = TRUE;
    ULONG cElementFetched = 0;

    if (!bstrMember) {
        RRETURN(E_ADS_BAD_PARAMETER);
    }

    if (!bMember) {
        RRETURN(E_ADS_BAD_PARAMETER);
    }

    hr = Members(
            &pMembers
            );
    BAIL_ON_FAILURE(hr);

    hr = pMembers->get__NewEnum(
                &pUnknown
                );
	//
	// If it has no members, we will return FALSE
	//
	if (hr == E_FAIL) {
		hr = S_OK;
		goto error;
	}

    hr = pUnknown->QueryInterface(
                IID_IEnumVARIANT,
                (void **)&pEnumVar
                );
    BAIL_ON_FAILURE(hr);


    while (fContinue) {

        hr = pEnumVar->Next(
                    10,
                    VariantArray,
                    &cElementFetched
                    );

        if (hr == S_FALSE) {
            fContinue = FALSE;

            //
            // Reset hr to S_OK, we want to return success
            //

            hr = S_OK;
        }


        fMember = (VARIANT_BOOL)VerifyIfMember(
                        bstrMember,
                        VariantArray,
                        cElementFetched
                        );
        if (fMember) {

            fContinue = FALSE;
        }



        for (i = 0; i < cElementFetched; i++ ) {

            IDispatch *pDispatch = NULL;

            pDispatch = VariantArray[i].pdispVal;
            pDispatch->Release();

        }

        memset(VariantArray, 0, sizeof(VARIANT)*10);

    }

error:

    *bMember = fMember? VARIANT_TRUE: VARIANT_FALSE;

    if (pEnumVar) {
        pEnumVar->Release();
    }

    if (pUnknown) {
        pUnknown->Release();
    }

    if (pMembers) {
        pMembers->Release();
    }


    RRETURN(hr);
}


BOOL
VerifyIfMember(
    BSTR bstrMember,
    VARIANT * VariantArray,
    ULONG cElementFetched
    )
{
    DWORD i = 0;
    HRESULT hr = S_OK;
    IADs FAR * pObject = NULL;
    IDispatch FAR * pDispatch = NULL;

    for (i = 0; i < cElementFetched; i++ ) {

        IDispatch *pDispatch = NULL;
        BSTR       bstrName = NULL;

        pDispatch = VariantArray[i].pdispVal;

        hr = pDispatch->QueryInterface(
                    IID_IADs,
                    (VOID **) &pObject
                    );
        BAIL_ON_FAILURE(hr);

        hr = pObject->get_ADsPath(&bstrName);
        BAIL_ON_FAILURE(hr);

        if (!_wcsicmp(bstrName, bstrMember)) {

            SysFreeString(bstrName);
            bstrName = NULL;

            pObject->Release();

           return(TRUE);

        }

        SysFreeString(bstrName);
        bstrName = NULL;

        pObject->Release();

    }

error:

    return(FALSE);

}


STDMETHODIMP
CNDSGroup::Add(THIS_ BSTR bstrNewItem)
{
    HRESULT hr = S_OK;

    WCHAR szNDSUserPathName[MAX_PATH];
    WCHAR szNDSUserTreeName[MAX_PATH];
    IUnknown * pUnknown = NULL;
    IADs * pUser = NULL;

    WCHAR szNDSGroupPathName[MAX_PATH];
    WCHAR szNDSGroupTreeName[MAX_PATH];
    BSTR bstrPathName = NULL;

    hr = ::GetObject(
                bstrNewItem,
                _Credentials,
                (void **)&pUnknown
                );
    BAIL_ON_FAILURE(hr);

    hr = pUnknown->QueryInterface(IID_IADs, (void **)&pUser);
    BAIL_ON_FAILURE(hr);

    hr = BuildNDSPathFromADsPath(
                bstrNewItem,
                szNDSUserTreeName,
                szNDSUserPathName
                );
    BAIL_ON_FAILURE(hr);

    hr = _pADs->get_ADsPath(&bstrPathName);
    BAIL_ON_FAILURE(hr);

    hr = BuildNDSPathFromADsPath(
                bstrPathName,
                szNDSGroupTreeName,
                szNDSGroupPathName
                );
    BAIL_ON_FAILURE(hr);


    hr = AddEntry(_pADs, L"Member",szNDSUserPathName);
    BAIL_ON_FAILURE(hr);

    // hr = AddEntry(_pADs, L"Equivalent To Me", szNDSUserPathName);
    // BAIL_ON_FAILURE(hr);

    hr = AddEntry(pUser, L"Group Membership", szNDSGroupPathName);
    BAIL_ON_FAILURE(hr);

error:

    if (bstrPathName) {
        ADsFreeString(bstrPathName);
    }

    if (pUnknown) {
        pUnknown->Release();
    }

    if (pUser) {
        pUser->Release();
    }

    RRETURN(hr);
}


STDMETHODIMP
CNDSGroup::Remove(THIS_ BSTR bstrNewItem)
{
    HRESULT hr = S_OK;

    WCHAR szNDSUserPathName[MAX_PATH];
    WCHAR szNDSUserTreeName[MAX_PATH];
    IUnknown * pUnknown = NULL;
    IADs * pUser = NULL;

    WCHAR szNDSGroupPathName[MAX_PATH];
    WCHAR szNDSGroupTreeName[MAX_PATH];
    BSTR bstrPathName = NULL;

    hr = ::GetObject(
                bstrNewItem,
                _Credentials,
                (void **)&pUnknown
                );

    BAIL_ON_FAILURE(hr);

    hr = pUnknown->QueryInterface(IID_IADs, (void **)&pUser);
    BAIL_ON_FAILURE(hr);

    hr = BuildNDSPathFromADsPath(
                bstrNewItem,
                szNDSUserTreeName,
                szNDSUserPathName
                );
    BAIL_ON_FAILURE(hr);

    hr = _pADs->get_ADsPath(&bstrPathName);
    BAIL_ON_FAILURE(hr);

    hr = BuildNDSPathFromADsPath(
                bstrPathName,
                szNDSGroupTreeName,
                szNDSGroupPathName
                );
    BAIL_ON_FAILURE(hr);


    hr = RemoveEntry(_pADs, L"Member",szNDSUserPathName);
    BAIL_ON_FAILURE(hr);

    // hr = RemoveEntry(_pADs, L"Equivalent To Me", szNDSUserPathName);
    // BAIL_ON_FAILURE(hr);

    hr = RemoveEntry(pUser, L"Group Membership", szNDSGroupPathName);
    BAIL_ON_FAILURE(hr);

error:

    if (bstrPathName) {
        ADsFreeString(bstrPathName);
    }

    if (pUnknown) {
        pUnknown->Release();
    }

    if (pUser) {
        pUser->Release();
    }

    RRETURN(hr);
}


HRESULT
AddEntry(
    IADs * pADs,
    LPWSTR pszAttribute,
    LPWSTR pszValue
    )
{

    HRESULT hr = S_OK;
    VARIANT vOldValue;
    VARIANT vNewValue;
    SAFEARRAY * pArray = NULL;

    VariantInit(&vOldValue);
    VariantInit(&vNewValue);

#if defined(BUILD_FOR_NT40)

    hr = pADs->Get(pszAttribute, &vOldValue);
    if (hr == E_ADS_PROPERTY_NOT_FOUND) {


        VariantInit(&vNewValue);
        V_BSTR(&vNewValue) = SysAllocString(pszValue);
        V_VT(&vNewValue) =  VT_BSTR;

        hr = pADs->Put(pszAttribute, vNewValue);
        BAIL_ON_FAILURE(hr);

    }else{

        hr = VarAddEntry(
                    pszValue,
                    vOldValue,
                    &vNewValue
                    );
        BAIL_ON_FAILURE(hr);

        hr = pADs->Put(pszAttribute, vNewValue);
        BAIL_ON_FAILURE(hr);
    }
#else

    //
    // NT5 supports appending values. So we don't need to read everything.
    // append ourselves and write everything
    //

    SAFEARRAYBOUND sabNewArray;
    int i;
    VARIANT v;

    sabNewArray.cElements = 1;
    sabNewArray.lLbound = 0;

    pArray = SafeArrayCreate(
                    VT_VARIANT,
                    1,
                    &sabNewArray
                    );
    if (!pArray) {
        hr = E_OUTOFMEMORY;
        BAIL_ON_FAILURE(hr);
    }

    VariantInit(&v);

    V_BSTR(&v) = SysAllocString(pszValue);
    V_VT(&v) =  VT_BSTR;

    i = 0;
    hr = SafeArrayPutElement(
                pArray,
                (long *)&i,
                (void *)&v
                );

    VariantClear(&v);

    BAIL_ON_FAILURE(hr);

    V_VT(&vNewValue) = VT_ARRAY | VT_VARIANT;
    V_ARRAY(&vNewValue) = pArray;

    hr = pADs->PutEx(ADS_PROPERTY_APPEND, pszAttribute, vNewValue);
    BAIL_ON_FAILURE(hr);

#endif

    hr = pADs->SetInfo();
    BAIL_ON_FAILURE(hr);

error:

    VariantClear(&vOldValue);
    VariantClear(&vNewValue);

    RRETURN(hr);
}






HRESULT
RemoveEntry(
    IADs * pADs,
    LPWSTR pszAttribute,
    LPWSTR pszValue
    )
{
    HRESULT hr = S_OK;
    VARIANT vOldValue;
    VARIANT vNewValue;
    SAFEARRAY * pArray = NULL;

    VariantInit(&vOldValue);
    VariantInit(&vNewValue);

#if defined(BUILD_FOR_NT40)

    hr = pADs->Get(pszAttribute, &vOldValue);
    BAIL_ON_FAILURE(hr);

    hr = VarRemoveEntry(
                pszValue,
                vOldValue,
                &vNewValue
                );
    BAIL_ON_FAILURE(hr);


    if (V_VT(&vNewValue) == VT_EMPTY) {
        hr = pADs->PutEx(ADS_PROPERTY_CLEAR, pszAttribute, vNewValue);
    }else {
        hr = pADs->Put(pszAttribute, vNewValue);

    }
    BAIL_ON_FAILURE(hr);

#else

    SAFEARRAYBOUND sabNewArray;
    VARIANT  v;
    int i;

    //
    // NT5 supports deleting values. So we don't need to read everything.
    // delete ourselves and write everything - Very inefficient!
    //

    sabNewArray.cElements = 1;
    sabNewArray.lLbound = 0;

    pArray = SafeArrayCreate(
                    VT_VARIANT,
                    1,
                    &sabNewArray
                    );
    if (!pArray) {
        hr = E_OUTOFMEMORY;
        BAIL_ON_FAILURE(hr);
    }

    VariantInit(&v);

    V_BSTR(&v) = SysAllocString(pszValue);
    V_VT(&v) =  VT_BSTR;

    i = 0;
    hr = SafeArrayPutElement(
                pArray,
                (long *)&i,
                (void *)&v
                );

    VariantClear(&v);

    BAIL_ON_FAILURE(hr);

    V_VT(&vNewValue) = VT_ARRAY | VT_VARIANT;
    V_ARRAY(&vNewValue) = pArray;

    hr = pADs->PutEx(ADS_PROPERTY_DELETE, pszAttribute, vNewValue);
    BAIL_ON_FAILURE(hr);

#endif

    hr = pADs->SetInfo();
    BAIL_ON_FAILURE(hr);

error:

    VariantClear(&vOldValue);
    VariantClear(&vNewValue);

    RRETURN(hr);
}


HRESULT
VarFindEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers
    )
{
    HRESULT hr = S_OK;
    DWORD dwSLBound = 0;
    DWORD dwSUBound = 0;
    DWORD i = 0;
    VARIANT v;

    if (!(V_VT(&varMembers) ==  (VT_VARIANT|VT_ARRAY))) {
        return(E_FAIL);
    }

    //
    // Check that there is only one dimension in this array
    //

    if ((V_ARRAY(&varMembers))->cDims != 1) {
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }
    //
    // Check that there is atleast one element in this array
    //

    if ((V_ARRAY(&varMembers))->rgsabound[0].cElements == 0){
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }

    //
    // We know that this is a valid single dimension array
    //

    hr = SafeArrayGetLBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSLBound
                            );
    BAIL_ON_FAILURE(hr);

    hr = SafeArrayGetUBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSUBound
                            );
    BAIL_ON_FAILURE(hr);

    for (i = dwSLBound; i <= dwSUBound; i++) {
        VariantInit(&v);
        hr = SafeArrayGetElement(V_ARRAY(&varMembers),
                                (long FAR *)&i,
                                &v
                                );

        if (!_wcsicmp(V_BSTR(&v), pszNDSPathName)) {
            VariantClear(&v);
            RRETURN(S_OK);
        }

        VariantClear(&v);
    }

error:

    RRETURN(E_FAIL);
}

HRESULT
VarMultipleAddEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{   SAFEARRAYBOUND sabNewArray;
    SAFEARRAY * pFilter = NULL;
    HRESULT hr = S_OK;
    DWORD dwSLBound = 0;
    DWORD dwSUBound = 0;
    DWORD i = 0;
    VARIANT v;

    VariantInit(pvarNewMembers);

    if (!(V_VT(&varMembers) == (VT_VARIANT|VT_ARRAY))) {
        return(E_FAIL);
    }

    //
    // Check that there is only one dimension in this array
    //

    if ((V_ARRAY(&varMembers))->cDims != 1) {
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }
    //
    // Check that there is atleast one element in this array
    //

    if ((V_ARRAY(&varMembers))->rgsabound[0].cElements == 0){
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }

    //
    // We know that this is a valid single dimension array
    //

    hr = SafeArrayGetLBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSLBound
                            );
    BAIL_ON_FAILURE(hr);

    hr = SafeArrayGetUBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSUBound
                            );
    BAIL_ON_FAILURE(hr);


    sabNewArray.cElements = (dwSUBound - dwSLBound + 1) + 1;
    sabNewArray.lLbound = dwSLBound;

    pFilter = SafeArrayCreate(
                    VT_VARIANT,
                    1,
                    &sabNewArray
                    );


    if (!pFilter) {
        hr = E_OUTOFMEMORY;
        BAIL_ON_FAILURE(hr);
    }

    for (i = dwSLBound; i <= dwSUBound; i++) {

        VariantInit(&v);

        hr = SafeArrayGetElement(
                    V_ARRAY(&varMembers),
                    (long FAR *)&i,
                    &v
                    );
        BAIL_ON_FAILURE(hr);

        hr = SafeArrayPutElement(
                pFilter,
                (long*)&i,
                (void *)&v
                );

        VariantClear(&v);
        BAIL_ON_FAILURE(hr);

    }

    VariantInit(&v);
    V_VT(&v) = VT_BSTR;
    V_BSTR(&v) = SysAllocString(pszNDSPathName);

    hr = SafeArrayPutElement(
                pFilter,
                (long *)&i,
                (void *)&v
                );
    VariantClear(&v);
    BAIL_ON_FAILURE(hr);

    V_VT(pvarNewMembers) = VT_ARRAY | VT_VARIANT;
    V_ARRAY(pvarNewMembers) = pFilter;

    RRETURN(S_OK);

error:

    if (pFilter) {
        SafeArrayDestroy(pFilter);
    }

    RRETURN(hr);
}

HRESULT
VarMultipleRemoveEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{   SAFEARRAYBOUND sabNewArray;
    SAFEARRAY * pFilter = NULL;
    HRESULT hr = S_OK;
    DWORD dwSLBound = 0;
    DWORD dwSUBound = 0;
    DWORD i = 0;
    DWORD dwNewCount = 0;
    VARIANT v;

    VariantInit(pvarNewMembers);


    if(!(V_VT(&varMembers) == (VT_VARIANT|VT_ARRAY))){
        return(E_FAIL);
    }

    //
    // Check that there is only one dimension in this array
    //

    if ((V_ARRAY(&varMembers))->cDims != 1) {
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }
    //
    // Check that there is atleast one element in this array
    //

    if ((V_ARRAY(&varMembers))->rgsabound[0].cElements == 0){
        hr = E_FAIL;
        BAIL_ON_FAILURE(hr);
    }

    //
    // We know that this is a valid single dimension array
    //

    hr = SafeArrayGetLBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSLBound
                            );
    BAIL_ON_FAILURE(hr);

    hr = SafeArrayGetUBound(V_ARRAY(&varMembers),
                            1,
                            (long FAR *)&dwSUBound
                            );
    BAIL_ON_FAILURE(hr);


    sabNewArray.cElements = (dwSUBound - dwSLBound);
    sabNewArray.lLbound = dwSLBound;

    pFilter = SafeArrayCreate(
                    VT_VARIANT,
                    1,
                    &sabNewArray
                    );


    if (!pFilter) {
        hr = E_OUTOFMEMORY;
        BAIL_ON_FAILURE(hr);
    }

    for (i = dwSLBound, dwNewCount = dwSLBound; i <= dwSUBound; i++) {
        VariantInit(&v);
        hr = SafeArrayGetElement(
                    V_ARRAY(&varMembers),
                    (long FAR *)&i,
                    &v
                    );

        if (!_wcsicmp(V_BSTR(&v), pszNDSPathName)) {

            VariantClear(&v);
            //
            // skip this entry
            //
            continue;

        }
        hr = SafeArrayPutElement(
                pFilter,
                (long*)&dwNewCount,
                (void *)&v
                );

        VariantClear(&v);
        BAIL_ON_FAILURE(hr);

        dwNewCount++;

    }

    V_VT(pvarNewMembers) = VT_ARRAY | VT_VARIANT;
    V_ARRAY(pvarNewMembers) = pFilter;

    RRETURN(S_OK);


error:

    if (pFilter) {
        SafeArrayDestroy(pFilter);
    }

    RRETURN(hr);
}




HRESULT
VarSingleAddEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{   SAFEARRAYBOUND sabNewArray;
    SAFEARRAY * pFilter = NULL;
    HRESULT hr = S_OK;
    DWORD dwSLBound = 0;
    DWORD dwSUBound = 0;
    DWORD i = 0;
    VARIANT v;

    VariantInit(pvarNewMembers);

    if(!((V_VT(&varMembers) & VT_TYPEMASK) == VT_BSTR)){
        return(E_FAIL);
    }

    sabNewArray.cElements = (1) + 1;
    sabNewArray.lLbound = 0;

    pFilter = SafeArrayCreate(
                    VT_VARIANT,
                    1,
                    &sabNewArray
                    );
    if (!pFilter) {
        hr = E_OUTOFMEMORY;
        BAIL_ON_FAILURE(hr);
    }

    i = 0;
    hr = SafeArrayPutElement(
                pFilter,
                (long *)&i,
                (void *)&varMembers
                );
    BAIL_ON_FAILURE(hr);

    i++;

    VariantInit(&v);
    V_VT(&v) = VT_BSTR;
    V_BSTR(&v) = SysAllocString(pszNDSPathName);

    hr = SafeArrayPutElement(
                pFilter,
                (long *)&i,
                (void *)&v
                );
    VariantClear(&v);
    BAIL_ON_FAILURE(hr);

    V_VT(pvarNewMembers) = VT_ARRAY | VT_VARIANT;
    V_ARRAY(pvarNewMembers) = pFilter;

    RRETURN(S_OK);

error:

    if (pFilter) {
        SafeArrayDestroy(pFilter);
    }

    RRETURN(hr);
}



HRESULT
VarSingleRemoveEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{
    HRESULT hr = S_OK;

    VariantInit(pvarNewMembers);

    if(!((V_VT(&varMembers) & VT_TYPEMASK) == VT_BSTR)){
        return(E_FAIL);
    }

    V_VT(pvarNewMembers) = VT_EMPTY;
    V_BSTR(pvarNewMembers) = NULL;

    RRETURN(hr);
}


HRESULT
VarRemoveEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{
    HRESULT hr = S_OK;

    if (V_VT(&varMembers) == (VT_VARIANT|VT_ARRAY)) {

        hr = VarMultipleRemoveEntry(
                pszNDSPathName,
                varMembers,
                pvarNewMembers
                );
        RRETURN(hr);

    }else if (V_VT(&varMembers) == VT_BSTR){

        hr = VarSingleRemoveEntry(
                pszNDSPathName,
                varMembers,
                pvarNewMembers
                );

        RRETURN(hr);

    }else {

        RRETURN(E_FAIL);
    }
}


HRESULT
VarAddEntry(
    LPWSTR pszNDSPathName,
    VARIANT varMembers,
    VARIANT * pvarNewMembers
    )
{
    HRESULT hr = S_OK;

    if (V_VT(&varMembers) == (VT_VARIANT|VT_ARRAY)){

        hr = VarMultipleAddEntry(
                pszNDSPathName,
                varMembers,
                pvarNewMembers
                );
        RRETURN(hr);

    }else if ((V_VT(&varMembers) & VT_TYPEMASK) == VT_BSTR){

        hr = VarSingleAddEntry(
                pszNDSPathName,
                varMembers,
                pvarNewMembers
                );

        RRETURN(hr);

    }else {

        RRETURN(E_FAIL);
    }
}

