1399 lines
72 KiB
HTML
1399 lines
72 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<title>Active Directory Service Interfaces - Getting Started</title>
|
|
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
</head>
|
|
|
|
<body topmargin="0" leftmargin="0">
|
|
|
|
<table border="0" height="86" cellpadding="0" cellspacing="0">
|
|
<tr>
|
|
<td width="77%" valign="top" height="58"><map name="FPMap2">
|
|
<area href="http://www.microsoft.com/windows2000/library/howitworks/activedirectory/adsilinks.asp" shape="rect" coords="4, 6, 248, 57"></map><img src="banner.gif"
|
|
border="0" alt="http://www.microsoft.com/windows2000/library/howitworks/activedirectory/adsilinks.asp" width="250" height="60" usemap="#FPMap2"></td>
|
|
<td width="3%" height="58"></td>
|
|
<td width="21%" height="58" valign="bottom"><p align="right"><map name="FPMap3">
|
|
<area href="http://www.microsoft.com" shape="rect" coords="7, 6, 108, 39"></map><img src="mslogo.gif"
|
|
border="0" alt="http://www.microsoft.com" width="112" height="40" usemap="#FPMap3"></td>
|
|
</tr>
|
|
<tr>
|
|
<td valign="top" align="left" height="28"><map name="FPMap0">
|
|
<area href="rtk.htm" shape="rect" coords="420, 1, 515, 18" ALT="rtk.htm">
|
|
<area href="interopt.htm" shape="rect" coords="350, 1, 415, 19" ALT="interopt.htm">
|
|
<area href="ad.htm" shape="rect" coords="233, 1, 345, 19" ALT="ad.htm">
|
|
<area href="winnt.htm" shape="rect" coords="165, 1, 223, 19" ALT="winnt.htm">
|
|
<area href="dev.htm" shape="rect" coords="67, 1, 165, 19" ALT="dev.htm">
|
|
<area href="../default.htm" shape="rect" coords="13, 1, 65, 20" ALT = "../default.htm"></map>
|
|
<img rectangle="(233,1) (345, 19) ad.htm" rectangle="(165,1) (223, 19) winnt.htm" rectangle="(67,1) (165, 19) dev.htm" rectangle="(13,1) (65, 20) ../default.htm" src="router.gif" alt="router.gif (3874 bytes)" border="0" usemap="#FPMap0" width="536" height="26"></td>
|
|
<td width="3%" height="28"></td>
|
|
<td width="21%" height="28"></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="4588">
|
|
<tr>
|
|
<td width="2%" height="19"></td>
|
|
<td width="98%" height="19"></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="2%" height="1"></td>
|
|
<td width="98%" height="1"><img src="http://adsi/sdk/getstart.gif" width="148" height="56"></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="2%" height="4624"></td>
|
|
<td width="98%" height="4624" valign="top">
|
|
<p><font face="Verdana"><small>You should set up
|
|
your ADSI <a href="dev.htm">development environment</a> before we start. ADSI is
|
|
very easy and fun to program. This page gives you a quick start on ADSI programming. For
|
|
more advanced topics and provider-specific information, see the documentation and samples in the Platform SDK.</small></font>
|
|
|
|
</p>
|
|
|
|
<p><a name="top"></a><font face="Verdana" color="#0080C0"><strong><small>How do I:</small></strong></font>
|
|
|
|
<ul>
|
|
|
|
<li><font face="Verdana"><small><strong><a href="#connect">Connect/bind
|
|
to a directory object</a></strong><br>
|
|
First, you must bind to a directory object before any other operations, such as
|
|
searching, reading and modifying attributes, or enumerating are allowed. You can
|
|
connect or bind to a directory object remotely. </small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#credentials">Specify
|
|
alternate credentials</a></strong><br>
|
|
|
|
In addition to the currently logged on user, ADSI allows you to specify other
|
|
alternate credentials. </small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#enumerate">Enumerate
|
|
children in a container</a></strong><br>
|
|
|
|
A directory is normally a hierarchical model. It may have children which are also parents of other children.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#readAttr">Read an
|
|
attribute on an object</a></strong><br>
|
|
|
|
An object may contain one or more attributes which can have a single
|
|
value or multiple values.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#write">Write an attribute
|
|
on an object</a></strong><br>
|
|
|
|
You may modify attributes or write a new value.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#create">Create an object</a></strong><br>
|
|
|
|
An object can be created for a given parent.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#delete">Delete an object</a></strong><br>
|
|
|
|
An object can be deleted for a given parent.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#rename">Rename an object</a></strong><br>
|
|
|
|
An object can be renamed for a given parent.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#move">Move an object</a></strong><br>
|
|
|
|
An object can be moved from a given parent to a new destination parent.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#getObject">Get a child object</a></strong><br>
|
|
|
|
You can bind to an object for a given parent.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#parent">Get a parent of an
|
|
object</a></strong><br>
|
|
|
|
You can bind to the parent object.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#search">Search for a set
|
|
of objects</a></strong><br>
|
|
|
|
You can specify criteria for searching a set of objects.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#filter">Filtering a set of
|
|
objects</a></strong><br>
|
|
|
|
Another easy way to search is to use filtering. This is a subset of search capabilities.</small></font></li>
|
|
</ul>
|
|
|
|
<ul>
|
|
<li><font face="Verdana"><small><strong><a href="#readSchema">Read Schema</a></strong><br>
|
|
|
|
Each ADSI provider has a schema which defines the classes, attributes, and syntax.</small></font></li>
|
|
</ul>
|
|
|
|
<p><font face="Verdana" color="#000000"><small> </small></font></p>
|
|
|
|
<p><strong><font face="Verdana" color="#0080C0"><small>What's Next?</small></font></strong></p>
|
|
|
|
<p><font face="Verdana" color="#000000"><small>Now that you are managing basic ADSI
|
|
operations, you can continue your quest to set up a fully functioning directory. To focus
|
|
on tasks you want to accomplish for the directory you're connecting to, visit the
|
|
provider's pages (WinNT for NT 4.0, LDAP for Active Directory, SiteServer, Exchange and
|
|
other LDAP directories, and more).</small></font></p>
|
|
|
|
<br>
|
|
|
|
<a name="connect"></a><font face="Verdana" color="#0080C0"><strong><small>Connecting/binding to a directory
|
|
object</small></strong></font>
|
|
|
|
<p><font face="Verdana"><small>Before you bind to a directory object, you must know the
|
|
ADsPath. For example, in the Windows NT 4.0 directory, the path can be
|
|
WinNT://domainName/object. For Windows 2000 Active Directory, you can bind to it as
|
|
LDAP://DC=MyCompany, DC=COM. For Exchange Server, you should know the Exchange
|
|
Server name and its organization, for example, LDAP://exchSrv01/O=Microsoft. For more
|
|
information about each provider, visit the provider pages.</small></font></p>
|
|
|
|
<p><font face="Verdana"><small>To bind to an object, use the <strong>GetObject</strong>
|
|
function for Visual Basic and the <strong>ADsGetObject</strong> function for Visual C++.
|
|
These functions run in the context of the currently logged on user.</small></font></p>
|
|
|
|
<p><font face="Verdana"><small>'---Visual Basic Sample: Binding to JSmith user in
|
|
ARCADIABAY domain</small> <br>
|
|
|
|
<small>Set obj = GetObject("WinNT://ARCADIABAY/JSmith,user")</small><br>
|
|
<br>
|
|
<small>'Source code can be found in the \samples\start\Binding\vb directory.</small></font></p>
|
|
<p><font face="Verdana"><small>// Visual C++ Sample: Binding to JSmith user in ARCADIABAY
|
|
domain</small><br>
|
|
<small>HRESULT hr;</small><br>
|
|
<small>IADs *pADs;</small><br>
|
|
<small>hr = ADsGetObject( L"WinNT://ARCADIABAY/JSmith,user", IID_IADs, (void**)
|
|
&pADs );</small><br>
|
|
//...<br>
|
|
<small>pADs->Release(); // Do not forget to release when you're done.</small></font></p>
|
|
<p><font face="Verdana"><small>//Source code can be found in the \samples\start\Binding\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p> </p>
|
|
<p><a name="credentials"></a><small><font face="Verdana"><strong><font color="#0080C0">Specifying
|
|
alternate credentials</font></strong> </font></small></p>
|
|
<p><small><font face="Verdana">Sometimes, you would like to bind to another object that
|
|
has a different set of credentials. This can be accomplished using the <strong>IADsOpenDSObject</strong>
|
|
interface, or the <strong>ADsOpenObject</strong> function for Visual C++.</font></small></p>
|
|
<p><small><font face="Verdana">'---- Visual Basic Sample: Binding to the JSmith user in
|
|
the ArcadiaBay domain with an alternate credential</font></small></p>
|
|
<p><font face="Verdana"><small>Set dso = GetObject("WinNT:")</small><br>
|
|
<small>Set usr = dso.OpenDSObject("WinNT://ARCADIABAY/JSmith,user",
|
|
"Administrator", "secret", ADS_SECURE_AUTHENTICATION)</small><br>
|
|
</font><br>
|
|
<font face="Verdana"><small>'Source code can be found in the \samples\start\Binding\vb
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small> </small></font></p>
|
|
<p><font face="Verdana"><small>//---- Visual C++ Sample: Binding to the JSmith user in the
|
|
ArcadiaBay domain with an alternate credential</small><br>
|
|
<small>IADs *pADs;</small><br>
|
|
<small>HRESULT hr;</small><br>
|
|
<small>hr = ADsOpenObject(L"WinNT://ARCADIABAY/JSmith,user",
|
|
L"Administrator", L"secret", ADS_SECURE_AUTHENTICATION, IID_IADs,
|
|
(void**) &pADs );</small><br>
|
|
<small>//...</small><br>
|
|
<small>// Make sure that you release it after use</small>.<br>
|
|
<small>pADs->Release();</small></font></p>
|
|
<p><font face="Verdana"><small>//Source code can be found in the \samples\start\Binding\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p> </p>
|
|
<p><a name="enumerate"></a><font face="Verdana" color="#0080C0"><strong><small>Enumerating
|
|
children in a container</small></strong></font></p>
|
|
<p><font face="Verdana"><small>Once you bind to an object which is a container, you'll be
|
|
able to enumerate its children using a normal For...each statement in Visual Basic, or
|
|
using the <strong>ADsBuildEnumerator</strong> function for Visual C++. Note that only
|
|
immediate children are enumerated using this call. If you want to list all of the objects
|
|
of a subtree, you must use the <strong><a href="#search">Search</a></strong> function.</small></font></p>
|
|
<p><font face="Verdana"><small>' Visual Basic Sample: Enumerating children for a
|
|
given container</small><br>
|
|
<br>
|
|
<small>Set cont = GetObject("WinNT://INDEPENDENCE")<br>
|
|
For Each obj In cont<br>
|
|
Debug.Print obj.Name & " (" & obj.Class & ")"<br>
|
|
Next<br>
|
|
</small></font><br>
|
|
'<small><font face="Verdana">Source code can be found in the \samples\start\Enum\vb
|
|
directory.</font></small></p>
|
|
<p><font face="Verdana"><small>// Visual C++ Sample: Enumerating children for a given
|
|
container</small><br>
|
|
<br>
|
|
<small> ////////////////////////////////<br>
|
|
// Bind to a domain object<br>
|
|
////////////////////////////////<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE", IID_IADsContainer,
|
|
(void**) &pCont );<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
/////////////////////////////////<br>
|
|
// Enumerate<br>
|
|
/////////////////////////////////<br>
|
|
IEnumVARIANT *pEnum = NULL;<br>
|
|
hr = ADsBuildEnumerator( pCont, &pEnum );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
VARIANT var;<br>
|
|
ULONG lFetch;<br>
|
|
IADs *pChild=NULL;<br>
|
|
VariantInit(&var);<br>
|
|
<br>
|
|
while( SUCCEEDED(ADsEnumerateNext( pEnum, 1,
|
|
&var, &lFetch )) && lFetch == 1 )<br>
|
|
{<br>
|
|
hr =
|
|
V_DISPATCH(&var)->QueryInterface( IID_IADs, (void**) &pChild );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
|
|
BSTR bstrName;<br>
|
|
|
|
BSTR bstrClass;<br>
|
|
|
|
// Get more information on the child classes<br>
|
|
|
|
pChild->get_Name(&bstrName);<br>
|
|
|
|
pChild->get_Class(&bstrClass);<br>
|
|
<br>
|
|
|
|
printf("%S\t(%S)\n", bstrName, bstrClass );<br>
|
|
<br>
|
|
|
|
// Clean-up<br>
|
|
|
|
SysFreeString(bstrName);<br>
|
|
|
|
SysFreeString(bstrClass);<br>
|
|
<br>
|
|
|
|
pChild->Release();<br>
|
|
<br>
|
|
}<br>
|
|
VariantClear(&var);<br>
|
|
}<br>
|
|
<br>
|
|
}<br>
|
|
</small></font></p>
|
|
<p><font face="Verdana"><small>// Do not forget to free up the enumerator using <strong>ADsFreeEnumerator</strong>.<br>
|
|
if ( pEnum )<br>
|
|
{<br>
|
|
ADsFreeEnumerator( pEnum );<br>
|
|
}<br>
|
|
<br>
|
|
pCont->Release();</small></font></p>
|
|
|
|
<p><small><font face="Verdana">// Source code can be found in the \samples\start\Enum\vc
|
|
directory.</font></small></p>
|
|
<p><small><font face="Verdana">Back to <a href="#top">top</a></font></small></p>
|
|
|
|
<p><small><font face="Verdana" color="#0080C0"><strong> </strong></font></small></p>
|
|
|
|
<p><font face="Verdana" color="#0080C0"><strong><small><a name="readAttr"></a>Reading an attribute value on
|
|
an object</small></strong></font></p>
|
|
|
|
<p><font face="Verdana"><small>To read an attribute, you can use the <strong>IADs::Get</strong>
|
|
method for both Visual Basic and Visual C++. If you are a Visual C++ programmer, you
|
|
can also use the <strong>IDirectoryObject::GetObjectAttributes</strong> method. Note that <u>not</u>
|
|
all providers support the <strong>IDirectoryObject</strong> interface. </small></font></p>
|
|
|
|
<p><small><font face="Verdana">'--- Visual Basic Sample: Getting attributes with single
|
|
and multiple values</font></small></p>
|
|
|
|
<p><small><font face="Verdana">Set usr =
|
|
GetObject("WinNT://INDEPENDENCE/Administrator,user")<br>
|
|
|
|
<br>
|
|
|
|
'--- Reading an attribute with a single value<br>
|
|
Debug.Print usr.Name<br>
|
|
Debug.Print usr.FullName<br>
|
|
|
|
<br>
|
|
|
|
'Or you can also use generic <strong>Get</strong><br>
|
|
Debug.Print usr.Get("FullName")<br>
|
|
|
|
<br>
|
|
|
|
'--- Reading attributes with multiple values<br>
|
|
sid = usr.Get("objectSID")<br>
|
|
For Each sidByte In sid<br>
|
|
Debug.Print Hex(sidByte)<br>
|
|
Next<br>
|
|
<br>
|
|
'Or you can also use LBound and UBound for an attribute with multiple values.<br>
|
|
For i = LBound(sid) To UBound(sid)<br>
|
|
Debug.Print Hex(sid(i))<br>
|
|
Next i<br>
|
|
</font></small></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Read\vb
|
|
directory.</font></small></p>
|
|
<p> </p>
|
|
<p><small><font face="Verdana">'--- Visual C++ Sample: Getting attributes with single and
|
|
multiple values</font></small></p>
|
|
<p><font face="Verdana"><small> HRESULT hr;<br>
|
|
IADs *pUsr=NULL;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
////////////////////////////////////<br>
|
|
// Bind to a directory object<br>
|
|
////////////////////////////////////<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE/Administrator,user",
|
|
IID_IADs, (void**) &pUsr );</small><br>
|
|
<small> if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
//////////////////////////////////////////<br>
|
|
// Get an attribute with a single value<br>
|
|
//////////////////////////////////////////<br>
|
|
VARIANT var;<br>
|
|
VariantInit(&var);<br>
|
|
<br>
|
|
hr = pUsr->Get(L"FullName", &var );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
printf("FullName: %S\n",
|
|
V_BSTR(&var) );<br>
|
|
VariantClear(&var);<br>
|
|
}<br>
|
|
<br>
|
|
if ( pUsr )<br>
|
|
{<br>
|
|
pUsr->Release();<br>
|
|
}<br>
|
|
<br>
|
|
////////////////////////////////////////////////////////////////////<br>
|
|
// Get an attribute with a multiple value from a service object<br>
|
|
////////////////////////////////////////////////////////////////////<br>
|
|
IADs *pSvc = NULL;<br>
|
|
<br>
|
|
hr =
|
|
ADsGetObject(L"WinNT://INDEPENDENCE/ANDYHAR11/Browser,service", IID_IADs,
|
|
(void**) &pSvc );<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
hr = pSvc->Get(L"Dependencies", &var );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
LONG lstart, lend;<br>
|
|
SAFEARRAY *sa = V_ARRAY( &var );<br>
|
|
VARIANT varItem;<br>
|
|
<br>
|
|
// Get the lower and upper bound<br>
|
|
hr = SafeArrayGetLBound( sa, 1, &lstart );<br>
|
|
hr = SafeArrayGetUBound( sa, 1, &lend );<br>
|
|
<br>
|
|
// Now iterate and print the content<br>
|
|
VariantInit(&varItem);<br>
|
|
printf("Getting service dependencies using IADs
|
|
:\n");<br>
|
|
for ( long idx=lstart; idx < lend; idx++ )<br>
|
|
{<br>
|
|
hr =
|
|
SafeArrayGetElement( sa, &idx, &varItem );<br>
|
|
printf("%S ",
|
|
V_BSTR(&varItem));<br>
|
|
|
|
VariantClear(&varItem);<br>
|
|
}<br>
|
|
printf("\n");<br>
|
|
<br>
|
|
VariantClear(&var);<br>
|
|
}<br>
|
|
<br>
|
|
// Clean-up<br>
|
|
if ( pSvc )<br>
|
|
{<br>
|
|
pSvc->Release();<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
|
|
//////////////////////////////////////////////////////////////////////////<br>
|
|
// Using <strong>IDirectoryObject</strong> to get an attribute with
|
|
multiple values<br>
|
|
// Note: NOT all providers support this interface.<br>
|
|
|
|
/////////////////////////////////////////////////////////////////////////<br>
|
|
IDirectoryObject *pDirObject=NULL;<br>
|
|
ADS_ATTR_INFO *pAttrInfo=NULL;<br>
|
|
DWORD
|
|
|
|
dwReturn;<br>
|
|
LPWSTR
|
|
|
|
pAttrNames[]={L"objectClass" };<br>
|
|
DWORD
|
|
|
|
dwNumAttr=sizeof(pAttrNames)/sizeof(LPWSTR);<br>
|
|
<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://CN=Administrator,CN=Users,DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
|
|
IID_IDirectoryObject, <br>
|
|
|
|
(void**) &pDirObject );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
// Now get the attribute<br>
|
|
hr = pDirObject->GetObjectAttributes( pAttrNames, <br>
|
|
|
|
dwNumAttr, <br>
|
|
|
|
&pAttrInfo, <br>
|
|
|
|
&dwReturn );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
printf("Getting the objectClass multivalue
|
|
attribute using IDirectoryObject :\n");<br>
|
|
for (DWORD val=0; val <
|
|
pAttrInfo->dwNumValues; val++, pAttrInfo->pADsValues++) <br>
|
|
{<br>
|
|
|
|
printf(" %S\n", pAttrInfo->pADsValues->CaseIgnoreString);<br>
|
|
}<br>
|
|
FreeADsMem(pAttrInfo); // the pAttrInfo must be
|
|
freed using FreeADsMem<br>
|
|
}<br>
|
|
<br>
|
|
//Clean-up<br>
|
|
pDirObject->Release();<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
</small></font></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Read\vc
|
|
directory.</font></small></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="write"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Writing an attribute on an object</small></strong></font></p>
|
|
<p><font face="Verdana"><small>You can modify an attribute using the <strong>IADs::Put</strong>
|
|
and <strong>IADs::PutEx</strong> methods. For Visual C++, you can also use the <strong>IDirectoryObject::SetObjectAttributes
|
|
</strong>method.</small></font></p>
|
|
<p><small><font face="Verdana">'--- Visual Basic Sample: Setting attributes with
|
|
single and multiple values</font></small></p>
|
|
<p><small><font face="Verdana">'Bind to a user<br>
|
|
Set usr = GetObject("LDAP://CN=Jane
|
|
Johnson,OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com")<br>
|
|
<br>
|
|
'Modify single attributes<br>
|
|
usr.Put "givenName", "Jane"<br>
|
|
usr.Put "sn", "Johnson"<br>
|
|
<br>
|
|
'Modify multivalue attributes<br>
|
|
usr.Put "otherTelephone", Array("425 844 1234", "425 924
|
|
4321")<br>
|
|
<br>
|
|
'Commit to the directory<br>
|
|
usr.SetInfo</font></small></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Write\vb
|
|
directory.</font></small></p>
|
|
<p> </p>
|
|
<p><small><font face="Verdana">//--- Visual C++ Sample: Setting attributes with
|
|
single and multiple values</font></small></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IADs *pADs=NULL;<br>
|
|
LPWSTR pszADsPath = L"LDAP://CN=Jane
|
|
Johnson,OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com";<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
//////////////////////////////////////<br>
|
|
// Modifying attributes using <strong>IADs</strong><br>
|
|
//////////////////////////////////////<br>
|
|
hr = ADsGetObject(pszADsPath,<br>
|
|
IID_IADs, <br>
|
|
|
|
(void**) &pADs );<br>
|
|
<br>
|
|
if (!SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
VARIANT var;<br>
|
|
<br>
|
|
<br>
|
|
// We omit checking the result for brevity.<br>
|
|
<br>
|
|
// First Name<br>
|
|
VariantInit(&var);<br>
|
|
V_BSTR(&var) = SysAllocString(L"Jane");<br>
|
|
V_VT(&var) = VT_BSTR;<br>
|
|
hr = pADs->Put( L"givenName", var );<br>
|
|
<br>
|
|
// Last Name<br>
|
|
VariantClear(&var);<br>
|
|
V_BSTR(&var) = SysAllocString(L"Johnson");<br>
|
|
V_VT(&var) = VT_BSTR;<br>
|
|
hr = pADs->Put( L"givenName", var ); <br>
|
|
VariantClear(&var);<br>
|
|
<br>
|
|
<br>
|
|
// Other Telephones<br>
|
|
LPWSTR pszPhones[] = { L"425 844 1234", L"425 924
|
|
4321" };<br>
|
|
DWORD dwNumber = sizeof( pszPhones ) /sizeof(LPWSTR);<br>
|
|
<br>
|
|
hr = ADsBuildVarArrayStr( pszPhones, dwNumber, &var );<br>
|
|
hr = pADs->Put( L"otherTelephone", var ); <br>
|
|
VariantClear(&var);<br>
|
|
<br>
|
|
hr = pADs->SetInfo();<br>
|
|
pADs->Release();<br>
|
|
<br>
|
|
if (!SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
/////////////////////////////////////////////////////<br>
|
|
// Alternatively, you can use <strong>IDirectoryObject</strong><br>
|
|
/////////////////////////////////////////////////////<br>
|
|
IDirectoryObject *pDir=NULL;<br>
|
|
hr = ADsGetObject(pszADsPath,<br>
|
|
IID_IDirectoryObject, <br>
|
|
|
|
(void**) &pDir );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
DWORD dwReturn;<br>
|
|
ADSVALUE snValue;<br>
|
|
ADSVALUE fNameValue;<br>
|
|
ADSVALUE phoneValue[2];<br>
|
|
<br>
|
|
ADS_ATTR_INFO attrInfo[] = { <br>
|
|
{L"givenName",ADS_ATTR_UPDATE,
|
|
ADSTYPE_CASE_IGNORE_STRING,&snValue,1},<br>
|
|
{L"sn", ADS_ATTR_UPDATE,
|
|
ADSTYPE_CASE_IGNORE_STRING,&fNameValue,1 },<br>
|
|
{L"otherTelephone", ADS_ATTR_UPDATE,
|
|
ADSTYPE_CASE_IGNORE_STRING, phoneValue,2 }<br>
|
|
|
|
};<br>
|
|
DWORD dwAttrs = sizeof(attrInfo)/sizeof(ADS_ATTR_INFO); <br>
|
|
<br>
|
|
///// First Name ///////////<br>
|
|
fNameValue.dwType=ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
fNameValue.CaseIgnoreString = L"Johnson";<br>
|
|
<br>
|
|
<br>
|
|
///// Last Name ///////////<br>
|
|
snValue.dwType= ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
snValue.CaseIgnoreString = L"Johnson";<br>
|
|
<br>
|
|
///// Other Telephone ///////////<br>
|
|
phoneValue[0].dwType = ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
phoneValue[0].CaseIgnoreString = L"425 844 1234";<br>
|
|
<br>
|
|
phoneValue[1].dwType = ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
phoneValue[1].CaseIgnoreString = L"425 924 4321";<br>
|
|
<br>
|
|
hr = pDir->SetObjectAttributes(attrInfo, dwAttrs, &dwReturn);<br>
|
|
<br>
|
|
pDir->Release();<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
return 0;</font></small></p>
|
|
<p><small><font face="Verdana">//Source code can be found in the \samples\start\Write\vc
|
|
directory.</font></small></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="create"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Creating an object</small></strong></font></p>
|
|
<p><font face="Verdana"><small>To create an object, you can use the <strong>IADsContainer::Create</strong>
|
|
method for both Visaul Basic and Visual C++. You can also use the <strong>IDirectoryObject::CreateDSObject</strong>
|
|
method.</small></font></p>
|
|
<p><small><font face="Verdana">'-- Visual Basic Sample: Creating a user object</font></small></p>
|
|
<p><small><font face="Verdana">Set cont = GetObject("WinNT://INDEPENDENCE")<br>
|
|
<br>
|
|
'---- Creating a user<br>
|
|
Set usr = cont.Create("user", "JohnD")<br>
|
|
usr.FullName = "John Doe"<br>
|
|
usr.SetInfo</font></small></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Create\vb
|
|
directory.</font></small></p>
|
|
<p><small><font face="Verdana">//-- Visual C++ Sample: Creating a user object</font></small></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IADsContainer *pCont = NULL;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
hr = ADsGetObject( L"WinNT://INDEPENDENCE",
|
|
IID_IADsContainer, (void**) &pCont );<br>
|
|
if (!SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
IADs *pADs=NULL;<br>
|
|
IDispatch *pDisp=NULL;<br>
|
|
hr = pCont->Create(L"user", L"AliceW",
|
|
&pDisp );<br>
|
|
pCont->Release();<br>
|
|
<br>
|
|
if( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
hr = pDisp->QueryInterface( IID_IADs, (void**) &pADs );<br>
|
|
pDisp->Release();<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return 0;<br>
|
|
}<br>
|
|
<br>
|
|
pADs->SetInfo(); // Commit<br>
|
|
<br>
|
|
pADs->Release(); // Release<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>
|
|
///////////////////////////////////////////////////////////<br>
|
|
// Use <strong>IDirectoryObject</strong> to create an object.<br>
|
|
////////////////////////////////////////////////////////////<br>
|
|
IDirectoryObject *pDirObject=NULL;<br>
|
|
ADSVALUE sAMValue;<br>
|
|
ADSVALUE uPNValue;<br>
|
|
ADSVALUE classValue;<br>
|
|
<br>
|
|
<br>
|
|
ADS_ATTR_INFO attrInfo[] = <br>
|
|
{ <br>
|
|
{ L"objectClass", ADS_ATTR_UPDATE,
|
|
ADSTYPE_CASE_IGNORE_STRING, &classValue, 1 },<br>
|
|
{L"sAMAccountName", ADS_ATTR_UPDATE,
|
|
ADSTYPE_CASE_IGNORE_STRING, &sAMValue, 1},<br>
|
|
{L"userPrincipalName",
|
|
ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &uPNValue, 1},<br>
|
|
};</small><br>
|
|
<small><br>
|
|
DWORD dwAttrs = sizeof(attrInfo)/sizeof(ADS_ATTR_INFO); <br>
|
|
<br>
|
|
classValue.dwType = ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
classValue.CaseIgnoreString = L"user";<br>
|
|
<br>
|
|
sAMValue.dwType=ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
sAMValue.CaseIgnoreString = L"mikes";<br>
|
|
<br>
|
|
uPNValue.dwType=ADSTYPE_CASE_IGNORE_STRING;<br>
|
|
uPNValue.CaseIgnoreString = L"mikes@arcadiabay.com";<br>
|
|
<br>
|
|
// Create this user in an organizational unit<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
|
|
IID_IDirectoryObject, (void**) &pDirObject );<br>
|
|
<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
hr = pDirObject->CreateDSObject(
|
|
L"CN=Mike Smith", attrInfo, <br>
|
|
|
|
dwAttrs, &pDisp );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
pDisp->Release();<br>
|
|
}<br>
|
|
}<br>
|
|
pDirObject->Release();<br>
|
|
<br>
|
|
CoUninitialize();</small></font></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Create\vc
|
|
directory.</font></small></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="delete"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Deleting an object</small></strong></font></p>
|
|
<p><font face="Verdana"><small>You can use the <strong>IADsContainer::Delete</strong>
|
|
method in Visual Basic or Visual C++. You can also use the <strong>IDirectoryObject::DeleteDSObject</strong>
|
|
method to delete an object if you are using Visual C++.</small></font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Deleting a user object</small><br>
|
|
<small>Set cont = GetObject("WinNT://INDEPENDENCE")<br>
|
|
<br>
|
|
'---- Deleting a user<br>
|
|
cont.Delete "user", "JohnD"<br>
|
|
</small><br>
|
|
<small>'Source code can be found in the \samples\start\Delete\vb directory.</small></font></p>
|
|
<p><font face="Verdana"><br>
|
|
<small>//-- Visual C++ Sample: Deleting a user object using the <strong>IADsContainer::Delete</strong>
|
|
and <strong>IDirectoryObject::DeleteDSObject</strong> methods</small></font></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IADsContainer *pCont=NULL;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE", IID_IADsContainer,
|
|
(void**) &pCont);<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
///////////////////////////////////////////////////////<br>
|
|
// Using <strong>IADsContainer::Delete</strong> to delete a user<br>
|
|
///////////////////////////////////////////////////////<br>
|
|
hr = pCont->Delete(L"user", L"AliceW");<br>
|
|
pCont->Release();<br>
|
|
<br>
|
|
/////////////////////////////////////////////////////////////////////<br>
|
|
// Using <strong>IDirectoryObject::DeleteDSObject</strong> to delete a
|
|
user<br>
|
|
/////////////////////////////////////////////////////////////////////<br>
|
|
IDirectoryObject *pDirObject=NULL;<br>
|
|
<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
|
|
IID_IDirectoryObject, (void**) &pDirObject );<br>
|
|
<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
hr =
|
|
pDirObject->DeleteDSObject(L"CN=Mike Smith");<br>
|
|
pDirObject->Release();<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();</font></small></p>
|
|
<p><small><font face="Verdana">'Source code can be found in the \samples\start\Delete\vc
|
|
directory.</font></small></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="rename"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Renaming an object</small></strong></font></p>
|
|
<p><font face="Verdana"><small>You can rename an object using the <strong>IADsContainer::MoveHere</strong>
|
|
method. First, you must know the object's parent.</small></font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Renaming a user object using the <strong>IADsContainer::MoveHere</strong>
|
|
method</small> <br>
|
|
<small> </small><br>
|
|
<small> Set cont = GetObject("WinNT://INDEPENDENCE")<br>
|
|
<br>
|
|
'---- Renaming a user and updating its attributes<br>
|
|
Set usr = cont.MoveHere("WinNT://INDEPENDENCE/JSmith",
|
|
"JJohnson")<br>
|
|
usr.FullName = "Jane Johnson"<br>
|
|
usr.SetInfo<br>
|
|
</small><br>
|
|
<small>'Source code can be found in the \samples\start\Rename\vb directory.</small></font></p>
|
|
<p><font face="Verdana"><br>
|
|
<small>//-- Visual C++ Sample: Renaming a user object using the <strong>IADsContainer::MoveHere</strong>
|
|
method</small></font></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IADsContainer *pCont=NULL;<br>
|
|
IDispatch *pDisp=NULL;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE", IID_IADsContainer,
|
|
(void**) &pCont);<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
hr =
|
|
pCont->MoveHere(L"WinNT://INDEPENDENCE/JSmith",L"JJohnson",
|
|
&pDisp );<br>
|
|
<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
pDisp->Release();<br>
|
|
}<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>'Source code can be found in the \samples\start\Rename\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="move"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Moving an object</small></strong></font></p>
|
|
<p><font face="Verdana" color="#000000"><small>To move an object, you must bind to the
|
|
parent's destination first, then call the <strong>IADsContainer::MoveHere</strong> method.
|
|
Note that you can move and rename and object at the same time.</small></font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Moving user object using the <strong>IADsContainer::MoveHere</strong>
|
|
method</small></font></p>
|
|
<p><small><font face="Verdana">'Bind to the parent object's destination.<br>
|
|
Set cont =
|
|
GetObject("LDAP://OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com")<br>
|
|
<br>
|
|
'---- Moving a user from one organization to another.<br>
|
|
Set usr = cont.MoveHere("LDAP://CN=Mike
|
|
Smith,OU=MCS,DC=windows2000,DC=nttest,DC=microsoft,DC=com", vbNullString)<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>'Source code can be found in the \samples\start\Move\vb
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>//-- Visual C++ Sample: Moving a user object using the <strong>IADsContainer::MoveHere</strong>
|
|
method</small></font></p>
|
|
<p><small><font face="Verdana"> <br>
|
|
///////////////////////////////////////////////<br>
|
|
// First, bind to the destination container.<br>
|
|
///////////////////////////////////////////////<br>
|
|
HRESULT hr;<br>
|
|
IADsContainer *pCont=NULL;</font></small></p>
|
|
<p><small><font face="Verdana"> CoInitialize(NULL);<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://OU=MCS,DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
|
|
IID_IADsContainer,<br>
|
|
|
|
(void**) &pCont );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
///////////////////////////////////////////////////////<br>
|
|
// Now, move the object to the bound container.<br>
|
|
///////////////////////////////////////////////////////<br>
|
|
IDispatch *pDisp=NULL;<br>
|
|
<br>
|
|
hr = pCont->MoveHere(L"LDAP://CN=Mike
|
|
Smith,OU=DSys,DC=windows2000,DC=nttest,DC=microsoft,DC=com", NULL, &pDisp );<br>
|
|
pCont->Release();<br>
|
|
<br>
|
|
if (SUCCEEDED(hr) )<br>
|
|
{ <br>
|
|
// You may do another operation here, such as
|
|
updating attributes.<br>
|
|
pDisp->Release();<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>'Source code can be found in the \samples\start\Move\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="getObject"></a></p>
|
|
<p><small><font face="Verdana" color="#0080C0"><strong>Getting a child object</strong></font></small></p>
|
|
<p><font size="2" face="Verdana">In ADSI, a container object exposes an <b>IADsContainer</b>
|
|
interface. The <b>IADsContainer</b> interface has the <b>IADsContainer::GetObject</b>
|
|
method so that you can bind directly to a child object. Note that the object returned by
|
|
the <b>IADsContainer::GetObject</b> method has the same security context as the object on
|
|
which the method was called. This means that if you have pointer to a container object and
|
|
you know the relative path to a child object, you can avoid having to pass credentials
|
|
again when binding to the child object. This may be useful when your application is
|
|
binding using alternate credentials (that is, when it is not in the context of the logged
|
|
on user).</font></p>
|
|
<p><small><font face="Verdana">'-- Visual Basic Sample: Getting a child object</font></small></p>
|
|
<p><font face="Verdana"><small>'Bind to the parent container.<br>
|
|
Set cont = GetObject("WinNT://INDEPENDENCE")<br>
|
|
<br>
|
|
'---- Getting a child object from the container<br>
|
|
Set usr = cont.GetObject("user", "JJohnson")<br>
|
|
</small><br>
|
|
<small>'Source code can be found in the \samples\start\Child\vb directory.</small></font></p>
|
|
<p><font face="Verdana"><small>//Visual C++ Sample: Getting a child object</small></font></p>
|
|
<p><small><font face="Verdana">#define RETURN_ON_FAILURE(hr) if(!SUCCEEDED(hr)) return hr;</font><br>
|
|
</small></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
IADsContainer *pCont=NULL;<br>
|
|
<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
IID_IADsContainer, <br>
|
|
|
|
(void**) &pCont );<br>
|
|
<br>
|
|
RETURN_ON_FAILURE(hr);<br>
|
|
<br>
|
|
<br>
|
|
|
|
////////////////////////////////////////////////////////////////////////////<br>
|
|
// Get the child from the container.<br>
|
|
// Note in the LDAP provider you can go down more than one level.<br>
|
|
|
|
////////////////////////////////////////////////////////////////////////////<br>
|
|
IDispatch *pDisp = NULL;<br>
|
|
IADs *pADs = NULL;<br>
|
|
hr = pCont->GetObject(L"user", L"CN=Mike Smith,
|
|
OU=DSys", &pDisp );<br>
|
|
pCont->Release();<br>
|
|
<br>
|
|
RETURN_ON_FAILURE(hr);<br>
|
|
<br>
|
|
<br>
|
|
hr = pDisp->QueryInterface( IID_IADs, (void**) &pADs );<br>
|
|
pDisp->Release(); <br>
|
|
RETURN_ON_FAILURE(hr);<br>
|
|
<br>
|
|
// Do something with pADs here.<br>
|
|
pADs->Release();<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();</font></small></p>
|
|
<p><font face="Verdana"><small>// Source code can be found in the \samples\start\Child\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="parent"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><small><strong>Getting the parent of an object</strong></small></font></p>
|
|
<p><font size="2" face="Verdana">In ADSI, a directory object is represented by an ADSI COM
|
|
object, and every ADSI COM object exposes an <b>IADs</b> interface. The <b>IADs</b>
|
|
interface has the <b>IADs::get_Parent</b> method so that you can get the ADsPath for the
|
|
parent of the directory object. You can use that ADsPath to bind to the parent object.</font></p>
|
|
<p><small><font face="Verdana">'-- Visual Basic Sample: Getting a parent object</font></small></p>
|
|
<p><small><font face="Verdana">'Bind to an object.<br>
|
|
Set usr = GetObject("WinNT://INDEPENDENCE/JJohnson,user")<br>
|
|
<br>
|
|
'---- Getting a parent object using the <strong>IADs::get_Parent</strong> method.<br>
|
|
Set cont = GetObject(usr.Parent)<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>' Source code can be found in the \samples\start\Parent\vb
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small><small>//</small>-- Visual C++ Sample: Getting a parent
|
|
object</small><br>
|
|
<small> HRESULT hr;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
/////////////////////////////////////////<br>
|
|
//Bind to an object<br>
|
|
/////////////////////////////////////////<br>
|
|
IADs *pADs = NULL;<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE/JJohnson", IID_IADs,
|
|
(void**) &pADs );<br>
|
|
if (!SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
BSTR bstrParent;<br>
|
|
IADs *pParent=NULL;<br>
|
|
<br>
|
|
/////////////////////////////////<br>
|
|
// Get the ADs Parent's Path<br>
|
|
/////////////////////////////////<br>
|
|
pADs->get_Parent(&bstrParent);<br>
|
|
pADs->Release();<br>
|
|
<br>
|
|
////////////////////////////////<br>
|
|
// Bind to the Parent<br>
|
|
////////////////////////////////<br>
|
|
hr = ADsGetObject( bstrParent, IID_IADs, (void**) &pParent );<br>
|
|
SysFreeString(bstrParent);<br>
|
|
<br>
|
|
<br>
|
|
if (SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
// Do something with pParent.<br>
|
|
pParent->Release();<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();</small><br>
|
|
</font></p>
|
|
<p><font face="Verdana"><small>// Source code can be found in the \samples\start\Parent\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><a name="search"></a></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small>Searching for a set of objects</small></strong></font></p>
|
|
<p><font face="Verdana"><small>You must use ADO to perform searches when using Visual
|
|
Basic. If you use Visual C++, you can also use the <strong>IDirectorySearch</strong>
|
|
interface.</small></font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Searching for all groups</small><br>
|
|
<small>Dim con As New Connection, rs As New Recordset<br>
|
|
Dim Com As New Command<br>
|
|
<br>
|
|
'Open a Connection object<br>
|
|
con.Provider = "ADsDSOObject"<br>
|
|
con.Open "Active Directory Provider"<br>
|
|
<br>
|
|
' Create a command object on this connection<br>
|
|
Set Com.ActiveConnection = con<br>
|
|
Com.CommandText = "select name from
|
|
'LDAP://DC=windows2000,DC=nttest,DC=microsoft,DC=com' where objectCategory='group' ORDER
|
|
BY NAME"<br>
|
|
<br>
|
|
Set rs = Com.Execute<br>
|
|
<br>
|
|
'--------------------------------------<br>
|
|
' Navigate the record set<br>
|
|
'----------------------------------------<br>
|
|
While Not rs.EOF<br>
|
|
Debug.Print rs.Fields("Name")<br>
|
|
rs.MoveNext<br>
|
|
Wend<br>
|
|
</small></font></p>
|
|
<p><font face="Verdana"><small>' Source code can be found in the \samples\start\Search\vb
|
|
directory.</small></font></p>
|
|
<p><small><font face="Verdana">//-- Visual C++ Sample: Searching for all groups</font></small></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IDirectorySearch *pSearch;<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
<br>
|
|
///////////////////////////////////////////////////////<br>
|
|
// Bind to the object, it serves as a base search<br>
|
|
//////////////////////////////////////////////////////<br>
|
|
hr =
|
|
ADsGetObject(L"LDAP://DC=windows2000,DC=nttest,DC=microsoft,DC=com",<br>
|
|
IID_IDirectorySearch,<br>
|
|
|
|
(void**) &pSearch );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
///////////////////////////////////////<br>
|
|
// Perform a subtree search<br>
|
|
/////////////////////////////////////////<br>
|
|
ADS_SEARCHPREF_INFO prefInfo[1];<br>
|
|
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;<br>
|
|
prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;<br>
|
|
prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;<br>
|
|
hr = pSearch->SetSearchPreference( prefInfo, 1);<br>
|
|
<br>
|
|
////////////////////////////////////<br>
|
|
// Prepare for attribute return<br>
|
|
////////////////////////////////////<br>
|
|
LPWSTR pszAttr[] = { L"Name"};<br>
|
|
ADS_SEARCH_HANDLE hSearch;<br>
|
|
DWORD dwCount= sizeof(pszAttr)/sizeof(LPWSTR);<br>
|
|
<br>
|
|
<br>
|
|
//////////////////////////////////////////<br>
|
|
// Search for all groups in a domain<br>
|
|
//////////////////////////////////////////<br>
|
|
hr = pSearch->ExecuteSearch(L"(objectCategory=Group)",
|
|
pszAttr, dwCount, &hSearch );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
pSearch->Release();<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
//////////////////////////////////////////<br>
|
|
// Now enumerate the result<br>
|
|
//////////////////////////////////////////<br>
|
|
ADS_SEARCH_COLUMN col;<br>
|
|
while( pSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS )<br>
|
|
{<br>
|
|
// Get 'Name' attribute<br>
|
|
hr = pSearch->GetColumn( hSearch,
|
|
pszAttr[0], &col );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
|
|
printf("%S\n", col.pADsValues->CaseIgnoreString);<br>
|
|
pSearch->FreeColumn(
|
|
&col ); // You need to FreeColumn after use.<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
}<br>
|
|
<br>
|
|
////////////////////<br>
|
|
// Clean-up<br>
|
|
////////////////////<br>
|
|
pSearch->CloseSearchHandle(hSearch);<br>
|
|
pSearch->Release();<br>
|
|
<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>// Source code can be found in the \samples\start\Search\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p> </p>
|
|
<p><a name="filter"></a><font face="Verdana" color="#0080C0"><strong><small>Filtering a
|
|
set of objects</small></strong></font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Getting groups and users</small></font></p>
|
|
<p><small><font face="Verdana">'Bind to a domain object<br>
|
|
Set dom = GetObject("WinNT://INDEPENDENCE")<br>
|
|
<br>
|
|
'Show all users and groups<br>
|
|
dom.Filter = Array("user", "group")<br>
|
|
For Each obj In dom<br>
|
|
Debug.Print obj.Name & " (" & obj.Class &
|
|
")"<br>
|
|
Next</font></small></p>
|
|
<p><font face="Verdana"><small>' Source code can be found in the \samples\start\Filter\vb
|
|
directory.</small></font></p>
|
|
<p><small><font face="Verdana">// -- Visual C++ Sample: Getting groups and users</font></small></p>
|
|
<p><small><font face="Verdana"> HRESULT hr;<br>
|
|
IADsContainer *pCont=NULL;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
///////////////////////////////////<br>
|
|
// Bind to the object<br>
|
|
//////////////////////////////////<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE", IID_IADsContainer,
|
|
(void**) &pCont );<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
///////////////////////////////////<br>
|
|
// Build variant filter<br>
|
|
//////////////////////////////////<br>
|
|
LPWSTR pszFilter[] = { L"user", L"group" };<br>
|
|
DWORD dwNumber = sizeof( pszFilter ) /sizeof(LPWSTR);<br>
|
|
VARIANT var;<br>
|
|
<br>
|
|
hr = ADsBuildVarArrayStr( pszFilter, dwNumber, &var );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
pCont->Release();<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
///////////////////////////////////<br>
|
|
// Set the filter<br>
|
|
//////////////////////////////////<br>
|
|
<br>
|
|
hr = pCont->put_Filter(var);<br>
|
|
VariantClear(&var);<br>
|
|
<br>
|
|
if (!SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
pCont->Release();<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
////////////////////////////////////////////<br>
|
|
// Enumerate the result<br>
|
|
////////////////////////////////////////////<br>
|
|
IEnumVARIANT *pEnum = NULL;<br>
|
|
hr = ADsBuildEnumerator( pCont, &pEnum );<br>
|
|
pCont->Release(); // This is no longer needed, since we have the
|
|
enumerator already.<br>
|
|
<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
VARIANT var;<br>
|
|
ULONG lFetch;<br>
|
|
IADs *pChild=NULL;<br>
|
|
VariantInit(&var);<br>
|
|
<br>
|
|
while( SUCCEEDED(ADsEnumerateNext( pEnum, 1,
|
|
&var, &lFetch )) && lFetch == 1 )<br>
|
|
{<br>
|
|
hr =
|
|
V_DISPATCH(&var)->QueryInterface( IID_IADs, (void**) &pChild );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
|
|
BSTR bstrName;<br>
|
|
|
|
BSTR bstrClass;<br>
|
|
|
|
// Get more information on the child classes<br>
|
|
|
|
pChild->get_Name(&bstrName);<br>
|
|
|
|
pChild->get_Class(&bstrClass);<br>
|
|
|
|
<br>
|
|
|
|
printf("%S\t\t(%S)\n", bstrName, bstrClass );<br>
|
|
|
|
<br>
|
|
|
|
// Clean-up<br>
|
|
|
|
SysFreeString(bstrName);<br>
|
|
|
|
SysFreeString(bstrClass);<br>
|
|
|
|
<br>
|
|
|
|
pChild->Release();<br>
|
|
}<br>
|
|
VariantClear(&var);<br>
|
|
}<br>
|
|
}<br>
|
|
<br>
|
|
CoUninitialize();<br>
|
|
</font></small></p>
|
|
<p><font face="Verdana"><small>// Source code can be found in the \samples\start\Filter\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><br>
|
|
</strong></font><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p><small><strong><font face="Verdana" color="#0080C0"> </font></strong></small></p>
|
|
<p><font face="Verdana" color="#0080C0"><strong><small><a name="readSchema"></a>Reading the Schema</small></strong></font></p>
|
|
<p><font face="Verdana"><small>Most providers support the schema. The schema contains
|
|
class and attribute definitions. ADSI abstracts the schema in the well known location,
|
|
Provider://schema. Some providers may prefer to use the real schema for schema operations.
|
|
Each object carries the schema location in which its class is defined. This
|
|
information can be obtained using the <strong>IADs::get_Class</strong> method.</small><br>
|
|
</font></p>
|
|
<p><font face="Verdana"><small>'-- Visual Basic Sample: Listing a schema information</small><br>
|
|
<small>'Bind to a schema container<br>
|
|
Set Scm = GetObject("WinNT://INDEPENDENCE/Schema")<br>
|
|
<br>
|
|
'Show all items in the schema container<br>
|
|
For Each obj In Scm<br>
|
|
Debug.Print obj.Name & " (" & obj.Class &
|
|
")"<br>
|
|
Next<br>
|
|
<br>
|
|
'You can also bind to an object and get the schema location<br>
|
|
Set dom = GetObject("WinNT://INDEPENDENCE")<br>
|
|
Debug.Print dom.Schema<br>
|
|
Set Class = GetObject(dom.Schema)<br>
|
|
'Mandatory attributes<br>
|
|
For Each prop In Class.MandatoryProperties<br>
|
|
Debug.Print prop<br>
|
|
Next<br>
|
|
<br>
|
|
'Optional attributes<br>
|
|
For Each prop In Class.OptionalProperties<br>
|
|
Debug.Print prop<br>
|
|
Next<br>
|
|
</small></font></p>
|
|
<p><font face="Verdana"><small>'Source code can be found in the \samples\start\Schema\vb
|
|
directory.</small></font></p>
|
|
<p> </p>
|
|
<p><small><font face="Verdana">//-- Visual C++ Sample: Listing schema information</font></small></p>
|
|
<p><small><font face="Verdana"> IADsContainer *pSchema=NULL;<br>
|
|
HRESULT hr;<br>
|
|
<br>
|
|
CoInitialize(NULL);<br>
|
|
<br>
|
|
hr = ADsGetObject(L"WinNT://INDEPENDENCE/Schema",
|
|
IID_IADsContainer, (void**) &pSchema );<br>
|
|
<br>
|
|
if ( !SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
return hr;<br>
|
|
}<br>
|
|
<br>
|
|
<br>
|
|
////////////// Enumerate Schema objects
|
|
///////////////////////////////////<br>
|
|
IEnumVARIANT *pEnum = NULL;<br>
|
|
hr = ADsBuildEnumerator( pSchema, &pEnum );<br>
|
|
pSchema->Release(); // This is no longer needed, since we have the
|
|
enumerator already.<br>
|
|
<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
VARIANT var;<br>
|
|
ULONG lFetch;<br>
|
|
IADs *pChild=NULL;<br>
|
|
VariantInit(&var);<br>
|
|
<br>
|
|
while( SUCCEEDED(ADsEnumerateNext( pEnum, 1,
|
|
&var, &lFetch )) && lFetch == 1 )<br>
|
|
{<br>
|
|
hr =
|
|
V_DISPATCH(&var)->QueryInterface( IID_IADs, (void**) &pChild );<br>
|
|
if ( SUCCEEDED(hr) )<br>
|
|
{<br>
|
|
|
|
BSTR bstrName;<br>
|
|
|
|
BSTR bstrClass;<br>
|
|
|
|
// Get more information on the child classes<br>
|
|
|
|
pChild->get_Name(&bstrName);<br>
|
|
|
|
pChild->get_Class(&bstrClass);<br>
|
|
|
|
<br>
|
|
|
|
printf("%S\t\t(%S)\n", bstrName, bstrClass );<br>
|
|
|
|
<br>
|
|
|
|
// Clean-up<br>
|
|
|
|
SysFreeString(bstrName);<br>
|
|
|
|
SysFreeString(bstrClass);<br>
|
|
|
|
<br>
|
|
|
|
pChild->Release();<br>
|
|
}<br>
|
|
VariantClear(&var);<br>
|
|
}<br>
|
|
}<br>
|
|
<br>
|
|
CoUninitialize();</font></small></p>
|
|
<p><font face="Verdana"><small>// Source code can be found in the \samples\start\Schema\vc
|
|
directory.</small></font></p>
|
|
<p><font face="Verdana"><small>Back to <a href="#top">top</a></small></font></p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </small></strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td width="2%" height="21"></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p> </p>
|
|
|
|
<p> </p>
|
|
|
|
<p><font SIZE="2"> </p>
|
|
|
|
<p></font> </p>
|
|
|
|
<p> </p>
|
|
</body>
|
|
</html>
|