Directory Services |
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; }