CGENOBJ.CPP
/*++  
 
Copyright (c) 1996 Microsoft Corporation 
 
Module Name: 
 
    CGenObj.cpp 
 
Abstract: 
 
    Microsoft ADs DS Provider Generic Object 
 
Author: 
 
Environment: 
 
    User mode 
 
Revision History : 
 
--*/ 
#include "adssmp.h" 
#pragma hdrstop 
 
DEFINE_IDispatch_Implementation(CSampleDSGenObject) 
DEFINE_IADs_Implementation(CSampleDSGenObject) 
 
 
CSampleDSGenObject::CSampleDSGenObject():_pPropertyCache(NULL) 
{ 
    VariantInit(&_vFilter); 
} 
 
HRESULT 
CSampleDSGenObject::CreateGenericObject( 
    BSTR Parent, 
    BSTR CommonName, 
    BSTR ClassName, 
    DWORD dwObjectState, 
    REFIID riid, 
    void **ppvObj 
    ) 
{ 
    CSampleDSGenObject FAR * pGenObject = NULL; 
    HRESULT hr = S_OK; 
 
    hr = AllocateGenObject(&pGenObject); 
    BAIL_ON_FAILURE(hr); 
 
    hr = pGenObject->InitializeCoreObject( 
                Parent, 
                CommonName, 
                ClassName, 
                L"", 
                CLSID_SampleDSGenObject, 
                dwObjectState 
                ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = pGenObject->QueryInterface(riid, ppvObj); 
    BAIL_ON_FAILURE(hr); 
 
    pGenObject->Release(); 
 
    RRETURN(hr); 
 
error: 
 
    delete pGenObject; 
 
    RRETURN(hr); 
} 
 
CSampleDSGenObject::~CSampleDSGenObject( ) 
{ 
 
    delete _pDispMgr; 
    delete _pPropertyCache; 
 
} 
 
STDMETHODIMP 
CSampleDSGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv) 
{ 
    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 
CSampleDSGenObject::SetInfo() 
{ 
    HRESULT hr = S_OK; 
 
    if (GetObjectState() == ADS_OBJECT_UNBOUND) { 
 
        hr = SampleDSCreateObject(); 
        BAIL_ON_FAILURE(hr); 
 
        // 
        // If the create succeded, set the object type to bound 
        // 
 
        SetObjectState(ADS_OBJECT_BOUND); 
 
    }else { 
 
        hr = SampleDSSetObject(); 
        BAIL_ON_FAILURE(hr); 
    } 
 
error: 
 
    RRETURN(hr); 
} 
 
 
HRESULT 
CSampleDSGenObject::SampleDSSetObject() 
{ 
    WCHAR szSampleDSPathName[MAX_PATH]; 
    HANDLE hObject = NULL; 
    HRESULT hr = S_OK; 
    HANDLE hOperationData = NULL; 
 
 
    hr = BuildDSPathFromADsPath( 
                _ADsPath, 
                szSampleDSPathName 
                ); 
    BAIL_ON_FAILURE(hr); 
 
     
    hr = SampleDSOpenObject( 
                    szSampleDSPathName, 
                    &hObject, 
                    NULL, 
                    REG_DS 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSCreateBuffer(&hOperationData); 
    BAIL_ON_FAILURE(hr); 
     
    hr = _pPropertyCache->SampleDSMarshallProperties( 
                            hOperationData 
                            ); 
     
    BAIL_ON_FAILURE(hr); 
    hr = SampleDSModifyObject(hObject, 
                              hOperationData 
                             ); 
error: 
    if (hObject) { 
        hr = SampleDSCloseObject(hObject); 
    } 
    if (hOperationData) { 
        SampleDSFreeBuffer(hOperationData); 
    } 
    RRETURN(hr); 
} 
 
HRESULT 
CSampleDSGenObject::SampleDSCreateObject() 
{ 
    WCHAR szSampleDSParentName[MAX_PATH]; 
    HANDLE hOperationData = NULL; 
    HANDLE hObject = NULL; 
    HRESULT hr = S_OK; 
 
    hr = BuildDSPathFromADsPath( 
                _Parent, 
                szSampleDSParentName 
                ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSOpenObject( 
                    szSampleDSParentName, 
                    &hObject, 
                    NULL, 
                    REG_DS 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSCreateBuffer(&hOperationData); 
    BAIL_ON_FAILURE(hr); 
     
    hr = _pPropertyCache->SampleDSMarshallProperties( 
                            hOperationData 
                            ); 
    BAIL_ON_FAILURE(hr); 
     
    hr = SampleDSAddObject( 
                hObject, 
                _Name, 
                _ADsClass, 
                hOperationData 
                ); 
     
error: 
    if (hObject) { 
        hr = SampleDSCloseObject(hObject); 
    } 
    if (hOperationData) { 
        SampleDSFreeBuffer(hOperationData); 
    } 
 
    RRETURN(hr); 
} 
 
 
HRESULT 
CSampleDSGenObject::GetInfo() 
{ 
    RRETURN(GetInfo(TRUE)); 
} 
 
HRESULT 
CSampleDSGenObject::GetInfo( 
    BOOL fExplicit 
){ 
    HANDLE hObject = NULL; 
    HRESULT hr = S_OK; 
    WCHAR szDSPathName[MAX_PATH]; 
    HANDLE hOperationData = NULL; 
 
    if (GetObjectState() == ADS_OBJECT_UNBOUND) { 
        hr = E_ADS_OBJECT_UNBOUND; 
        BAIL_ON_FAILURE(hr); 
    } 
 
    hr = BuildDSPathFromADsPath( 
                _ADsPath, 
                szDSPathName 
                ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSOpenObject( 
                    szDSPathName, 
                    &hObject, 
                    NULL, 
                    REG_DS 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSReadObject( 
        hObject, 
        &hOperationData 
    ); 
    BAIL_ON_FAILURE(hr); 
             
    hr = _pPropertyCache->SampleDSUnMarshallProperties(hOperationData, 
                                                       fExplicit 
                                                       ); 
    BAIL_ON_FAILURE(hr); 
error: 
 
    if (hObject) { 
        hr = SampleDSCloseObject(hObject); 
    } 
    if (hOperationData) { 
        SampleDSFreeBuffer(hOperationData); 
    } 
 
    RRETURN(hr); 
} 
 
/* IADsContainer methods */ 
 
STDMETHODIMP 
CSampleDSGenObject::get_Count(long FAR* retval) 
{ 
    RRETURN(E_NOTIMPL); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::get_Filter(THIS_ VARIANT FAR* pVar) 
{ 
    VariantInit(pVar); 
    RRETURN(VariantCopy(pVar, &_vFilter)); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::put_Filter(THIS_ VARIANT Var) 
{ 
    RRETURN(VariantCopy(&_vFilter, &Var)); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::put_Hints(THIS_ VARIANT Var) 
{ 
    RRETURN( E_NOTIMPL); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::get_Hints(THIS_ VARIANT FAR* pVar) 
{ 
    RRETURN(E_NOTIMPL); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::GetObject( 
    BSTR ClassName, 
    BSTR RelativeName, 
    IDispatch * FAR* ppObject 
    ) 
{ 
    RRETURN(::RelativeGetObject(_ADsPath, 
                                ClassName, 
                                RelativeName, 
                                ppObject, 
                                FALSE)); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::get__NewEnum( 
    THIS_ IUnknown * FAR* retval 
    ) 
{ 
    HRESULT hr; 
    IUnknown FAR* punkEnum=NULL; 
    IEnumVARIANT * penum = NULL; 
 
 
    *retval = NULL; 
 
    hr = CSampleDSGenObjectEnum::Create( 
                (CSampleDSGenObjectEnum **)&penum, 
                _ADsPath, 
                _vFilter 
                ); 
    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 
CSampleDSGenObject::Create( 
    THIS_ BSTR ClassName, 
    BSTR RelativeName, 
    IDispatch * FAR* ppObject 
    ) 
{ 
    HRESULT hr = S_OK; 
    IADs * pADs  = NULL; 
    WCHAR szDSTreeName[MAX_PATH]; 
    DWORD dwSyntaxId = 0; 
 
    // 
    // Get the TreeName for this object 
    // 
 
    hr = BuildDSTreeNameFromADsPath( 
                _ADsPath, 
                szDSTreeName 
                ); 
    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 = CSampleDSGenObject::CreateGenericObject( 
                    _ADsPath, 
                    RelativeName, 
                    ClassName, 
                    ADS_OBJECT_UNBOUND, 
                    IID_IDispatch, 
                    (void **)ppObject 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
error: 
 
    RRETURN(hr); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::Delete( 
    THIS_ BSTR bstrClassName, 
    BSTR bstrRelativeName 
    ) 
{ 
    WCHAR szDSPathName[MAX_PATH]; 
    HRESULT hr = S_OK; 
    DWORD dwStatus = 0; 
    HANDLE hParentObject = NULL; 
 
    hr = BuildDSPathFromADsPath( 
                _ADsPath, 
                szDSPathName 
                ); 
    BAIL_ON_FAILURE(hr); 
     
    hr = SampleDSOpenObject( 
                    szDSPathName, 
                    &hParentObject, 
                    NULL, 
                    REG_DS 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
    hr= SampleDSRemoveObject( 
                hParentObject, 
                bstrRelativeName); 
    BAIL_ON_FAILURE(hr); 
 
 
error: 
    if (hParentObject) { 
        dwStatus = SampleDSCloseObject(hParentObject); 
    } 
    RRETURN(hr); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::CopyHere( 
    THIS_ BSTR SourceName, 
    BSTR NewName, 
    IDispatch * FAR* ppObject 
    ) 
{ 
    RRETURN(E_NOTIMPL); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::MoveHere( 
    THIS_ BSTR SourceName, 
    BSTR NewName, 
    IDispatch * FAR* ppObject 
    ) 
{ 
    RRETURN(E_NOTIMPL); 
} 
 
HRESULT 
CSampleDSGenObject::AllocateGenObject(CSampleDSGenObject ** ppGenObject) 
{ 
    CSampleDSGenObject FAR * pGenObject = NULL; 
    CDispatchMgr FAR * pDispMgr = NULL; 
    CPropertyCache FAR * pPropertyCache = NULL; 
    HRESULT hr = S_OK; 
 
    pGenObject = new CSampleDSGenObject(); 
    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 = CPropertyCache::createpropertycache( 
                        (CCoreADsObject FAR *)pGenObject, 
                        &pPropertyCache 
                        ); 
    BAIL_ON_FAILURE(hr); 
 
 
 
    pGenObject->_pPropertyCache = pPropertyCache; 
    pGenObject->_pDispMgr = pDispMgr; 
    *ppGenObject = pGenObject; 
     
    RRETURN(hr); 
 
error: 
    delete  pDispMgr; 
    RRETURN(hr); 
} 
 
STDMETHODIMP 
CSampleDSGenObject::Get( 
    THIS_ BSTR bstrName, 
    VARIANT FAR* pvProp 
    ) 
{ 
    HRESULT hr = S_OK; 
    DWORD dwSyntaxId; 
    DWORD dwNumValues; 
    LPSampleDSOBJECT 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 = SampleDSTypeToVarTypeCopyConstruct( 
                pNdsSrcObjects, 
                dwNumValues, 
                pvProp 
                ); 
    BAIL_ON_FAILURE(hr); 
 
error: 
    if (pNdsSrcObjects) { 
 
        SampleDSTypeFreeSampleDSObjects( 
            pNdsSrcObjects, 
            dwNumValues 
            ); 
    } 
 
    RRETURN(hr); 
} 
 
 
STDMETHODIMP 
CSampleDSGenObject::Put( 
    THIS_ BSTR bstrName, 
    VARIANT vProp 
    ) 
{ 
    HRESULT hr = S_OK; 
    DWORD dwSyntaxId  = 0; 
    DWORD dwIndex = 0; 
    LPSampleDSOBJECT pNdsDestObjects = NULL; 
    WCHAR szSampleDSTreeName[MAX_PATH]; 
    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 { 
 
        dwNumValues = 1; 
        pvProp = &vProp; 
    } 
 
    // 
    // Get the TreeName for this object 
    // 
 
    hr = BuildDSPathFromADsPath( 
                _ADsPath, 
                szSampleDSTreeName 
                ); 
    BAIL_ON_FAILURE(hr); 
     
    // 
    // check if the variant maps to the syntax of this property 
    // 
    switch (vProp.vt) { 
        case VT_BSTR: 
                dwSyntaxId = SampleDS_DATATYPE_1; 
                break; 
        case VT_I4: 
                dwSyntaxId = SampleDS_DATATYPE_2; 
                break; 
        default: 
                hr = E_FAIL; 
                goto error; 
        } 
                hr = VarTypeToSampleDSTypeCopyConstruct( 
                    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, 
                    dwSyntaxId, 
                    dwNumValues, 
                    pNdsDestObjects 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
error: 
 
    if (pNdsDestObjects) { 
        SampleDSTypeFreeSampleDSObjects( 
                pNdsDestObjects, 
                dwNumValues 
                ); 
 
    } 
 
 
    if (pVarArray) { 
 
        DWORD i = 0; 
 
        for (i = 0; i < dwNumValues; i++) { 
            VariantClear(pVarArray + i); 
        } 
        FreeProvMem(pVarArray); 
    } 
 
    RRETURN(hr); 
} 
 
 
HRESULT 
ConvertSafeArrayToVariantArray( 
    VARIANT varSafeArray, 
    VARIANT ** ppVarArray, 
    PDWORD pdwNumVariants 
    ) 
{ 
    HRESULT hr = S_OK; 
    DWORD dwSLBound = 0; 
    DWORD dwSUBound = 0; 
    DWORD i = 0; 
    DWORD dwNumVariants = 0; 
    VARIANT * pVarArray = NULL; 
 
    *pdwNumVariants = 0; 
    *ppVarArray  = 0; 
 
    if(!((V_VT(&varSafeArray) &  VT_VARIANT) &&  V_ISARRAY(&varSafeArray))) { 
        return(E_FAIL); 
    } 
 
    // 
    // Check that there is only one dimension in this array 
    // 
 
    if ((V_ARRAY(&varSafeArray))->cDims != 1) { 
        hr = E_FAIL; 
        BAIL_ON_FAILURE(hr); 
    } 
    // 
    // Check that there is atleast one element in this array 
    // 
 
    if ((V_ARRAY(&varSafeArray))->rgsabound[0].cElements == 0){ 
        hr = E_FAIL; 
        BAIL_ON_FAILURE(hr); 
    } 
 
    hr = SafeArrayGetLBound(V_ARRAY(&varSafeArray), 
                            1, 
                            (long FAR *)&dwSLBound 
                            ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SafeArrayGetUBound(V_ARRAY(&varSafeArray), 
                            1, 
                            (long FAR *)&dwSUBound 
                            ); 
    BAIL_ON_FAILURE(hr); 
 
    dwNumVariants = dwSUBound - dwSLBound + 1; 
    pVarArray = (VARIANT*)AllocProvMem( 
                                sizeof(VARIANT)*dwNumVariants 
                                ); 
    if (!pVarArray) { 
        hr = E_OUTOFMEMORY; 
        BAIL_ON_FAILURE(hr); 
    } 
 
    for (i = dwSLBound; i <= dwSUBound; i++) { 
 
        VariantInit(pVarArray + i); 
        hr = SafeArrayGetElement(V_ARRAY(&varSafeArray), 
                                (long FAR *)&i, 
                                (pVarArray + i) 
                                ); 
        CONTINUE_ON_FAILURE(hr); 
    } 
 
    *ppVarArray = pVarArray; 
    *pdwNumVariants = dwNumVariants; 
 
error: 
 
    RRETURN(hr); 
}