Directory Services

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.

#include <wchar.h>
#include <objbase.h>
#include <activeds.h>
 
// Ensure that you define Unicode.
// Define version 5 for Windows 2000.
#define _WIN32_WINNT 0x0500
// For LDAP API.
#include <winldap.h>
// Link against the following library:
// wldap32.lib
 
 
static GUID MyWKOTestObjectGUID = { /* df447b5e-aa5b-11d2-8d53-00c04f79ab81 */
	0xdf447b5e,
	0xaa5b,
	0x11d2,
	{0x8d, 0x53, 0x00, 0xc0, 0x4f, 0x79, 0xab, 0x81}
  };
 
 
 
HRESULT GUIDtoBindableString (LPGUID pGUID, LPOLESTR *ppGUIDString);
 
HRESULT AddValueToOtherWKOProperty(LPOLESTR szContainerDN, // DN for container whose otherWellKnownObjects property to modify.
								 LPGUID pWKOGUID, // WKO GUID for the well-known object.
								 LPOLESTR szWKOObjectDN // DN of the well-known object.
								 );
 
 
 
 
void wmain( int argc, wchar_t *argv[ ])
{
 
LPOLESTR pszBuffer = new OLECHAR[MAX_PATH*2];
	wprintf(L"This program does the following:\n");
	wprintf(L"1. Creates a container (MyWKOTestContainer) in the current Window 2000 domain.\n");
	wprintf(L"2. Creates a container object (MyWKOTestObject) within the container.\n");
	wprintf(L"3. Adds a value for the container object on the otherWellKnownObject property of the container.\n");
	wprintf(L"4. Binds to the container object using WKGUID binding string.\n");
	wprintf(L"5. Renames the container object using WKGUID binding string.\n");
	wprintf(L"6. Binds to the container object using WKGUID binding string.\n");
	wprintf(L"7. Optionally, cleans up by removing the container and container object.\n\n");


// Intialize COM.
CoInitialize(NULL);
 
HRESULT hr = S_OK;
IADs *pObject = NULL;
IADsContainer *pDomain = NULL;
IDispatch *pDisp = NULL;
IDispatch *pDispNewObject = NULL;
IADsContainer *pNewContainer = NULL;
IADs *pIADsObject = NULL;
IADs *pNewObject = NULL;
IADs *pTestWKO1 = NULL;
IADs *pTestWKO2 = NULL;
VARIANT vartest;
VARIANT var;
BSTR bstr = NULL;
 
LPOLESTR szNewContainerDN = new OLECHAR[MAX_PATH];
LPOLESTR szPath = new OLECHAR[MAX_PATH];
LPOLESTR szRelPath = new OLECHAR[MAX_PATH];
LPOLESTR szGUIDString = NULL;
 
// Names of the container and child object.
LPOLESTR szContainer = L"MyWKOTestContainer";
LPOLESTR szNewObject = L"MyWKOTestObject";
 
LPOLESTR szNewObjectRenameRDN = L"cn=ObjectwithNEWNAME";

// Initialize Variants.
VariantInit(&var);
VariantInit(&vartest);
 
// Get rootDSE and the domain container DN.
hr = ADsOpenObject(L"LDAP://rootDSE",
				 NULL,
				 NULL,
				 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
				 IID_IADs,
				 (void**)&pObject);
if (FAILED(hr))
{
   wprintf(L"Not Found. Cannot bind to the domain.\n");
   if (pObject)
	 pObject->Release();
   goto Cleanup;
}
 
hr = pObject->Get(_bstr_t("defaultNamingContext"),&var);
if (SUCCEEDED(hr))
{
	// Build the ADsPath to the domain.
	wcsncpy(szPath,L"LDAP://", MAX_PATH);
	wcsncat(szPath,var.bstrVal, MAX_PATH-wcslen(szPath));
	VariantClear(&var);
	// Bind to the current domain.
	hr = ADsOpenObject(szPath,
					 NULL,
					 NULL,
					 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
					 IID_IADsContainer,
					 (void**)&pDomain);
	if (SUCCEEDED(hr))
	{
	// Create the container.
	wcsncpy(szRelPath,L"cn=",MAX_PATH);
	wcsncat(szRelPath,szContainer,MAX_PATH-wcslen(szRelPath));
	hr = pDomain->Create(_bstr_t("container"), // ldapDisplayName of the class of the object to create.
						 _bstr_t(szRelPath), // Relative path in RDN=value format.
							&pDisp); // Return an IDispatch pointer to the new object.
	if (SUCCEEDED(hr))
	{
		// QI for an IADs interface.
		hr = pDisp->QueryInterface(IID_IADs, (void **)&pIADsObject);
		// Commit the new object to the directory.
		hr = pIADsObject->SetInfo();
		// QI for an IADsContainer interface.
		hr = pDisp->QueryInterface(IID_IADsContainer, (void **)&pNewContainer);
		if (SUCCEEDED(hr))
		{
		// Create the new container object in the container.
		wcsncpy(szRelPath,L"cn=",MAX_PATH);
		wcsncat(szRelPath,szNewObject,MAX_PATH-wcslen(szRelPath));
		hr = pNewContainer->Create(_bstr_t("container"), // ldapDisplayName of the class of the object to create.
					 _bstr_t(szRelPath), // Relative path in RDN=value format.
					 &pDispNewObject); // Return an IDispatch pointer to the new object.
		if (SUCCEEDED(hr))
		{
			// Get the DN of the new container object.
			hr = pIADsObject->Get(_bstr_t("distinguishedName"), &var);
			if (SUCCEEDED(hr))
			{
			wcsncpy(szNewContainerDN, var.bstrVal,MAX_PATH);
			VariantClear(&var);
			wprintf(L"Created new container with DN: %s\n",szNewContainerDN);
			hr = pDispNewObject->QueryInterface(IID_IADs, (void **)&pNewObject);
			if (SUCCEEDED(hr))
			{
				// Commit the new object to the directory.
				hr = pNewObject->SetInfo();
				// Get the DN for the new object.
				hr = pNewObject->Get(_bstr_t("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);
				GUIDtoBindableString (&MyWKOTestObjectGUID, &szGUIDString);
				wprintf(L"pWKOGUID (bindable string format): %s\n",szGUIDString);
				wprintf(L"szWKOObjectDN: %s\n",var.bstrVal);
				hr = AddValueToOtherWKOProperty(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.
					wcsncpy(szPath,L"LDAP://<WKGUID=", MAX_PATH);
					wcsncat(szPath,szGUIDString, MAX_PATH-wcslen(szPath));
					wcsncat(szPath,L",", MAX_PATH-wcslen(szPath));
					wcsncat(szPath,szNewContainerDN, MAX_PATH-wcslen(szPath));
					wcsncat(szPath,L">", MAX_PATH-wcslen(szPath));
					wprintf(L"Bind with the following WKGUID binding string: %s\n",szPath);
					hr = ADsOpenObject(szPath,
						 NULL,
						 NULL,
						 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
						 IID_IADs,
						 (void**)&pTestWKO1);
					if (SUCCEEDED(hr))
					{
						hr = pTestWKO1->Get(_bstr_t("distinguishedName"),&vartest);
							if (SUCCEEDED(hr))
						{
							wprintf(L"Successfully bound to object. DN: %s\n",vartest.bstrVal);
							VariantClear(&vartest);
					}
				}
					else
						wprintf(L"Binding failed with hr: %x\n",hr);
				
					if (pTestWKO1)
						pTestWKO1->Release();
					// Bind again using the DN to get a regular ADsPath.
					wcsncpy(szPath,L"LDAP://", MAX_PATH);
					wcsncat(szPath,var.bstrVal, MAX_PATH-wcslen(szPath));
					hr = ADsOpenObject(szPath,
						 NULL,
						 NULL,
						 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
						 IID_IADs,
						 (void**)&pTestWKO1);
					hr = pTestWKO1->get_ADsPath(&bstr);
					// Rename the WKO object.
					hr = pNewContainer->MoveHere(bstr,_bstr_t(szNewObjectRenameRDN),NULL);
					FreeADsStr(bstr);
					if (pTestWKO1)
						pTestWKO1->Release();
					// Bind again using WKGUID binding.
					// Build the ADsPath to the well-known object.
					wcsncpy(szPath,L"LDAP://<WKGUID=", MAX_PATH);
					wcsncat(szPath,szGUIDString, MAX_PATH-wcslen(szPath));
					wcsncat(szPath,L",", MAX_PATH-wcslen(szPath));
					wcsncat(szPath,szNewContainerDN, MAX_PATH-wcslen(szPath));
					wcsncat(szPath,L">", MAX_PATH-wcslen(szPath));
					wprintf(L"Bind AGAIN with the following WKGUID binding string: %s\n",szPath);
					hr = ADsOpenObject(szPath,
						 NULL,
						 NULL,
						 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
						 IID_IADs,
						 (void**)&pTestWKO2);
					if (SUCCEEDED(hr))
					{
						hr = pTestWKO2->Get(_bstr_t("distinguishedName"),&vartest);
						if (SUCCEEDED(hr))
						{
							wprintf(L"Successfully bound to object (Be aware that the DN reflects the rename). DN: %s\n",vartest.bstrVal);
							VariantClear(&vartest);
					}
				}
					else
						wprintf(L"Binding failed with hr: %x\n",hr);
			}
				CoTaskMemFree(szGUIDString);
			}
		}
			if (pNewObject)
				pNewObject->Release();
		}
			VariantClear(&var);
	}
		if (pIADsObject)
			pIADsObject->Release();
		if (pDispNewObject)
			pDispNewObject->Release();
	}
 
		// Offer user the option to delete test containers.
		wprintf(L"Delete the test container and object (Y/N):");
		getws(pszBuffer);
		if (0==wcsnicmp(L"Y", pszBuffer,1))
		{
			// Delete the object.
			// Delete the container.
			hr = pNewContainer->Delete(_bstr_t("container"),_bstr_t(szNewObjectRenameRDN));
			if (SUCCEEDED(hr))
			{
			wprintf(L"Test object successfully deleted.\n");
			wcsncpy(szRelPath,L"cn=", MAX_PATH);
			wcsncat(szRelPath,szContainer, MAX_PATH-wcslen(szRelPath));
			// Delete the container.
			hr = pDomain->Delete(_bstr_t("container"),_bstr_t(szRelPath));
			if (SUCCEEDED(hr))
				wprintf(L"Test container, and its contents, successfully deleted.\n");
			else
				wprintf(L"Failed to delete test container and its contents. hr: %x\n",hr);
		}
			else
			wprintf(L"Failed to delete test container and its contents. hr: %x\n",hr);
	}
 
		if (pNewContainer)
		pNewContainer->Release();
}
	if (pDisp)
		pDisp->Release();
}
	if (pDomain)
	pDomain->Release();
}
if (pObject)
   pObject->Release();
 
// Uninitialize COM.
CoUninitialize();
 
Cleanup:
	delete [] szNewContainerDN;;
	delete [] szPath;
	delete [] szRelPath;
	return;
}
 
HRESULT AddValueToOtherWKOProperty(LPOLESTR szContainerDN, // DN for container whose otherWellKnownObjects property to modify.
								 LPGUID pWKOGUID, // WKO GUID for the well-known object.
								 LPOLESTR szWKOObjectDN // DN of the well-known object.
								 )
{
HRESULT hr = E_FAIL;
LPOLESTR szGUIDString = new OLECHAR[MAX_PATH];
LPOLESTR szDNwithOctetString = new OLECHAR[MAX_PATH*2];
DWORD dwReturn = 0;
// Connection handle.
LDAP *hConnect = NULL;
// Specify NULL to bind to a DC in the current computer domain.
// LDAP_PORT is the default port, 389.
hConnect  = ldap_open(NULL,  LDAP_PORT);
// Bind using the preferred authentication method on Windows 2000
// and the caller security context.
dwReturn = ldap_bind_s( hConnect, NULL, NULL, LDAP_AUTH_NEGOTIATE );
if (dwReturn==LDAP_SUCCESS)
{
 
  // Create the WKO value to add.
  GUIDtoBindableString (pWKOGUID, &szGUIDString);
  DWORD dwGUIDSize = (wcslen(szGUIDString));
  // Build the DNwithoctetstring.
  _snwprintf(szDNwithOctetString,MAX_PATH*2, L"B:%d:%s:%s", dwGUIDSize, szGUIDString,szWKOObjectDN); 
  // ULONG ulBerSize = (wcslen(szDNwithOctetString));
  // Build the BerVal.
//  PCHAR pByteVal = (PCHAR)szDNwithOctetString;
//  berval berWKO;
//  berWKO.bv_len = ulBerSize;
//  berWKO.bv_val = pByteVal;
  // Build the mod structure to add the value.
  LDAPMod ldWKO;
  // mod_values takes a NULL terminated array of WCHARs.
  // Add a single value.
  WCHAR *StrValues[] = {szDNwithOctetString , NULL };
  // Operation
  ldWKO.mod_op = LDAP_MOD_ADD;
  // Attribute
  ldWKO.mod_type = L"otherWellKnownObjects";
  // Value to set
  ldWKO.mod_vals.modv_strvals = StrValues;
  // mods is a NULL terminated array of LDAPMod structures.
  // Add a single value.
  LDAPMod *pMod[] = {&ldWKO,NULL};

  // Modify the object specified by szContainerDN.
  dwReturn = ldap_modify_s(  hConnect,
							 szContainerDN,
							 pMod);
  CoTaskMemFree(szGUIDString);
 
  if (dwReturn==LDAP_SUCCESS)
	hr = S_OK;
}
delete [] szGUIDString;
delete [] szDNwithOctetString;

return hr;
}
 
 
 
 
 
HRESULT GUIDtoBindableString (LPGUID pGUID, LPOLESTR *ppGUIDString)
{
HRESULT hr = E_FAIL;
if (!pGUID)
  return E_INVALIDARG;
// Build bindable GUID string.
LPOLESTR szDSGUID = new WCHAR [128];
DWORD dwLen =  sizeof(*pGUID);
LPBYTE lpByte = (LPBYTE) pGUID;
// Copy a blank string to set it as a zero-length string.
wcsncpy(szDSGUID, L"",128);
// Loop through to add each byte to the string.
for( DWORD dwItem = 0L; dwItem < dwLen ; dwItem++ )
{
  // Append to szDSGUID, double-byte, byte at dwItem index.
  snwprintf(szDSGUID + wcslen(szDSGUID),128-wcslen(szDSGuid), L"%02x", lpByte[dwItem]);
}
// Allocate memory for string.
*ppGUIDString = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szDSGUID)+1));
if (*ppGUIDString)
  wcscpy(*ppGUIDString, szDSGUID);
else
  hr=E_FAIL;
// Caller must free ppGUIDString using CoTaskMemFree.
delete [] szDSGUID;
return hr;
}
 
 
// This function gets the specified well-known object for the current user's domain.
 
HRESULT GetWKOObject(LPOLESTR szBindableWKGUID, // IN. Bindable string GUID of well-known object.
						IADs **ppObject // OUT. Return a pointer to the specified well-known object.
						)
{
HRESULT hr = E_FAIL;
// Get rootDSE and the domain container DN.
IADs *pObject = NULL;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
VARIANT var;

VariantInit(&var);

hr = ADsOpenObject(L"LDAP://rootDSE",
				 NULL,
				 NULL,
				 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
				 IID_IADs,
				 (void**)&pObject);
 
// Get current domain DN.
if (SUCCEEDED(hr))
{
	hr = pObject->Get(_bstr_t("defaultNamingContext"),&var);
	if (SUCCEEDED(hr))
	{
		// Build the WKGUID binding string.
		wcsncpy(szPath,L"LDAP://",MAX_PATH);
		wcsncat(szPath,L"<WKGUID=",MAX_PATH-wcslen(szPath));
		wcsncat(szPath,szBindableWKGUID,MAX_PATH-wcslen(szPath));
		wcsncat(szPath,L",",MAX_PATH-wcslen(szPath));
		wcsncat(szPath,var.bstrVal,MAX_PATH-wcslen(szPath));
		wcsncat(szPath,L">",MAX_PATH-wcslen(szPath));
		// Print the binding string.
		// wprintf(L"WKGUID binding string: %s\n",szPath);
		VariantClear(&var);
		// Bind to the well-known object.
		hr = ADsOpenObject(szPath,
						 NULL,
						 NULL,
						 ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
						 IID_IADs,
						 (void**)ppObject);
		if (FAILED(hr))
		{
			if (*ppObject)
			{
			(*ppObject)->Release();
			(*ppObject) = NULL;
		}
	}
}
}
if (pObject)
  pObject->Release();

delete [] szPath;
return hr;
}