CENUMOBJ.CPP
/*++ 
 
Copyright (c) 1996 Microsoft Corporation 
 
Module Name: 
 
    CEnumObj.c 
 
Abstract: 
 
    Generic Object Enumeration CodeStandard IClassFactory implementation 
 
Author: 
 
Environment: 
 
    User mode 
 
Revision History : 
 
--*/ 
#include "adssmp.h" 
#pragma hdrstop 
 
 
//+--------------------------------------------------------------------------- 
// 
//  Function:   CSampleDSEnumVariant::Create 
// 
//  Synopsis: 
// 
//  Arguments:  [pCollection] 
//              [ppEnumVariant] 
// 
//  Returns:    HRESULT 
// 
//  Modifies: 
// 
//  History:     
// 
//---------------------------------------------------------------------------- 
HRESULT 
CSampleDSGenObjectEnum::Create( 
    CSampleDSGenObjectEnum FAR* FAR* ppenumvariant, 
    BSTR ADsPath, 
    VARIANT var 
    ) 
{ 
    HRESULT hr = NOERROR; 
    CSampleDSGenObjectEnum FAR* penumvariant = NULL; 
    WCHAR szDSPath[MAX_PATH]; 
    DWORD dwModificationTime = 0L; 
    DWORD dwNumberOfEntries = 0L; 
    DWORD dwStatus = 0L; 
 
    *ppenumvariant = NULL; 
 
    penumvariant = new CSampleDSGenObjectEnum(); 
    if (!penumvariant) { 
        hr = E_OUTOFMEMORY; 
        BAIL_ON_FAILURE(hr); 
    } 
 
    hr = xx_put_BSTR(&penumvariant->_ADsPath, ADsPath); 
    BAIL_ON_FAILURE(hr); 
 
    hr = BuildDSFilterArray( 
                var, 
                (LPBYTE *)&penumvariant->_pDSFilterList 
                ); 
    if (FAILED(hr)) { 
        penumvariant->_pDSFilterList = NULL; 
    } 
 
    *ppenumvariant = penumvariant; 
 
    hr = BuildDSPathFromADsPath( 
                ADsPath, 
                szDSPath 
                ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSOpenObject( 
                    szDSPath, 
                    &penumvariant->_hObject, 
                    NULL, 
                    REG_DS 
                    ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SampleDSRDNEnum(  
                 &penumvariant->_hEnum,  
                 penumvariant->_hObject 
                 ); 
     
    RRETURN(hr); 
 
error: 
    if (penumvariant->_hObject) { 
        SampleDSCloseObject(penumvariant->_hObject); 
    } 
     
    delete penumvariant; 
 
    RRETURN(hr); 
} 
 
CSampleDSGenObjectEnum::CSampleDSGenObjectEnum(): 
                    _ADsPath(NULL) 
{ 
    _pObjList = NULL; 
    _dwObjectReturned = 0; 
    _dwObjectCurrentEntry = 0; 
    _dwObjectTotal = 0; 
    _hObject = NULL; 
    _hEnum = NULL; 
    _lpObjects = NULL; 
    _pDSFilterList = NULL; 
 
    _bNoMore = FALSE; 
} 
 
 
CSampleDSGenObjectEnum::~CSampleDSGenObjectEnum() 
{ 
    if (_pDSFilterList) { 
        FreeFilterList((LPBYTE)_pDSFilterList); 
    } 
} 
 
HRESULT 
CSampleDSGenObjectEnum::EnumObjects( 
    DWORD ObjectType, 
    ULONG cElements, 
    VARIANT FAR * pvar, 
    ULONG FAR * pcElementFetched 
    ) 
{ 
 
    // 
    // Multi-level detection of Objects may not be necessary for DS code 
    // 
 
    RRETURN(EnumGenericObjects(cElements, pvar, pcElementFetched)); 
 
} 
HRESULT 
CSampleDSGenObjectEnum::EnumGenericObjects( 
    ULONG cElements, 
    VARIANT FAR* pvar, 
    ULONG FAR* pcElementFetched 
    ) 
{ 
    DWORD           i; 
    ULONG           cRequested = 0; 
    ULONG           cTotalFetched = 0; 
    HRESULT         hr; 
 
    for (i = 0; i < cElements; i++)  { 
        VariantInit(&pvar[i]); 
    } 
    cRequested = cElements; 
 
        hr = FetchObjects(cElements, pvar, &cTotalFetched); 
    
    if (pcElementFetched) { 
        *pcElementFetched = cTotalFetched; 
    } 
 
    RRETURN(hr); 
} 
 
// 
// Load IDispatch pointers of Next cElements Filtered Objects into pvar array 
// 
HRESULT 
CSampleDSGenObjectEnum::FetchObjects( 
 
    ULONG cElements, 
    VARIANT FAR* pvar, 
    ULONG FAR* pcElementFetched 
    ) 
{ 
    HRESULT hr; 
    IDispatch *pDispatch = NULL; 
    DWORD i = 0; 
 
    while (i < cElements) { 
 
        hr = FetchNextObject(&pDispatch); 
        if (hr == S_FALSE) { 
            break; 
        } 
 
        VariantInit(&pvar[i]); 
        pvar[i].vt = VT_DISPATCH; 
        pvar[i].pdispVal = pDispatch; 
        (*pcElementFetched)++; 
        i++; 
    } 
    return(hr); 
} 
//+--------------------------------------------------------------------------- 
// 
//  Function:   CSampleDSNamespaceEnum::FetchNextObject 
// 
//  Synopsis:   Gets IDispatch pointer of next object in namespace subject to 
//                              filter. 
// 
//  Arguments:  [ppDispatch] -- Pointer to where to return IDispatch pointer. 
// 
//  Returns:    HRESULT -- S_OK if got the next object 
//                      -- S_FALSE if not 
// 
//  Modifies:   [*ppDispatch] 
// 
//---------------------------------------------------------------------------- 
HRESULT 
CSampleDSGenObjectEnum::FetchNextObject( 
    IDispatch ** ppDispatch 
    ) 
 { 
    HRESULT hr; 
    LPTSTR lpszObjectRDN=NULL ; 
    LPTSTR lpszObjectClass = 0; 
    DWORD dwClassId = 0; 
    IADs * pADs = NULL; 
    *ppDispatch = NULL; 
 
    hr = S_OK; 
    while (hr == S_OK){ 
        hr=SampleDSNextRDN(_hEnum, 
                           &lpszObjectRDN, 
                           &lpszObjectClass 
                           );     
        if (S_OK==hr &&  
            S_OK==IsValidDSFilter(lpszObjectClass)) { 
            break; 
        } 
    } 
 
    // 
    // Now create and send back the current object 
    // 
    if (hr == S_OK) { 
        hr = CSampleDSGenObject::CreateGenericObject(_ADsPath, 
                                                     lpszObjectRDN, 
                                                     lpszObjectClass, 
                                                     ADS_OBJECT_BOUND, 
                                                     IID_IDispatch, 
                                                     (void **)ppDispatch 
                                                     ); 
        BAIL_ON_FAILURE(hr); 
    } 
    else { 
        if (_hEnum) { 
            SampleDSFreeEnum(_hEnum); 
            _hEnum = NULL; 
        } 
    } 
 
error: 
 
    // 
    // Free the intermediate pADs pointer. 
    // 
    if (pADs) { 
        pADs->Release(); 
    } 
    if (lpszObjectRDN) 
        FreeProvMem(lpszObjectRDN); 
    if (lpszObjectClass) 
        FreeProvMem(lpszObjectClass); 
    RRETURN_ENUM_STATUS(hr);  
} 
 
 
//+--------------------------------------------------------------------------- 
// 
//  Function:   CSampleDSGenObjectEnum::Next 
// 
//  Synopsis:   Returns cElements number of requested NetOle objects in the 
//              array supplied in pvar. 
// 
//  Arguments:  [cElements] -- The number of elements requested by client 
//              [pvar] -- ptr to array of VARIANTs to for return objects 
//              [pcElementFetched] -- if non-NULL, then number of elements 
//                                 -- actually returned is placed here 
// 
//  Returns:    HRESULT -- S_OK if number of elements requested are returned 
//                      -- S_FALSE if number of elements is < requested 
// 
// 
//---------------------------------------------------------------------------- 
STDMETHODIMP 
CSampleDSGenObjectEnum::Next( 
    ULONG cElements, 
    VARIANT FAR* pvar, 
    ULONG FAR* pcElementFetched 
    ) 
{ 
    ULONG cElementFetched = 0; 
    HRESULT hr = S_OK; 
 
    hr = EnumGenericObjects( 
            cElements, 
            pvar, 
            &cElementFetched 
            ); 
 
 
    if (pcElementFetched) { 
        *pcElementFetched = cElementFetched; 
    } 
    RRETURN(hr); 
} 
 
HRESULT 
CSampleDSGenObjectEnum::IsValidDSFilter(LPWSTR ObjectName){ 
 
    if (_pDSFilterList){ 
                for (DWORD i = 0; i < _pDSFilterList->dwNumberOfFilters; i++) { 
 
                        if ( !_wcsicmp(ObjectName,_pDSFilterList->Filters[i].lpObjectClass) ) { 
                                RRETURN(S_OK); 
                        } 
                } 
                RRETURN(E_FAIL); 
    } 
    RRETURN(S_OK); 
} 
 
HRESULT 
BuildDSFilterArray( 
    VARIANT var, 
    LPBYTE * ppContigFilter 
    ) 
{ 
    LONG uDestCount = 0; 
    LONG dwSLBound = 0; 
    LONG dwSUBound = 0; 
    VARIANT v; 
    LONG i; 
    HRESULT hr = S_OK; 
 
    LPDS_FILTER_LIST pDsFilterList = NULL; 
    LPBYTE pContigFilter = NULL; 
 
    if(!((V_VT(&var) &  VT_VARIANT) &&  V_ISARRAY(&var))) { 
        RRETURN(E_FAIL); 
    } 
 
    // 
    // Check that there is only one dimension in this array 
    // 
 
    if ((V_ARRAY(&var))->cDims != 1) { 
        hr = E_FAIL; 
        BAIL_ON_FAILURE(hr); 
    } 
    // 
    // Check that there is atleast one element in this array 
    // 
 
    if ((V_ARRAY(&var))->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(&var), 
                            1, 
                            (long FAR *)&dwSLBound 
                            ); 
    BAIL_ON_FAILURE(hr); 
 
    hr = SafeArrayGetUBound(V_ARRAY(&var), 
                            1, 
                            (long FAR *)&dwSUBound 
                            ); 
    BAIL_ON_FAILURE(hr); 
 
 
    pContigFilter = (LPBYTE)AllocProvMem( 
                            sizeof(DS_FILTER_LIST) 
                            - sizeof(DS_FILTER) 
                            ); 
    if (!pContigFilter) { 
 
        hr = E_FAIL; 
        BAIL_ON_FAILURE(hr); 
    } 
 
 
    for (i = dwSLBound; i <= dwSUBound; i++) { 
        VariantInit(&v); 
        hr = SafeArrayGetElement(V_ARRAY(&var), 
                                (long FAR *)&i, 
                                &v 
                                ); 
        if (FAILED(hr)) { 
            continue; 
        } 
 
        // 
        //  Create an entry in the filter block 
        //  Append it to the existing block 
        // 
 
        pContigFilter = CreateAndAppendFilterEntry( 
                            pContigFilter, 
                            V_BSTR(&v) 
                            ); 
        if (!pContigFilter) { 
 
            hr = E_FAIL; 
            BAIL_ON_FAILURE(hr); 
        } 
 
    } 
 
    pDsFilterList = (LPDS_FILTER_LIST)pContigFilter; 
 
    if (!pDsFilterList->dwNumberOfFilters){ 
 
        hr = E_FAIL; 
        BAIL_ON_FAILURE(hr); 
    } 
 
    *ppContigFilter = pContigFilter; 
 
    RRETURN(S_OK); 
 
error: 
 
    if (pContigFilter){ 
 
        FreeFilterList( 
               pContigFilter 
               ); 
 
    } 
 
    *ppContigFilter = NULL; 
 
    RRETURN(hr); 
} 
 
LPBYTE 
CreateAndAppendFilterEntry( 
    LPBYTE pContigFilter, 
    LPWSTR lpObjectClass 
    ) 
{ 
    LPWSTR pszFilter = NULL; 
    LPDS_FILTER_LIST pDsFilterList = NULL; 
    DWORD dwFilterCount = 0; 
    LPBYTE pNewContigFilter = NULL; 
    LPDS_FILTER pNewEntry = NULL; 
 
 
    pszFilter = (LPWSTR)AllocProvStr(lpObjectClass); 
    if (!pszFilter) { 
        return(pContigFilter); 
    } 
 
    pDsFilterList = (LPDS_FILTER_LIST)pContigFilter; 
 
    dwFilterCount = pDsFilterList->dwNumberOfFilters; 
 
    pNewContigFilter = (LPBYTE)ReallocProvMem( 
                                    pContigFilter, 
 
                                    sizeof(DS_FILTER_LIST) + 
                                    (dwFilterCount - 1)* sizeof(DS_FILTER), 
 
                                    sizeof(DS_FILTER_LIST) 
                                    + dwFilterCount * sizeof(DS_FILTER) 
                                    ); 
    if (!pNewContigFilter) { 
        return(pContigFilter); 
    } 
 
    pNewEntry = (LPDS_FILTER)(pNewContigFilter + sizeof(DS_FILTER_LIST) 
                        + (dwFilterCount - 1)* sizeof(DS_FILTER)); 
 
    pNewEntry->lpObjectClass = pszFilter; 
 
    pDsFilterList = (LPDS_FILTER_LIST)pNewContigFilter; 
 
    pDsFilterList->dwNumberOfFilters = dwFilterCount + 1; 
 
    return(pNewContigFilter); 
} 
 
void 
FreeFilterList( 
    LPBYTE lpContigFilter 
    ) 
{ 
    LPDS_FILTER_LIST lpDsFilterList = (LPDS_FILTER_LIST)lpContigFilter; 
    DWORD dwNumFilters = 0; 
    LPDS_FILTER lpDsFilter = NULL; 
    DWORD i = 0; 
 
    dwNumFilters = lpDsFilterList->dwNumberOfFilters; 
 
    if (dwNumFilters){ 
 
        lpDsFilter = (LPDS_FILTER)(lpContigFilter  + sizeof(DS_FILTER_LIST) 
                                      - sizeof(DS_FILTER)); 
 
        for (i = 0; i < dwNumFilters; i++) { 
 
            FreeProvStr((lpDsFilter + i)->lpObjectClass); 
        } 
 
    } 
 
    FreeProvMem(lpContigFilter); 
}