Platform SDK: Active Directory, ADSI, and Directory Services

ADsBuildEnumerator

The ADsBuildEnumerator function builds an enumerator object for the specified ADSI container object.

HRESULT ADsBuildEnumerator(
  IADsContainer *pADsContainer, 
  IEnumVARIANT **ppEnumVariant 
);

Parameters

pADsContainer
[in] Pointer to the IADsContainer interface on the object to be enumerated.
ppEnumVariant
[out] Indirect pointer to the IEnumVARIANT interface on the enumerator object created for the specified container object.

Return Values

This method supports the standard HRESULT return values, including S_OK for a successful operation. For other return values, see ADSI Error Codes.

Remarks

The ADsBuildEnumerator helper function calls the IADsContainer::get__NewEnum method to create an enumerator object and then calls the QueryInterface method of IUnknown to get a pointer to the IEnumVARIANT interface on the enumerator object. The general procedure to enumerate the available objects in a container is as follows:

  1. Create an enumerator on that container and retrieve the IEnumVARIANT interface pointer.
  2. Call the ADsEnumerateNext function on the IEnumVARIANT interface.
  3. Upon finishing the enumeration, call ADsFreeEnumerator to release the enumerator.

The following code snippet illustrates how this and other related API functions can be used to delete all the objects in a container.

Void DeleteObject(IUnknown* pIUnknown)
{
IUnknown*       pIChildUnk   = NULL;
IADsContainer*  pIContainer  = NULL;
IEnumVARIANT*   pIEnumVar    = NULL;
ULONG           ulFetch      = 0;
VARIANT         var;
HRESULT         hr;
 
if(pIUnknown =NULL) return E_FAIL;
 
// QI container interface.
hr=pIUnknown->QueryInterface(IID_IADsContainer,(void**)&pIContainer);
 
if (SUCCEEDED(hr)) {
    //Create an enumerator object in the container.
    hr=ADsBuildEnumerator(pIContainer, &pIEnumVar);
    while(SUCCEEDED(hr)) {
        //Get the next contained object.
        ulFetch = 0L;
        hr = ADsEnumerateNext(pIEnumvar, 1, &var, &ulFetch);
        if(!ulFetch) break;
        //Check if the retrieved object is another container.
        V_DISPATCH(%var)->QueryInterface(IID_IUnknown,
                                        (void**)&pIChildUnk);
        //Release the contained object.
        VariantClear(&var);
 
        //Call the function recursively on child containers.
        if(pIChildUnk != NULL) {
            DeleteObject(pIContainer, pIChildUnk);
            pIChildUnk->Release();
        }
        pIChildUnk = NULL;
    }
    //Release the enumerator.
    if (pIEnumVar != NULL) {
        ADsFreeEnumerator(pIEnumVar);
    }
    //Release the container.
    pIContainer->Release();
}
 

If the server supports paged search and the client has specified the page limit that exceeds the maximum search results allowed on the server, the ADsBuildEnumerator function forwards errors and results from the server to the user in the following ways:

  1. If the server returns an error with no results, then the function returns only the error.
  2. If the server returns partial results with or without an error, the function returns the partial results from the server to the user.
  3. If the server returns all results, for example, the maximum number of search results on each page and all results through multiple pages, with or without an error, the function returns all the results from the server to the user.

Here is another code snippet that uses the ADsBuildEnumerator function to enumerate Group Membership.

int main(int argc, char* argv[])
{
    IADs            *pRoot=NULL;
    IADsContainer   *pCont=NULL;
    IEnumVARIANT    *pEnum=NULL,*pMbrEnum=NULL;
    IDispatch       *pDisp,*pDispMem;
    IADs            *pADs,*pADsMem;
    IADsGroup       *pGrp;
    IADsMembers     *pMbr;
 
 
    VARIANT varDSRoot;
    VARIANT varEnum,varEnumMem;
    ULONG   ulFetch=0;
    BSTR    bstrPath;
 
    TCHAR   adspath[MAX_PATH];
    
    HRESULT hr;
 
    hr = CoInitialize(NULL);
    
    //Get the name of the root container for this domain.  
    //Read the Root DSE from the default DS, which will be the DS for 
    //the local domain.  This will get us the name of the schema 
    //container, which is stored in the "defaultNamingContext" 
    //operational attribute.
 
    hr = ADsGetObject(TEXT("LDAP://RootDSE"),
                      IID_IADs,
                      (void**)&pRoot);
 
    hr = pRoot->Get(TEXT("defaultNamingContext"),&varDSRoot);
    _tprintf(TEXT("\nDS Root :%s\n"),varDSRoot.bstrVal);
    pRoot->Release();
 
    //Now bind to the builtin container.
 
    _tcscpy(adspath,TEXT("LDAP://"));
    _tcscat(adspath,TEXT("CN=Builtin,"));
    _tcscat(adspath,varDSRoot.bstrVal);
 
    hr = ADsGetObject(adspath,IID_IADsContainer,(void**)&pCont);
 
    //Enumerate the contents of the builtin container
 
    hr = ADsBuildEnumerator(pCont,&pEnum);
 
    while (hr == S_OK) {
        //
        //Fetch one element and place it in varEnum.  ulFetch is the
        //number of elements actually returned.  If there are no 
        //objects to enumerate ulFetch will be zero and the call will 
        //succeed. When an object is fetched, varEnum  will contain 
        //the dispinterface of the child object
        //
        hr = ADsEnumerateNext(pEnum,1,&varEnum,&ulFetch);
        if (ulFetch) {
            //
            //Use the dispinterface to QI for IADs.
            //
            pDisp = V_DISPATCH(&varEnum);
            hr = pDisp->QueryInterface( IID_IADs, (void**)&pADs); 
            hr = pADs->get_ADsPath(&bstrPath);
            if SUCCEEDED(hr) {
                _tprintf(TEXT(" Builtin:%s\n"),bstrPath);
 
                //Enumerate the members of this group. Bind to the 
                //group requesting IADsGroup
                //
                hr = ADsGetObject(bstrPath,IID_IADsGroup,(void**)&pGrp);
                //Retrieve the Members property - this is a container
                //that holds IADs objects for the members
                //
                hr = pGrp->Members(&pMbr);
                //Create another enumerator and enumerate the members 
                //of the group.
                //
                hr = ADsBuildEnumerator((IADsContainer*)pMbr,&pMbrEnum);
                while (hr == S_OK) {
                    hr = ADsEnumerateNext(pMbrEnum,1,&varEnumMem,&ulFetch);
                    if (ulFetch) {
                        //
                        //For each member, read the ADsPath attribute 
                        //and display it.
                        //
                        pDispMem = V_DISPATCH(&varEnumMem);
                        hr = pDispMem->QueryInterface( IID_IADs, (void**)&pADsMem); 
                        hr = pADsMem->get_ADsPath(&bstrPath);
                        _tprintf(TEXT("  Member:%s\n"),bstrPath);
                        pDispMem->Release();
                        pADsMem->Release();
                    } //Object Fetched.
                } //Member enumerator built.
                hr = ADsFreeEnumerator(pMbrEnum);
                pGrp->Release();
                pMbr->Release();
              
                pADs->Release();
                pDisp->Release();
            } //Group object bound
        } //Group fetched
    } // Group enumerator built
 
 
    hr = ADsFreeEnumerator(pEnum);
 
    if (pCont)
        pCont->Release();
 
    return 0;
}
 

Requirements

  Windows NT/2000: Requires Windows 2000 (or Windows NT 4.0 with DSClient).
  Windows 95/98: Requires Windows 95 or later (with DSClient).
  Header: Declared in Adshlp.h.
  Library: Included as a resource in ActiveDs.dll.

See Also

ADSI Error Codes, ADSI Functions, ADsEnumerateNext, ADsFreeEnumerator, IADsContainer, IEnumVARIANT