Example Code for Creating a Container Object
The following code example creates two objects. First, a container object and, second, a sub-container object. A value for the sub-container object is added to the otherWellKnownObjects property of the container object. The code example binds to the sub-container object using the WKGUID binding and displays its ADsPath. It then renames the sub-container object and binds again using the same WKGUID binding.
#define _WIN32_WINNT 0x0501
#include "resource.h"
#include <atlbase.h>
#include <atlcom.h>
#pragma comment(lib, "Activeds.lib")
#pragma comment(lib, "adsiid.Lib")
#include <atlenc.h>
#include <activeds.h>
#include <stdio.h>
void wmain( int argc, wchar_t *argv[ ])
HRESULT hr = S_OK;
CComPtr<IADs> pObject ;
CComPtr<IADsContainer> pDomain ;
IDispatch *pDisp = NULL;
CComPtr<IADsContainer> pNewContainer ;
CComPtr<IADs> pIADsObject, pNewObject, pTestWKO1, pTestWKO2;
CComVariant vartest, var;
CComBSTR bstr, szNewContainerDN (MAX_PATH),
szPath(MAX_PATH),
szRelPath(MAX_PATH);
// Names of the container and child object.
CComBSTR szContainer ( L"MyWKOTestContainer"),
szNewObject ( L"MyWKOTestObject"),
szNewObjectRenameRDN ( L"cn=ObjectwithNEWNAME");
// Get rootDSE and the domain container DN.
hr = ADsGetObject(L"LDAP://rootDSE", IID_IADs, (void**)&pObject);
if (FAILED(hr))
{
wprintf(L"Not Found. Cannot bind to the domain.\n");
return hr;
}
hr = pObject->Get(CComBSTR(L"defaultNamingContext"),&var);
if (SUCCEEDED(hr))
{
// Build the ADsPath to the domain.
szPath = L"LDAP://";
szPath.AppendBSTR(var.bstrVal);
var.Clear();
// Bind to the current domain.
hr = ADsGetObject(szPath, IID_IADsContainer, (void**)&pDomain);
if (SUCCEEDED(hr))
{
// Create the container.
szRelPath = L"cn=";
szRelPath += szContainer;
hr = pDomain->Create(CComBSTR(L"container"),
// ldapDisplayName of the class
// of the object to create.
szRelPath, // Relative path in RDN=value format.
&pDisp); // Return an IDispatch pointer to new object.
if (SUCCEEDED(hr))
{
// Call the QueryInterface method for an IADs interface.
hr = pDisp->QueryInterface(&pIADsObject);
pDisp->Release();
// Commit the new object to the directory.
hr = pIADsObject->SetInfo();
// Call the QueryInterface method for an IADsContainer interface.
hr = pDisp->QueryInterface(&pNewContainer);
if (SUCCEEDED(hr))
{
// Create the new container object in the container.
szRelPath = L"cn=";
szRelPath += szNewObject;
hr = pNewContainer->Create(CComBSTR(L"container"),
szRelPath,
&pDisp);
if (SUCCEEDED(hr))
{
// Get the DN of the new container object.
hr = pIADsObject->Get(CComBSTR(L"distinguishedName"), &var);
if (SUCCEEDED(hr))
{
szNewContainerDN = var.bstrVal;
var.Clear();
wprintf(L"Created new container with DN: %s\n",szNewContainerDN);
hr = pDisp->QueryInterface(&pNewObject);
pDisp->Release();
if (SUCCEEDED(hr))
{
// Commit the new object to the directory.
hr = pNewObject->SetInfo();
// Get the DN for the new object.
hr = pNewObject->Get(CComBSTR(L"distinguishedName"), &var);
if (SUCCEEDED(hr))
{
wprintf(L"Created new child object with DN: %s\n",var.bstrVal);
// Use LDAP API to set the otherWellKnownObjects property.
wprintf(L"Call AddValueToOtherWKOProperty with:\n");
wprintf(L"szContainer DN: %s\n",szNewContainerDN);
wprintf(L"pWKOGUID (bindable string format): %s\n",
MyWKOTestObjectGUID);
wprintf(L"szWKOObjectDN: %s\n",var.bstrVal);
hr = AddValueToOtherWKOProperty(
pNewObject,
szNewContainerDN, // DN for container whose
// otherWellKnownObjects
// property to modify.
MyWKOTestObjectGUID, // WKO GUID for the well-known object
var.bstrVal // DN of the well-known object.
);
wprintf(L"AddValueToOtherWKOProperty returned: %x\n",hr);
if (SUCCEEDED(hr))
{
// Bind using WKGUID binding.
// Build the ADsPath to the well-known object.
szPath = L"LDAP://<WKGUID=";
szPath += MyWKOTestObjectGUID;
szPath += L",";
szPath += szNewContainerDN;
szPath += L">";
wprintf(L"Bind with the following WKGUID binding string: %s\n",
szPath);
hr = ADsGetObject(szPath,IID_IADs, (void**)&pTestWKO1);
if (SUCCEEDED(hr))
{
hr = pTestWKO1->Get(CComBSTR(L"distinguishedName"),
&vartest);
if (SUCCEEDED(hr))
{
wprintf(L"Successfully bound to object. DN: %s\n",
vartest.bstrVal);
vartest.Clear();
}
}
else
wprintf(L"Binding failed with hr: %x\n",hr);
// Bind again using the DN to get a regular ADsPath.
szPath = L"LDAP://";
szPath += var.bstrVal;
hr = ADsGetObject(szPath, IID_IADs, (void**)&pTestWKO1);
hr = pTestWKO1->get_ADsPath(&bstr);
// Rename the WKO object.
hr = pNewContainer->MoveHere(bstr, szNewObjectRenameRDN,NULL);
pTestWKO1.Release();
// Bind again using WKGUID binding.
// Build the ADsPath to the well-known object.
szPath = L"LDAP://<WKGUID=";
szPath += MyWKOTestObjectGUID;
szPath += L",";
szPath += szNewContainerDN;
szPath += L">";
wprintf(
L"Bind AGAIN with the following WKGUID binding string: %s\n",
szPath
);
hr = ADsGetObject(szPath, IID_IADs, (void**)&pTestWKO2);
if (SUCCEEDED(hr))
{
hr = pTestWKO2->Get(CComBSTR(L"distinguishedName"),
&vartest);
if (SUCCEEDED(hr))
{
wprintf(L"Successfully bound to object. ");
wprintf(L"Be aware that the DN reflects the rename.");
wprintf(L" DN: %s\n",vartest.bstrVal);
vartest.Clear();
}
}
else
wprintf(L"Binding failed with hr: %x\n",hr);
}
}
}
}
}
}
// Offer user the option to delete test containers.
wprintf(L"Delete the test container and object (Y/N):");
CComBSTR pszBuffer(MAX_PATH * 2);
_getws_s(pszBuffer, MAX_PATH * 2);
if (pszBuffer == L"Y" )
{
// Delete the object.
// Delete the container.
hr = pNewContainer->Delete(CComBSTR(L"container"),
szNewObjectRenameRDN);
if (SUCCEEDED(hr))
{
wprintf(L"Test object successfully deleted.\n");
szRelPath = L"cn=";
szRelPath += szContainer;
// Delete the container.
hr = pDomain->Delete(CComBSTR(L"container"), szRelPath);
if (SUCCEEDED(hr))
wprintf(L"Test container and its contents successfully deleted.\n");
else
wprintf(L"Failed to delete test container. hr: %x\n",hr);
}
else
wprintf(L"Failed to delete test container. hr: %x\n",hr);
}
hr = S_FALSE;
}
}
}
}
// converts hexadecimal string to a octet encoded byte
array STDMETHODIMP ConvertHexGuidToArray(PCWSTR hexGuid, LPSAFEARRAY *sa) throw() {
if (hexGuid == NULL) return E_INVALIDARG;
int hexLen = (int)wcslen(hexGuid);
HRESULT hr = S_OK;
CTempBuffer<CHAR> sHex(hexLen);
int loopLen = hexLen;
// make ansi
while(loopLen-- != 0)
sHex[loopLen] = (CHAR) hexGuid[loopLen];
SAFEARRAY *temp= SafeArrayCreateVector(VT_UI1, 0, hexLen / 2);
if (temp == NULL)
hr = E_OUTOFMEMORY;
PBYTE dst ;
if (hr == S_OK) hr = SafeArrayAccessData(temp, (void**)&dst);
int dstLen = hexLen /2;
if (hr == S_OK)
{
AtlHexDecode(sHex, hexLen, dst, &dstLen );
hr = SafeArrayUnaccessData(temp);
*sa = temp;
}
return hr;
}
HRESULT AddValueToOtherWKOProperty(IADs *pads,
LPOLESTR szContainerDN,
// DN for container
// whose otherWellKnownObjects
// property to modify.
PCWSTR pWKOGUID, // WKO GUID for the WKO.
BSTR szWKOObjectDN // DN of the WKO.
)
{
HRESULT hr = E_FAIL;
CComPtr<IADsDNWithBinary> pdnWithBin;
CComBSTR retGuid;
pdnWithBin.CoCreateInstance(CLSID_DNWithBinary);
CComVariant v;
v.vt = VT_UI1 | VT_ARRAY;
ConvertHexGuidToArray(pWKOGUID, &v.parray);
hr = pdnWithBin->put_DNString(szWKOObjectDN);
hr = pdnWithBin->put_BinaryValue(v);
v.Clear();
v.vt = VT_DISPATCH;
pdnWithBin.QueryInterface(&v.pdispVal);
SAFEARRAY *psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
VARIANT *varray = (VARIANT*)psa->pvData;
VariantCopy(&varray[0] ,&v);
CComVariant v2;
v2.vt = VT_VARIANT | VT_ARRAY;
v2.parray = psa;
hr = pads->PutEx(ADS_PROPERTY_APPEND,
CComBSTR(L"otherWellKnownObjects"),
v2);
return hr;
}