4.3.1 IADsContainer

IADsContainer is a COM interface defined by Active Directory. It provides the basic functionality required by all directory service container objects:

Note that GetInfo and SetInfo do not affect the objects stored in a container. Calling GetInfo and SetInfo affects the properties of the container object, not the objects stored in the container.

The IADsContainer interface definition is as follows:

[ object, uuid(IID_IADsContainer), oleautomation, dual ]

interface IADsContainer: IDispatch

{

// Read-only properties.

[propget]

HRESULT Count ([out, retval]long *plCount);

[propget, restricted, id(-4)]

HRESULT _NewEnum ([out, retval]Iunknown *ppEnumerator);

// Read/write properties.

[propget]

HRESULT Filter ([out, retval]VARIANT *pvFilter);

[propput]

HRESULT Filter ([in]VARIANT vFilter);

[propget]

HRESULT Hints ([out, retval]VARIANT *pvHints);

[propput]

HRESULT Hints ([in]VARIANT vHints);

// Methods.

HRESULT GetObject ([in]BSTR bstrClass,

[in]BSTR bstrRelativeName,

[out, retval]IADs **ppNamedObject );

HRESULT Create ([in]BSTR bstrClass,

[in]BSTR bstrRelativeName,

[out, retval]IADs **ppNewObject );

HRESULT Delete ([in]bstrClass,

[in]BSTR bstrRelativeName);

HRESULT CopyHere ([in]BSTR bstrSourceObject,

[in]BSTR bstrNewName,

[out, retval]IADs **ppNewObject);

HRESULT MoveHere ([in]BSTR bstrSourceObject,

[in]BSTR bstrNewName,

[out, retval]IADs **ppNewObject);

};

Method

Description

Filter

Gets or sets the filter on the object classes that will be returned in a given enumeration. The client can also give hints to the provider about which properties of the objects it will use after the enumeration. If Filter is not set or is set to empty, then all objects of all classes will be returned by the enumerator. Otherwise, each array entry should be of the following format:

<FilterEntry>::=<ClassName>

|"Provider Specific String"

<ClassName>is a BSTR value that represents a class,.

Hints

The vHints parameter allows the client to indicate which properties should be loaded, so the provider can attempt to optimize network access. If no hints are specified, the VARIANT vHints is marked as empty, and the provider is expected to provide as much smart network access as possible. Otherwise, each entry in the array should have the following format:

<HintEntry>::=<PropName>

<PropName> is a BSTR value that represents a property found in the schema.

Count

Gets the number of Active Directory objects within the container. If there is a filter set, only a count of the classes named in the filter will be returned.

_NewEnum

Gets an enumerator dependent object. If there is a filter set, only the classes named in the filter will be enumerated. Enumeration can be performed using the IEnumVARIANT interface. See section 0, "5.3 Enumerator Objects" for details.

Enumeration returns IADs interface pointers.

GetObject

Returns the IADs interface of the item in the container identified by the object's class and relative name (this is the value of the object's IADs::Name property). If the class name is not provided the provider will return the first item found with the specified name in the current container.

Create

Creates an object of the class specified by bstrClass, of name bstrRelativeName, and returns a pointer to the newly created object. The object is not actually created within the directory service until the IADs::SetInfo method is executed on the newly created object. This is to allow setting of mandatory properties.

The bstrClass value should take the following syntax:

<Class>::=<ClassName>

<ClassName> is a BSTR value that represents the classes found in the schema. The schema can be browsed using the schema management objects. See "Schema Management Active Directory objects" in Chapter 6, "Object Extensions," for more details.

Delete

Deletes the object identified by the provided class and relative name.

CopyHere

Creates a new object in this container identical to the specified object and returns a pointer to the new object. The destination container must be in the same namespace as the source. Copying objects across namespaces is not permitted. NewName is an optional parameter that, if present, contains the name inside the container.

MoveHere

Moves the specified object to this container and returns a pointer to the new object. The destination container must be in the same namespace as the source. Moving objects across namespaces is not permitted. NewName is an optional parameter that, if present, contains the name inside the container.


4.3.1.1 Enumeration

Given any interface on any leaf or container Active Directory object, it is possible to perform complete tree navigation and object enumeration.

To navigate up the tree, call QueryInterface for the IADs interface and use the Parent property to find the parent container of the object. The only container that does not have a parent is the namespaces container.

To navigate down the tree, call QueryInterface for the IADsContainer interface. If the interface is supported by the object, it is a container. Use the enumeration methods to expand the tree further. If the interface is not supported by the object, then it is a leaf, and the tree goes no deeper from that point.

Example 1: Navigating Down a Tree (Visual Basic)

' This example takes any Active Directory object and attempts

' to navigate down the tree. If the object is not a

' container, then the routine ends.

Dim MyObject as IADs

Dim Child as IADs

Dim Container as IADsContainer

' Setup error handling.

On Error Resume Next

' Bind to a known component.

Set MyObject = GetObject("WinNT://MSFT/Users")

' Ask for the IADsContainer interface.

Set Container = MyObject

' If no error occurs, further navigation is possible.

If Err = 0 Then

For Each Child in Container

Debug.Print Child.Name

Next Child

EndIf

Example 1: Navigating Down a Tree (C/C++)

//

// This example takes any Active Directory object and attempts

// to navigate down the tree. If the object is not a

// container, then the routine ends.

//

IADs *pMyObject;

IADs *pChild;

IADsContainer *pContainer;

IEnumVARIANT *pEnum;

HRESULT hr;

BSTR bstrName;

//

// Bind to a known component.

//

ADsGetObject(TEXT("WinNT://MSFT/Users"),

IID_IADs,

(void**)&pMyObject);

//

// Ask for the IADsContainer interface.

//

hr = pMyObject->QueryInterface(IID_IADsContainer, &pContainer);

//

// If no error occurs, further navigation is possible.

//

if (SUCCEEDED(hr))

{

//

// Get an enumerator. ADsBuildEnumerator is a helper function

// supplied by Active Directory - see Appendix B for more details.

//

ADsBuildEnumerator(pContainer, &pEnum);

//

// Enumerate through all the children of the container.

// ADsEnumerateNext is a helper function supplied by Active Directory.

// See Appendix B for more details.

//

do

{

hr = ADsEnumerateNext(pEnum,

1,

(void**)&pChild,

NULL);

if (SUCCEEDED(hr)

{

pChild->get_Name(&bstrName);

printf("%s\n", bstrName);

SysFreeString(bstrName);

pChild->Release();

} // if

} while (SUCCEEDED(hr)); // do

//

// Cleanup.

//

pEnum->Release();

pContainer->Release();

} // if

//

// Cleanup.

//

pMyObject->Release();

4.3.1.2 Life Cycle

Object creation is used to create new objects in a container. Object creation in Active Directory takes the following steps:

The client calls IADs::SetInfo() to persist the new object in the underlying namespace.

When the client calls SetInfo, the provider attempts to create the actual object in the namespace, and write the property values.

The following example demonstrates creating a user object.

Example 1: Creating a User Object (Visual Basic)

Dim Container as IADsContainer

Dim NewUser as IADsUser

' Bind to the known container.

Set Container = GetObject("WinNT://Mydomain")

' Create the new wrapper.

Set NewUser = Container.Create("user", "Jane")

' Write it back to the DS

NewUser.SetInfo

' Set Jane's password.

NewUser.SetPassword("Argus")

Example 1: Creating a User Object (C/C++)

IADsContainer    *pContainer;

IADs *pNewObject;

IADsUser *pUser;

//

// Bind to the known container.

//

ADsGetObject(TEXT("WinNT://Mydomain"),

IID_IADsContainer,

(void**)&pContainer);

//

// Create the new wrapper.

//

pContainer->Create(TEXT("user"),

TEXT("Jane"),

&pNewObject);

//

// Get the IADsUser interface from the wrapper.

//

pNewObject->QueryInterface(IID_IADsUser, &pUser);

//

// Write it back to the DS.

//

pUser->SetInfo();

//

// Set Jane's password.

//

pUser ->SetPassword(TEXT("Argus"));

//

// Cleanup.

//

pContainer->Release();

pNewObject->Release();

pUser->Release();

Object deletion is used to remove objects from a directory service. To delete an object, it's relative path string is passed to the Delete function. This is the value contained in the Name property on the IADs interface for the object.

Important note on deletion: when an object is deleted, it is removed from the underlying namespace immediately. Any interface pointers held by the application for the deleted object are still valid, because the interface pointers refer to Active Directory objects in memory. SetInfo and GetInfo calls using interface pointers for an object has been deleted will return an error. Applications should release any interface pointers for an object when the object is deleted. This is shown below in Example 2.

The following code deletes the user that was created in example 1. It also demonstrates how to get the parent container of an object.

Example 2: Deleting a User Object (Visual Basic)

Dim Container as IADsContainer

Dim User as IADsUser

Dim UserPath as String

' Bind to the known object. In this case, we happen to know

' the explicit path, but typically the object will be discovered

' using query or enumeration.

Set User = GetObject("WinNT://MSFT/Users/Jane")

' Get the container of the user object.

Set Container = GetObject(User.Parent)

' Delete the user.

Call Container.Delete("user",User.name)

' Release the user object. Note that we deleted

' the underlying DS object, so we should not hang on to the user

' component.

Set User = Nothing

Example 2: Deleting a User Object (C/C++)

IADsContainer    *pContainer;

BSTR bstrContainerPath;

IADsUser *pUser;

BSTR bstrUserName;

//

// Bind to the known object. In this case, we happen to know

// the explicit path, but typically the object will be discovered

// using query or enumeration.

//

ADsGetObject(TEXT("WinNT://MSFT/Users/Jane"),

IID_IADsUser,

(void**)&pUser);

//

// Get the container object path.

//

pUser->get_Parent(&bstrContainerPath);

//

// Get the container object.

//

ADsGetObject(bstrContainerPath,

IID_IADsContainer,

(void**)&pContainer);

//

// Get the user object's name. (This step is unneccesary in

// this example since we already know the name, but is included to

// indicate that we either need to know the name, or have a ptr

// to the object).

//

pUser->get_Name(&bstrUserName);

//

// Release the user object. Note that we are about to delete

// the underlying DS object, so we should not hang on to the user

// component.

//

pUser->Release();

//

// Delete the user.

//

pContainer->Delete(TEXT("user"),bstrUserName);

//

// Cleanup.

//

SysFreeString(bstrContainerPath);

SysFreeString(bstrUserPath);

pContainer->Release();

Object copy/move is a combination of the creation and deletion functions, with an option to rename an object when it reaches the target container.