void CDlgIDirectoryObject::ShowAttributes()
{
	ADS_OBJECT_INFO *pInfo;
	HRESULT hr;

	hr = m_pDirObject->GetObjectInformation(&pInfo);
	if (!SUCCEEDED(hr) )
	{
		return;
	}
	
	/////////////////////////////////////////////
	// Show the attributes in the UI
	/////////////////////////////////////////////
	USES_CONVERSION;

	m_sRDN		= OLE2T(pInfo->pszRDN);
	m_sDN		= OLE2T(pInfo->pszObjectDN);
	m_sParent	= OLE2T(pInfo->pszParentDN);
	m_sClass	= OLE2T(pInfo->pszClassName);
	m_sSchema	= OLE2T(pInfo->pszSchemaDN);
    
	///////////////////////////////////////////////////////////
	// Do not forget to clean-up the memory using FreeADsMem!
	//////////////////////////////////////////////////////////
	FreeADsMem( pInfo );

}
HRESULT CADsSearch::Execute( LPCTSTR pszFilter )
{
	USES_CONVERSION;
	HRESULT hr;


	if ( !m_pSearch  )
	{
		return E_UNEXPECTED;
	}
	
	m_hSearch	= NULL;

	//////////////////////////////////////////////
	// Set the search preference if any
	///////////////////////////////////////////////
	if ( m_dwPrefCount )
	{
		hr = m_pSearch->SetSearchPreference( m_srchInfo, m_dwPrefCount);
		if ( !SUCCEEDED(hr) )
		{
			return hr;
		}
	}

	if ( m_sColumnList.IsEmpty() )
	{
		hr = m_pSearch->ExecuteSearch( T2OLE(pszFilter), NULL, -1, &m_hSearch );
	}
	else // Columns is specified
	{
		unsigned int count, xx;
		LPWSTR    *pColumns = NULL;
		POSITION  pos; 
		CString	  s;

		count = m_sColumnList.GetCount();
		pColumns = (LPWSTR*)AllocADsMem( sizeof(LPWSTR)*count);
		pos = m_sColumnList.GetHeadPosition();
		for(xx=0; xx < count; xx++)
		{
			s = m_sColumnList.GetAt(pos);
			pColumns[xx] = T2OLE(s);
			m_sColumnList.GetNext(pos);
		}

		hr = m_pSearch->ExecuteSearch( T2OLE(pszFilter), pColumns, count, &m_hSearch );
		if ( pColumns )
		{
			FreeADsMem( pColumns );
		}

	}


	return hr;

}
Beispiel #3
0
static int smpd_build_spn_list()
{
    HRESULT hr;
    IDirectoryObject *pSCP = NULL;
    ADS_ATTR_INFO *pPropEntries = NULL;
    IDirectorySearch *pSearch = NULL;
    ADS_SEARCH_HANDLE hSearch = NULL;
    LPWSTR pszDN;                  /* distinguished name of SCP. */
    LPWSTR pszServiceDNSName;      /* service DNS name. */
    LPWSTR pszClass;               /* name of service class. */
    USHORT usPort;                 /* service port. */
    WCHAR pszSearchString[SMPD_MAX_NAME_LENGTH];
    char temp_str[SMPD_MAX_NAME_LENGTH];
    char temp_str2[SMPD_MAX_NAME_LENGTH];
    smpd_host_spn_node_t *iter;
    /* double t1, t2; */
    static int initialized = 0;

    if (initialized)
    {
	return SMPD_SUCCESS;
    }
    initialized = 1;

    /* t1 = PMPI_Wtime(); */

    CoInitialize(NULL);

    /* Get an IDirectorySearch pointer for the Global Catalog.  */
    hr = GetGCSearch(&pSearch);
    if (FAILED(hr) || pSearch == NULL) 
    {
	smpd_err_printf("GetGC failed 0x%x\n", hr);
	goto Cleanup;
    }

    /* Set up a deep search.
      Thousands of objects are not expected in this example, therefore
      query for 1000 rows per page.*/
    ADS_SEARCHPREF_INFO SearchPref[2];
    DWORD dwPref = sizeof(SearchPref)/sizeof(ADS_SEARCHPREF_INFO);
    SearchPref[0].dwSearchPref =    ADS_SEARCHPREF_SEARCH_SCOPE;
    SearchPref[0].vValue.dwType =   ADSTYPE_INTEGER;
    SearchPref[0].vValue.Integer =  ADS_SCOPE_SUBTREE;

    SearchPref[1].dwSearchPref =    ADS_SEARCHPREF_PAGESIZE;
    SearchPref[1].vValue.dwType =   ADSTYPE_INTEGER;
    SearchPref[1].vValue.Integer =  1000;

    hr = pSearch->SetSearchPreference(SearchPref, dwPref);
    if (FAILED(hr))
    {
	smpd_err_printf("Failed to set search prefs: hr:0x%x\n", hr);
	goto Cleanup;
    }

    /* Execute the search. From the GC get the distinguished name 
      of the SCP. Use the DN to bind to the SCP and get the other 
      properties. */
    LPWSTR rgszDN[] = {L"distinguishedName"};

    /* Search for a match of the product GUID. */
    swprintf(pszSearchString, L"keywords=%s", SMPD_SERVICE_VENDOR_GUIDW);
    hr = pSearch->ExecuteSearch(pszSearchString, rgszDN, 1, &hSearch);
    /*hr = pSearch->ExecuteSearch(L"keywords=5722fe5f-cf46-4594-af7c-0997ca2e9d72", rgszDN, 1, &hSearch);*/
    if (FAILED(hr))
    {
	smpd_err_printf("ExecuteSearch failed: hr:0x%x\n", hr);
	goto Cleanup;
    }

    /* Loop through the results. Each row should be an instance of the 
      service identified by the product GUID.
      Add logic to select from multiple service instances. */
    while (SUCCEEDED(hr = pSearch->GetNextRow(hSearch)))
    {
	if (hr == S_ADS_NOMORE_ROWS)
	{
	    DWORD dwError = ERROR_SUCCESS;
	    WCHAR szError[512];
	    WCHAR szProvider[512];

	    ADsGetLastError(&dwError, szError, 512, szProvider, 512);
	    if (ERROR_MORE_DATA == dwError)
	    {
		continue;
	    }
	    goto Cleanup;
	}

	ADS_SEARCH_COLUMN Col;

	hr = pSearch->GetColumn(hSearch, L"distinguishedName", &Col);
	pszDN = AllocADsStr(Col.pADsValues->CaseIgnoreString);
	pSearch->FreeColumn(&Col);

	/* Bind to the DN to get the other properties. */
	LPWSTR lpszLDAPPrefix = L"LDAP://";
	DWORD dwSCPPathLength = (DWORD)(wcslen(lpszLDAPPrefix) + wcslen(pszDN) + 1);
	LPWSTR pwszSCPPath = (LPWSTR)malloc(sizeof(WCHAR) * dwSCPPathLength);
	if (pwszSCPPath)
	{
	    wcscpy(pwszSCPPath, lpszLDAPPrefix);
	    wcscat(pwszSCPPath, pszDN);
	}       
	else
	{
	    smpd_err_printf("Failed to allocate a buffer\n");
	    goto Cleanup;
	}               
	/*wprintf(L"pszDN = %s\n", pszDN);*/
	/*FreeADsStr(pszDN);*/

	hr = ADsGetObject(pwszSCPPath, IID_IDirectoryObject, (void**)&pSCP);
	free(pwszSCPPath);

	if (SUCCEEDED(hr)) 
	{
	    /* Properties to retrieve from the SCP object. */
	    LPWSTR rgszAttribs[]=
	    {
		{L"serviceClassName"},
		{L"serviceDNSName"},
		/*{L"serviceDNSNameType"},*/
		{L"serviceBindingInformation"}
	    };

	    DWORD dwAttrs = sizeof(rgszAttribs)/sizeof(LPWSTR);
	    DWORD dwNumAttrGot;
	    hr = pSCP->GetObjectAttributes(rgszAttribs, dwAttrs, &pPropEntries, &dwNumAttrGot);
	    if (FAILED(hr)) 
	    {
		smpd_err_printf("GetObjectAttributes Failed. hr:0x%x\n", hr);
		goto Cleanup;
	    }

	    pszServiceDNSName = NULL;
	    pszClass = NULL;
	    iter = (smpd_host_spn_node_t*)malloc(sizeof(smpd_host_spn_node_t));
	    if (iter == NULL)
	    {
		smpd_err_printf("Unable to allocate memory to store an SPN entry.\n");
		goto Cleanup;
	    }
	    iter->next = NULL;
	    iter->host[0] = '\0';
	    iter->spn[0] = '\0';
	    iter->dnshost[0] = '\0';

	    /* Loop through the entries returned by GetObjectAttributes 
	    and save the values in the appropriate buffers.  */
	    for (int i = 0; i < (LONG)dwAttrs; i++) 
	    {
		if ((wcscmp(L"serviceDNSName", pPropEntries[i].pszAttrName) == 0) &&
		    (pPropEntries[i].dwADsType == ADSTYPE_CASE_IGNORE_STRING)) 
		{
		    pszServiceDNSName = AllocADsStr(pPropEntries[i].pADsValues->CaseIgnoreString);
		    /*wprintf(L"pszServiceDNSName = %s\n", pszServiceDNSName);*/
		}

		/*
		if ((wcscmp(L"serviceDNSNameType", pPropEntries[i].pszAttrName) == 0) &&
		(pPropEntries[i].dwADsType == ADSTYPE_CASE_IGNORE_STRING)) 
		{
		pszServiceDNSNameType = AllocADsStr(pPropEntries[i].pADsValues->CaseIgnoreString);
		wprintf(L"pszServiceDNSNameType = %s\n", pszServiceDNSNameType);
		}
		*/

		if ((wcscmp(L"serviceClassName", pPropEntries[i].pszAttrName) == 0) &&
		    (pPropEntries[i].dwADsType == ADSTYPE_CASE_IGNORE_STRING)) 
		{
		    pszClass = AllocADsStr(pPropEntries[i].pADsValues->CaseIgnoreString);
		    /*wprintf(L"pszClass = %s\n", pszClass);*/
		}

		if ((wcscmp(L"serviceBindingInformation", pPropEntries[i].pszAttrName) == 0) &&
		    (pPropEntries[i].dwADsType == ADSTYPE_CASE_IGNORE_STRING)) 
		{
		    usPort=(USHORT)_wtoi(pPropEntries[i].pADsValues->CaseIgnoreString);
		    /*wprintf(L"usPort = %d\n", usPort);*/
		}
	    }

	    wcstombs(iter->dnshost, pszServiceDNSName, SMPD_MAX_NAME_LENGTH);
	    wcstombs(temp_str, pszClass, SMPD_MAX_NAME_LENGTH);
	    /*MPIU_Snprintf(iter->spn, SMPD_MAX_NAME_LENGTH, "%s/%s:%d", temp_str, iter->dnshost, usPort);*/
	    wcstombs(temp_str2, pszDN, SMPD_MAX_NAME_LENGTH);
	    MPIU_Snprintf(iter->spn, SMPD_MAX_NAME_LENGTH, "%s/%s/%s", temp_str, iter->dnshost, temp_str2);
	    MPIU_Strncpy(iter->host, iter->dnshost, SMPD_MAX_NAME_LENGTH);
	    strtok(iter->host, ".");
	    iter->next = spn_list;
	    spn_list = iter;
	    if (pszServiceDNSName != NULL)
	    {
		FreeADsStr(pszServiceDNSName);
	    }
	    if (pszClass != NULL)
	    {
		FreeADsStr(pszClass);
	    }
	}
	FreeADsStr(pszDN);
    }

Cleanup:
    /*
    iter = spn_list;
    while (iter != NULL)
    {
	printf("host   : %s\n", iter->host);
	printf("dnshost: %s\n", iter->dnshost);
	printf("spn    : %s\n", iter->spn);
	iter = iter->next;
    }
    fflush(stdout);
    */
    if (pSCP)
    {
	pSCP->Release();
	pSCP = NULL;
    }

    if (pPropEntries)
    {
	FreeADsMem(pPropEntries);
	pPropEntries = NULL;
    }

    if (pSearch)
    {
	if (hSearch)
	{
	    pSearch->CloseSearchHandle(hSearch);
	    hSearch = NULL;
	}

	pSearch->Release();
	pSearch = NULL;
    }
    CoUninitialize();

    /* t2 = PMPI_Wtime();
    smpd_dbg_printf("build_spn_list took %0.6f seconds\n", t2-t1);
    */

    return SMPD_SUCCESS;
}
HRESULT FindAttributesOrClasses(IDirectorySearch *pSchemaNC, //IDirectorySearch pointer to schema naming context.
		 LPOLESTR szFilter, //Filter for finding specific attributes.
                            //NULL returns all attributeSchema objects.
         LPOLESTR *pszPropertiesToReturn, //Properties to return for attributeSchema objects found
					                    //NULL returns all set properties unless bIsVerbose is FALSE.
		 BOOL bIsAttributeQuery, //TRUE queries for attributes;FALSE for classes
		 BOOL bIsVerbose //TRUE means all properties for the found objects are displayed.
		                 //FALSE means only the ldapDisplayName with cn in parentheses:
						 //example: l (Locality-Name)
							)
{
	if (!pSchemaNC)
		return E_POINTER;
    //Create search filter
	int allocFilter = MAX_PATH*2;
	LPOLESTR pszSearchFilter = new OLECHAR[allocFilter];
	
    if ( !pszSearchFilter )
    {
        delete [] pszSearchFilter;
        return E_OUTOFMEMORY;
    }
        
	LPOLESTR szCategory = NULL;
	if (bIsAttributeQuery)
		szCategory = L"attributeSchema";
	else
		szCategory = L"classSchema";


	wcscpy_s(pszSearchFilter, allocFilter, L"(&(objectCategory=attributeSchema)%s)");
	BOOL bBufferOK=false;
	// Check for buffer overrun...
	if (szFilter)
	{
		if ( IS_BUFFER_ENOUGH(allocFilter,pszSearchFilter, szCategory) > 0 )
		{
	       swprintf_s(pszSearchFilter, allocFilter, L"(&(objectCategory=%s)%s)",szCategory,szFilter);
		   bBufferOK=true;
		}
	}
	else
	{
		if ( IS_BUFFER_ENOUGH(allocFilter,pszSearchFilter, szCategory) > 0 )
		{
 	       swprintf_s(pszSearchFilter, allocFilter,L"(objectCategory=%s)",szCategory);
		   bBufferOK=true;
		}
	}

	
	if( !bBufferOK)
	{
            delete [] pszSearchFilter;
			wprintf(L"Filter is too large - aborting");
			return E_FAIL;
	}

    //Attributes are one-level deep in the Schema container so only need to search one level.
	ADS_SEARCHPREF_INFO SearchPrefs;
	SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
	SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
	SearchPrefs.vValue.Integer = ADS_SCOPE_ONELEVEL;
    DWORD dwNumPrefs = 1;

	// COL for iterations
	LPOLESTR pszColumn = NULL;    
	ADS_SEARCH_COLUMN col;
    HRESULT hr;
    
    // Interface Pointers
    IADs    *pObj = NULL;
    IADs	* pIADs = NULL;

    // Handle used for searching
    ADS_SEARCH_HANDLE hSearch = NULL;
	
	// Set the search preference
    hr = pSchemaNC->SetSearchPreference( &SearchPrefs, dwNumPrefs);
    if (FAILED(hr))
        return hr;

	LPOLESTR pszBool = NULL;
	DWORD dwBool;
	PSID pObjectSID = NULL;
	LPOLESTR szSID = NULL;
	LPGUID pObjectGUID = NULL;
	FILETIME filetime;
	SYSTEMTIME systemtime;
	DATE date;
	VARIANT varDate;
	LARGE_INTEGER liValue;
	LPOLESTR *pszPropertyList = NULL;
	LPOLESTR pszNonVerboseList[] = {L"lDAPDisplayName",L"cn"};

	LPOLESTR szCNValue = new OLECHAR[MAX_PATH];
	LPOLESTR szLDAPDispleyNameValue = new OLECHAR[MAX_PATH];
	LPOLESTR szDSGUID = new WCHAR [39];
	
	if ( !szCNValue || 	!szLDAPDispleyNameValue || !szDSGUID )
	{
        if ( szDSGUID )
            delete [] szDSGUID;
        if ( szCNValue )
            delete [] szCNValue;
        if ( szLDAPDispleyNameValue )
            delete [] szLDAPDispleyNameValue;
        if ( pszSearchFilter )
            delete [] pszSearchFilter;	
        return E_OUTOFMEMORY;
    }

	int iCount = 0;
	DWORD x = 0L;



	if (!bIsVerbose)
	{
		 //Return non-verbose list properties only
         hr = pSchemaNC->ExecuteSearch(pszSearchFilter,
		                          pszNonVerboseList,
								  sizeof(pszNonVerboseList)/sizeof(LPOLESTR),
								  &hSearch
								  );
	}
	else
	{
		if (!pszPropertiesToReturn)
		{
			//Return all properties.
			hr = pSchemaNC->ExecuteSearch(pszSearchFilter,
		                          NULL,
								  0L,
								  &hSearch
								  );
		}
		else
		{
			//specified subset.
		    pszPropertyList = pszPropertiesToReturn;
		   //Return specified properties
		   hr = pSchemaNC->ExecuteSearch(pszSearchFilter,
		                          pszPropertyList,
								  sizeof(pszPropertyList)/sizeof(LPOLESTR),
								  &hSearch
								  );
		}
	}
 	if ( SUCCEEDED(hr) )
	{    
    // Call IDirectorySearch::GetNextRow() to retrieve the next row 
    //of data
	  hr = pSchemaNC->GetFirstRow( hSearch);
	  if (SUCCEEDED(hr))
	  {
        while( hr != S_ADS_NOMORE_ROWS )
		{
			//Keep track of count.
			iCount++;
			if (bIsVerbose)
			  wprintf(L"----------------------------------\n");
            // loop through the array of passed column names,
            // print the data for each column

			while( pSchemaNC->GetNextColumnName( hSearch, &pszColumn ) != S_ADS_NOMORE_COLUMNS )
            {
                hr = pSchemaNC->GetColumn( hSearch, pszColumn, &col );
			    if ( SUCCEEDED(hr) )
			    {
		            // Print the data for the column and free the column
				  if(bIsVerbose)
				  {
			        // Get the data for this column
				    wprintf(L"%s\n",col.pszAttrName);
					switch (col.dwADsType)
					{
						case ADSTYPE_DN_STRING:
                          for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %s\r\n",col.pADsValues[x].DNString);
						  }
						  break;
						case ADSTYPE_CASE_EXACT_STRING:	    
						case ADSTYPE_CASE_IGNORE_STRING:	    
						case ADSTYPE_PRINTABLE_STRING:	    
						case ADSTYPE_NUMERIC_STRING:	        
						case ADSTYPE_TYPEDNAME:	            
						case ADSTYPE_FAXNUMBER:	            
						case ADSTYPE_PATH:	                
						case ADSTYPE_OBJECT_CLASS:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %s\r\n",col.pADsValues[x].CaseIgnoreString);
						  }
						  break;
						case ADSTYPE_BOOLEAN:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  dwBool = col.pADsValues[x].Boolean;
							  pszBool = dwBool ? L"TRUE" : L"FALSE";
							  wprintf(L"  %s\r\n",pszBool);
						  }
						  break;
						case ADSTYPE_INTEGER:
					      for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %d\r\n",col.pADsValues[x].Integer);
						  }
						  break;
						case ADSTYPE_OCTET_STRING:
						    if ( _wcsicmp(col.pszAttrName,L"objectSID") == 0 )
							{
						      for (x = 0; x< col.dwNumValues; x++)
							  {
								  pObjectSID = (PSID)(col.pADsValues[x].OctetString.lpValue);
								  //Convert SID to string.
								  ConvertSidToStringSid(pObjectSID, &szSID);
								  wprintf(L"  %s\r\n",szSID);
								  LocalFree(szSID);
							  }
							}
						    else if ( (_wcsicmp(col.pszAttrName,L"objectGUID") == 0)
								|| (_wcsicmp(col.pszAttrName,L"schemaIDGUID") == 0) 
								|| (_wcsicmp(col.pszAttrName,L"attributeSecurityGUID") == 0) )
							{
						      for (x = 0; x< col.dwNumValues; x++)
							  {
								//Cast to LPGUID
								pObjectGUID = (LPGUID)(col.pADsValues[x].OctetString.lpValue);
								//Convert GUID to string.
								::StringFromGUID2(*pObjectGUID, szDSGUID, 39); 
								//Print the GUID
								wprintf(L"  %s\r\n",szDSGUID);
							  }
							}
						    else if ( _wcsicmp(col.pszAttrName,L"oMObjectClass") == 0 )
							{
							  //TODO: 
							  wprintf(L"  TODO:No conversion for this.");
							}
							else
							  wprintf(L"  Value of type Octet String. No Conversion.");
						    break;
						case ADSTYPE_UTC_TIME:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							systemtime = col.pADsValues[x].UTCTime;
							if (SystemTimeToVariantTime(&systemtime,
														&date) != 0) 
							{
								//Pack in variant.vt
								varDate.vt = VT_DATE;
								varDate.date = date;
								VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
							    wprintf(L"  %s\r\n",varDate.bstrVal);
								VariantClear(&varDate);
							}
							else
								wprintf(L"  Could not convert UTC-Time.\n");
						  }
						  break;
						case ADSTYPE_LARGE_INTEGER:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
						    liValue = col.pADsValues[x].LargeInteger;
							filetime.dwLowDateTime = liValue.LowPart;
							filetime.dwHighDateTime = liValue.HighPart;
							if((filetime.dwHighDateTime==0) && (filetime.dwLowDateTime==0))
							{
								wprintf(L"  No value set.\n");
							}
							else
							{
								//Check for properties of type LargeInteger that represent time
								//if TRUE, then convert to variant time.
								if ((0==wcscmp(L"accountExpires", col.pszAttrName))|
									(0==wcscmp(L"badPasswordTime", col.pszAttrName))||
									(0==wcscmp(L"lastLogon", col.pszAttrName))||
									(0==wcscmp(L"lastLogoff", col.pszAttrName))||
									(0==wcscmp(L"lockoutTime", col.pszAttrName))||
									(0==wcscmp(L"pwdLastSet", col.pszAttrName))
								   )
								{
									//Handle special case for Never Expires where low part is -1
									if (filetime.dwLowDateTime==-1)
									{
										wprintf(L"  Never Expires.\n");
									}
									else
									{
										if (FileTimeToLocalFileTime(&filetime, &filetime) != 0) 
										{
											if (FileTimeToSystemTime(&filetime,
																 &systemtime) != 0)
											{
												if (SystemTimeToVariantTime(&systemtime,
																			&date) != 0) 
												{
													//Pack in variant.vt
													varDate.vt = VT_DATE;
													varDate.date = date;
													VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
													wprintf(L"  %s\r\n",varDate.bstrVal);
													VariantClear(&varDate);
												}
												else
												{
													wprintf(L"  FileTimeToVariantTime failed\n");
												}
											}
											else
											{
												wprintf(L"  FileTimeToSystemTime failed\n");
											}

										}
										else
										{
											wprintf(L"  FileTimeToLocalFileTime failed\n");
										}
									}
								}
								else
								{
									//Print the LargeInteger.
									wprintf(L"  high: %d low: %d\r\n",filetime.dwHighDateTime, filetime.dwLowDateTime);
								}
							}
						  }
						  break;
						case ADSTYPE_NT_SECURITY_DESCRIPTOR:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  Security descriptor.\n");
						  }
						  break;
						default:
				          wprintf(L"Unknown type %d.\n",col.dwADsType);
					}
				  }
			      else
				  {
					//Verbose handles only the two single-valued attributes: cn and ldapdisplayname
					//so this is a special case.
					if (0==wcscmp(L"cn", pszColumn))
					{
					  wcscpy_s(szCNValue,MAX_PATH,col.pADsValues->CaseIgnoreString);
					}
					if (0==wcscmp(L"lDAPDisplayName", pszColumn))
					{
					  wcscpy_s(szLDAPDispleyNameValue,MAX_PATH,col.pADsValues->CaseIgnoreString);
					}
				  }
			      pSchemaNC->FreeColumn( &col );
			    }
				FreeADsMem( pszColumn );
            }
		   if (!bIsVerbose)
			   wprintf(L"%s (%s)\n",szLDAPDispleyNameValue,szCNValue);
 		   //Get the next row
		   hr = pSchemaNC->GetNextRow( hSearch);
		}

	  }
	  // Close the search handle to clean up
      pSchemaNC->CloseSearchHandle(hSearch);
	} 
	if (SUCCEEDED(hr) && 0==iCount)
		hr = S_FALSE;

    delete [] szDSGUID;
    delete [] szCNValue;
    delete [] szLDAPDispleyNameValue;
    delete [] pszSearchFilter;
        
    return hr;
}
Beispiel #5
0
HRESULT ExchangeAdmin::CreateExchangeMailBox(LPCWSTR lpwstrNewUser, LPCWSTR lpwstrNewUserPwd,
    LPCWSTR lpwstrlogonuser, LPCWSTR lpwstrLogonUsrPwd)
{
    HRESULT hr = S_OK;

    // Get Logon user DN
    wstring LogonUserDN;
    wstring legacyName;
	wstring msExchHomeSvrName;
    Zimbra::MAPI::Util::GetUserDNAndLegacyName(m_strServer.c_str(), lpwstrlogonuser,
        lpwstrLogonUsrPwd, LogonUserDN, legacyName);
	Zimbra::MAPI::Util::GetmsExchHomeServerName(m_strServer.c_str(), lpwstrlogonuser,
        lpwstrLogonUsrPwd, msExchHomeSvrName);
    Zimbra::Util::ScopedInterface<IDirectoryObject> pLogonContainer;
	Zimbra::Util::ScopedInterface<IADsUser> pIAdUser;
	Zimbra::Util::ScopedInterface<IADs> pIAds;
    wstring strContainer = L"LDAP://";

    strContainer += LogonUserDN.c_str();

    dloge("strContainer %S  msExchHomeSvrName: %S", strContainer.c_str(), msExchHomeSvrName.c_str());
    // Get loggedin user container
    hr = ADsOpenObject(strContainer.c_str(), NULL, NULL, ADS_SECURE_AUTHENTICATION,
        IID_IDirectoryObject, (void **)pLogonContainer.getptr());
    if (FAILED(hr))
    {
        if (hr == 0x8007052e)                   // credentials are not valid
        {
            hr = ADsOpenObject((LPTSTR)strContainer.c_str(), lpwstrlogonuser, lpwstrLogonUsrPwd,
				ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (void **)pLogonContainer.getptr());
			if (FAILED(hr)||(pLogonContainer.get()==NULL))
                throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): ADsOpenObject Failed.",
				ERR_ADOBJECT_OPEN, __LINE__, __FILE__);
        }
        else
        {
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): ADsOpenObject Failed.",
                ERR_ADOBJECT_OPEN, __LINE__, __FILE__);
        }
    }

    ADS_ATTR_INFO *pAttrInfo = NULL;
    DWORD dwReturn;
    LPWSTR pAttrNames[] = { L"mail", L"homeMDB", L"homeMTA" };
    DWORD dwNumAttr = sizeof (pAttrNames) / sizeof (LPWSTR);
    wstring strLogonHomeMDB;
    wstring strLogonHomeMTA;
    wstring strLogonMail;

    // Get attribute values requested. Its not necessary the order is same as requested.
    if (FAILED(hr = pLogonContainer->GetObjectAttributes(pAttrNames, dwNumAttr, &pAttrInfo,
            &dwReturn)))
        throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): GetObjectAttributes Failed.", 
		ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    for (DWORD idx = 0; idx < dwReturn; idx++)
    {
        if (_wcsicmp(pAttrInfo[idx].pszAttrName, L"mail") == 0)
            strLogonMail = pAttrInfo[idx].pADsValues->Email.Address;

        else if (_wcsicmp(pAttrInfo[idx].pszAttrName, L"homeMTA") == 0)
            strLogonHomeMTA = pAttrInfo[idx].pADsValues->DNString;

        else if (_wcsicmp(pAttrInfo[idx].pszAttrName, L"homeMDB") == 0)
            strLogonHomeMDB = pAttrInfo[idx].pADsValues->DNString;
    }
    // Use FreeADsMem for all memory obtained from the ADSI call.
    FreeADsMem(pAttrInfo);

    wstring twtsrlogonuserDN = LogonUserDN;
    size_t nPos = twtsrlogonuserDN.find(_T("DC="), 0);
    wstring wstrServerDN = twtsrlogonuserDN.substr(nPos);
    wstring wstrADSPath = _T("LDAP://CN=Users,") + wstrServerDN;
    ADSVALUE cnValue;
    ADSVALUE classValue;
    ADSVALUE sAMValue;
    ADSVALUE uPNValue;
	ADSVALUE controlValue;
    ADS_ATTR_INFO attrInfo[] = {
        { L"objectClass", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &classValue, 1 },
        { L"cn", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &cnValue, 1 },
        { L"sAMAccountName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &sAMValue, 1 },
        { L"userPrincipalName", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &uPNValue, 1 },
		{L"userAccountControl", ADS_ATTR_UPDATE, ADSTYPE_INTEGER,&controlValue, 1},
    };
    DWORD dwAttrs = sizeof (attrInfo) / sizeof (ADS_ATTR_INFO);

    classValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
    classValue.CaseIgnoreString = L"user";

	//int UF_ACCOUNTDISABLE = 0x0002;
	int UF_PASSWD_NOTREQD = 0x0020;
	//int UF_PASSWD_CANT_CHANGE = 0x0040;
	int UF_NORMAL_ACCOUNT = 0x0200;
	int UF_DONT_EXPIRE_PASSWD = 0x10000;
	//int UF_PASSWORD_EXPIRED = 0x800000;

	controlValue.dwType = ADSTYPE_INTEGER;
	controlValue.Integer=UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD |UF_DONT_EXPIRE_PASSWD;

    cnValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
    cnValue.CaseIgnoreString = (LPWSTR)lpwstrNewUser;

    sAMValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
    sAMValue.CaseIgnoreString = (LPWSTR)lpwstrNewUser;

    wstring wstrMail;
    size_t nPosMail = strLogonMail.find(_T("@"), 0);

    wstrMail = strLogonMail.substr(nPosMail);
    wstrMail = lpwstrNewUser + wstrMail;

    LPWSTR upnval = (LPWSTR)wstrMail.c_str();

    uPNValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
    uPNValue.CaseIgnoreString = upnval;

    Zimbra::Util::ScopedInterface<IDirectoryObject> pDirContainer;
    Zimbra::Util::ScopedInterface<IDispatch> pDisp;
    Zimbra::Util::ScopedInterface<IADsUser> pIADNewUser;
    wstring wstrLoggedUserName(LogonUserDN);
    size_t snPos = 0;
    size_t enPos = 0;

    if ((snPos = wstrLoggedUserName.find(L"CN=")) != wstring::npos)
    {
        if ((enPos = wstrLoggedUserName.find(L",", snPos)) != wstring::npos)
            wstrLoggedUserName = wstrLoggedUserName.substr(snPos + 3, (enPos - (snPos + 3)));
    }
    // get dir container
    if (FAILED(hr = ADsOpenObject(wstrADSPath.c_str(), wstrLoggedUserName.c_str(),
            lpwstrLogonUsrPwd, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject,
            (void **)pDirContainer.getptr())))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): ADsOpenObject Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);

    wstring wstrUserCN = L"CN=";

    wstrUserCN += lpwstrNewUser;
    dloge("CreateDSObject: %S",wstrUserCN.c_str());
    if (FAILED(hr = pDirContainer->CreateDSObject((LPWSTR)wstrUserCN.c_str(), attrInfo, dwAttrs,
            pDisp.getptr())))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): CreateDSObject Failed.",
            ERR_CREATE_EXCHMBX,__LINE__, __FILE__);
    if (FAILED(hr = pDisp->QueryInterface(IID_IADsUser, (void **)pIADNewUser.getptr())))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): QueryInterface Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);

    CComVariant varProp;
    varProp.Clear();

    // set samAccount
    varProp = lpwstrNewUser;
    if (FAILED(hr = pIADNewUser->Put(CComBSTR(L"sAMAccountName"), varProp)))
        throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): Put(sAMAccountName) Failed.",
		ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if(FAILED(hr = pIADNewUser->SetInfo()))
        throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): Put(sAMAccountName) Failed.", 
		ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    // set userAccountControl
    varProp.Clear();
    hr = pIADNewUser->Get(CComBSTR(L"userAccountControl"), &varProp);
    varProp = varProp.lVal & ~(ADS_UF_ACCOUNTDISABLE);
    if (FAILED(hr = pIADNewUser->Put(CComBSTR(L"userAccountControl"), varProp)))
        throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): Put(userAccountControl) Failed.",
		ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(userAccountControl) Failed.");
    // set Account enabled
    if (FAILED(hr = pIADNewUser->put_AccountDisabled(VARIANT_FALSE)))
    {
        throw
            ExchangeAdminException(hr, L"CreateExchangeMailBox(): put_AccountDisabled Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - put_AccountDisabled Failed.");
    // set password
    if (FAILED(hr = pIADNewUser->SetPassword(CComBSTR(lpwstrNewUserPwd))))
    {
        throw
            ExchangeAdminException(hr, L"CreateExchangeMailBox(): SetPassword Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - SetPassword Failed.");
    // user account password does not expire
    varProp.Clear();

    VARIANT var;

    VariantInit(&var);
    if (!FAILED(hr = pIADNewUser->Get(CComBSTR(L"userAccountControl"), &var)))
    {
        V_I4(&var) |= ADS_UF_DONT_EXPIRE_PASSWD;
        if (FAILED(hr = pIADNewUser->Put(CComBSTR(L"userAccountControl"), var)))
        {
            throw ExchangeAdminException(hr,L"CreateExchangeMailBox(): Put(userAccountControl) Failed.", 
				ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
        }
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - userAccountControl Failed.");
    varProp.Clear();
    // set the homeMDB;
    if (!strLogonHomeMDB.empty())
    {
        varProp = strLogonHomeMDB.c_str();
        if (FAILED(hr = pIADNewUser->Put(CComBSTR("homeMDB"), varProp)))
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(homeMDB) Failed.",
                ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(homeMDB) Failed.");

	varProp.Clear();
    if (!strLogonHomeMTA.empty())
    {
        varProp = strLogonHomeMTA.c_str();
        if (FAILED(hr = pIADNewUser->Put(CComBSTR("homeMTA"), varProp)))
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(homeMTA) Failed.",
                ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(homeMTA) Failed.");

	varProp.Clear();
	if (!msExchHomeSvrName.empty())
    {
        varProp = msExchHomeSvrName.c_str();
        if (FAILED(hr = pIADNewUser->Put(CComBSTR("msExchHomeServerName"), varProp)))
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(msExchHomeServerName) Failed.",
                ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(msExchHomeServerName) Failed.");
	varProp.Clear();

	varProp.Clear();
	wstring newUsrLegacyName=legacyName;
	size_t nwpos=newUsrLegacyName.rfind(L"cn=");
	if(nwpos !=wstring::npos)
	{
		newUsrLegacyName = newUsrLegacyName.substr(0,nwpos);
		newUsrLegacyName += L"cn=";
		newUsrLegacyName += lpwstrNewUser;
	}
	if (!newUsrLegacyName.empty())
    {
        varProp = newUsrLegacyName.c_str();
        if (FAILED(hr = pIADNewUser->Put(CComBSTR("legacyExchangeDN"), varProp)))
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(legacyExchangeDN) Failed.",
                ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(legacyExchangeDN) Failed.");

    // set nickname
    varProp.Clear();
    varProp = lpwstrNewUser;
    if (FAILED(hr = pIADNewUser->Put(CComBSTR("mailNickname"), varProp)))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(mailNickname) Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(mailNickname) Failed.");

    // set the displayName
    varProp.Clear();
    varProp = lpwstrNewUser;
    if (FAILED(hr = pIADNewUser->Put(CComBSTR("displayName"), varProp)))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(displayName) Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(displayName) Failed.");
    // set the mail atrribute
    varProp.Clear();
    varProp = wstrMail.c_str();
    if (FAILED(hr = pIADNewUser->Put(CComBSTR("mail"), varProp)))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put(mail) Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - Put(mail) Failed.");
    // set email
    if (FAILED(hr = pIADNewUser->put_EmailAddress(CComBSTR(wstrMail.c_str()))))
    {
        throw
            ExchangeAdminException(hr, L"CreateExchangeMailBox(): put_EmailAddress Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - put_EmailAddress Failed.");

	varProp.Clear();
	wstrMail=L"SMTP:"+wstrMail;
	varProp = wstrMail.c_str();
	if (FAILED(hr = pIADNewUser->Put(CComBSTR("proxyAddresses"),varProp)))
	{
        throw
            ExchangeAdminException(hr, L"CreateExchangeMailBox(): proxyAddressess Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    if(FAILED(hr = pIADNewUser->SetInfo()))
        ThrowSetInfoException(hr, L"SetInfo - proxyAddressess Failed.");

    // add to Domain Admins group
    BSTR bstrADSPath;

    if (FAILED(hr = pIADNewUser->get_ADsPath(&bstrADSPath)))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): get_ADsPath Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);

    wstring wstrGroup = _T("LDAP://CN=Domain Admins,CN=Users,") + wstrServerDN;
    Zimbra::Util::ScopedInterface<IADsGroup> pGroup;

    if (FAILED(hr = ADsGetObject(wstrGroup.c_str(), IID_IADsGroup, (void **)pGroup.getptr())))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): ADsGetObject Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if (FAILED(hr = ADsOpenObject(wstrGroup.c_str(), wstrLoggedUserName.c_str(),
            lpwstrLogonUsrPwd, ADS_SECURE_AUTHENTICATION, IID_IADsGroup,
            (void **)pGroup.getptr())))
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): ADsOpenObject Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    if (SUCCEEDED(hr = pGroup->Add(bstrADSPath)))
    {
        if (FAILED(hr = pGroup->SetInfo()))
            throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): pGroup SetInfo Failed.",
                ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
    else
    {
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): pGroup Add Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }

	GUID guid;
    if(FAILED(hr = CoCreateGuid(&guid)))
    {
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): CoCreateGuid Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }

    BYTE *str;
    hr = UuidToString((UUID *)&guid, (RPC_WSTR *)&str);
    if (hr != RPC_S_OK)
    {
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): UuidToString Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }

	varProp.Clear();
	//BYTE bytArr[]="3429bb3084703348b8023e94fabf16ea";
	PutBinaryIntoVariant(&varProp,str,16);
	RpcStringFree((RPC_WSTR *)&str);
	if (FAILED(hr = pIADNewUser->Put(CComBSTR("msExchMailboxGuid"), varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put msExchMailboxGuid Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
	}
	if(FAILED(hr = pIADNewUser->SetInfo()))
            ThrowSetInfoException(hr, L"SetInfo - msExchMailboxGuid Failed.");

	if (FAILED(hr = ADsOpenObject(strContainer.c_str(), NULL, NULL, ADS_SECURE_AUTHENTICATION,
        IID_IDirectoryObject, (void **)pIAdUser.getptr())))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): ADsOpenObject2 Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
	}	
	if (FAILED(hr = pIAdUser->QueryInterface(IID_IADs, (void**) pIAds.getptr())))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): pIAdUser->QueryInterface Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
	}

	varProp.Clear();
	if( FAILED(hr= pIAds->Get(CComBSTR("msExchMailboxSecurityDescriptor"),&varProp)))
	{
        throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Get msExchMailboxSecurityDescriptor Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
    }
	if (FAILED(hr = pIADNewUser->Put(CComBSTR("msExchMailboxSecurityDescriptor"), varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put msExchMailboxSecurityDescriptor Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
	}
	if(FAILED(hr = pIADNewUser->SetInfo()))
            ThrowSetInfoException(hr, L"SetInfo - msExchMailboxSecurityDescriptor Failed.");

	varProp.Clear();
	if( FAILED(hr=pIAds->Get(CComBSTR("msExchPoliciesIncluded"),&varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Get msExchPoliciesIncluded Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);        
    }
	if (FAILED(hr = pIADNewUser->Put(CComBSTR("msExchPoliciesIncluded"), varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put msExchPoliciesIncluded Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);     
	}
	if(FAILED(hr = pIADNewUser->SetInfo()))
            ThrowSetInfoException(hr, L"SetInfo - msExchPoliciesIncluded Failed.");

	varProp.Clear();
	if( FAILED(hr= pIAds->Get(CComBSTR("msExchUserAccountControl"),&varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Get msExchUserAccountControl Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);        
    }
	if (FAILED(hr = pIADNewUser->Put(CComBSTR("msExchUserAccountControl"), varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put msExchUserAccountControl Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);    
	}
	if(FAILED(hr = pIADNewUser->SetInfo()))
            ThrowSetInfoException(hr, L"SetInfo - msExchUserAccountControl Failed.");

	varProp.Clear();
	if(FAILED(hr = pIAds->GetEx(CComBSTR("showInAddressBook"), &varProp )))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Get showInAddressBook Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);		
	}
	if(FAILED(hr = pIADNewUser->Put(CComBSTR("showInAddressBook"), varProp)))
	{
		throw ExchangeAdminException(hr, L"CreateExchangeMailBox(): Put showInAddressBook Failed.",
            ERR_CREATE_EXCHMBX, __LINE__, __FILE__);
	}
	if(FAILED(hr = pIADNewUser->SetInfo()))
            ThrowSetInfoException(hr, L"SetInfo - showInAddressBook Failed.");
    return hr;
}
////////////////////////////////////////////
// OnExecute
// Demonstrate:
// IDirectorySearch::ExecuteSearch
// IDirectorySearch::GetNextRow
// IDirectorySearch::GetColumn
// IDirectorySearch::SetSearchPreference
//
/////////////////////////////////////////////
void CDlgIDirectorySearch::OnExecute() 
{
	ASSERT( m_pSearch );
	CWaitCursor wait;
	
	UpdateData(TRUE); // Get data from the Dialog Box
	HRESULT hr;
	ADS_SEARCH_HANDLE hSearch;
	ADS_SEARCH_COLUMN col;
	CString s;
	int idx=0;
	int nCount;
	LPWSTR *pszAttr=NULL;
	POSITION pos;
	USES_CONVERSION;


	


	/////////////////////////////////
	// Reset the Total Number
	//////////////////////////////////
	SetDlgItemText( IDC_TOTAL, _T(""));


	/////////////////////////////////////////////
	// Get the attribute list, and preparing..
	///////////////////////////////////////////
	CStringList sAttrList;
	m_cListView.DeleteAllItems(); // Reset the UI

    while( m_cListView.DeleteColumn(0))
	{
		;
	}

	//////////////////////////////////////////////////
	// Preparing for attribute list
	// and columns to display
	CString sTemp;
	m_cAttrList.GetWindowText(s);

	// we need to add adspath, so that we can refer to this object later when user dblclk the item
	if ( !s.IsEmpty() )
	{
		sTemp = s;
		sTemp.MakeLower();
		if ( s.Find(_T("adspath"),0) == -1 )
		{
			s += _T(",ADsPath");
		}
	}

	// convert to string list for easy manipulation
	StringToStringList( s, sAttrList );



	nCount = sAttrList.GetCount();
	idx=0;
	if ( nCount )
	{
		
		pszAttr = (LPWSTR*) AllocADsMem( nCount * sizeof(LPWSTR));
	
		pos = sAttrList.GetHeadPosition();
		while ( pos != NULL )
		{
			s = sAttrList.GetAt(pos);
			pszAttr[idx] = T2OLE(s);
			sAttrList.GetNext(pos );
			idx++;
		}
	}
	else
	{
		nCount = -1;
	}






	/////////////////////////////////////////
	// BEGIN  Set the preferences
	///////////////////////////////////////
	DWORD dwCountPref = 0;
	ADS_SEARCHPREF_INFO prefInfo[ MAX_SEARCH_PREF ];
	ADS_SORTKEY *pSortKey = NULL;

	if ( m_bEnableFilter == FALSE )
	{
		// Reset the preference
		m_pSearch->SetSearchPreference( prefInfo, dwCountPref );
	}
	else // Preferences are specified
	{
		////////////////////////
		// Timeout Pref
		////////////////////////////
		if ( m_nTimeOut != 0 )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_TIMEOUT;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			prefInfo[dwCountPref].vValue.Integer = m_nTimeOut;
			dwCountPref++;
		}

		//////////////////////////////
		// Search Scope
		/////////////////////////////
		idx = m_CADsSearchScope.GetCurSel();
		if ( idx != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			prefInfo[dwCountPref].vValue.Integer = idx;
			dwCountPref++;
		}



		///////////////////////////////////////////////////
		// Cache Result. The default is to cache the result
		/////////////////////////////////////////////////
		if ( !m_bCacheResult )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
			prefInfo[dwCountPref].vValue.Boolean = FALSE;
			dwCountPref++;
		}

		//////////////////////////////////////////////////
		// Page Size
		///////////////////////////////////////////////////
		if ( m_nPageSize > 0 )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;;
			prefInfo[dwCountPref].vValue.Integer = m_nPageSize;
			dwCountPref++;
		}


		////////////////////////////////////////////////
		// Chase Referrals
		///////////////////////////////////////////////
		idx = m_cChaseReferrals.GetCurSel();
		if ( idx != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			switch( idx )
			{
			case 0:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_NEVER; 
				 break;
			case 1:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_SUBORDINATE;
				 break;
			case 2:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
				 break;
			default:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
				 
			}
			
			dwCountPref++;
		}


		///////////////////////////////////////////////
		// Sort On
		////////////////////////////////////////////////
		if ( !m_sSortOn.IsEmpty() )
		{
			CStringList sList;
			UINT nCount;
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SORT_ON;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
  			StringToStringList( m_sSortOn, sList );

			nCount = sList.GetCount();
			if ( nCount >  0 )
			{
				POSITION pos;
				pos= sList.GetHeadPosition();
				pSortKey = (ADS_SORTKEY *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(ADS_SORTKEY) * nCount );
				idx = 0;
				while( pos != NULL )
				{
					pSortKey[idx].pszAttrType = T2OLE(sList.GetAt(pos));
					pSortKey[idx].pszReserved = NULL;
					pSortKey[idx].fReverseorder =0;

					// Next
					idx++;
					sList.GetNext( pos );
				}
				
				prefInfo[dwCountPref].vValue.ProviderSpecific.dwLength = sizeof(ADS_SORTKEY) * nCount;
				prefInfo[dwCountPref].vValue.ProviderSpecific.lpValue = (LPBYTE) pSortKey;
				dwCountPref++;
			}

		}

		//////////////////////////////////////////////
		// Size Limit
		//////////////////////////////////////////////
		if ( m_nSizeLimit > 0 )
		{
            prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SIZE_LIMIT;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
            prefInfo[dwCountPref].vValue.Integer = m_nSizeLimit;
			dwCountPref++;
		}


		//////////////////////////////////////////////////
		// A Synchronous
		///////////////////////////////////////////////////
		if ( m_bAsynch )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
            prefInfo[dwCountPref].vValue.Integer = TRUE;
			dwCountPref++;

		}

		/////////////////////////////////////////////////////
		//  Attribute Type Only
		//////////////////////////////////////////////////////
		if ( m_bAttrib )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_ATTRIBTYPES_ONLY;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
            prefInfo[dwCountPref].vValue.Integer = TRUE;
			dwCountPref++;

		}


		/////////////////////////////////////////////////////
		//  Derefence Alias
		//////////////////////////////////////////////////////
		if ( m_nDeref != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_DEREF_ALIASES;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
            prefInfo[dwCountPref].vValue.Integer = m_nDeref;
			dwCountPref++;


		}



		///////////////////////////////////////////////
		// Now Set the selected preferences
		//////////////////////////////////////////////
		hr = m_pSearch->SetSearchPreference( prefInfo, dwCountPref );


		
	}

	/////////////////////////////////////////
	// END  Set the preferences
	///////////////////////////////////////





	////////////////////////////////////////
	// Execute the Search
	//////////////////////////////////////
	DWORD dwCount=0;

	hr = m_pSearch->ExecuteSearch(T2OLE(m_sFilter), pszAttr, nCount, &hSearch );


	////////////////////////////////
	//// cleanup
	////////////////////////////////
	if ( pszAttr ) 
	{
  		FreeADsMem( pszAttr );
	}
	
	if ( pSortKey )
	{
		LocalFree( pSortKey );
	}




	if ( !SUCCEEDED(hr) )
	{
		AfxMessageBox(GetErrorMessage(hr));
		return;
	}

	////////////////////////////////////////////////////////
	// Enumerate the rows
	////////////////////////////////////////////////////////

	sAttrList.RemoveAll();

	

	
	/////////////////////////////////////////////////////////
	// Retrieve the column names returned from the server
	///////////////////////////////////////////////////////////
	LPWSTR pszColumn;
	hr = m_pSearch->GetFirstRow( hSearch );

	if ( !SUCCEEDED(hr) )
	{
		return;
	}
	
	

	idx=0;
	while( (hr=m_pSearch->GetNextColumnName( hSearch, &pszColumn )) != S_ADS_NOMORE_COLUMNS )
	{
		s = OLE2T( pszColumn );
		m_cListView.InsertColumn(idx, s, LVCFMT_LEFT, 150 ); // adding columns to the UI	
		sAttrList.AddTail(s);
		FreeADsMem( pszColumn );
		idx++;
	}



	/////////////////////////////////////////////
	// Start iterating the result set
	////////////////////////////////////////////
	int nCol;
	CStringList sValueList;

    do 
	{
		nCol=0;
		pos = sAttrList.GetHeadPosition();

		while( pos != NULL )
		{
		
		    s = sAttrList.GetAt(pos); //column name

			// Get the Name and display it in the list 
			hr = m_pSearch->GetColumn( hSearch, T2OLE(s), &col );
			if ( SUCCEEDED(hr) )
			{
				s =_T("");
				
				if ( col.dwADsType != ADSTYPE_INVALID ) // if we request for attrib only, no value will be returned
				{
					ADsToStringList(col.pADsValues, col.dwNumValues, sValueList );
					StringListToString( sValueList, s );
				}
	
				if ( nCol )
				{
					m_cListView.SetItemText(0,nCol, s);
				}
				else
				{
				   m_cListView.InsertItem(0, s);
				}
				
				m_pSearch->FreeColumn( &col );
			}


			

			nCol++;
			sAttrList.GetNext(pos);

		}
		dwCount++;
		/////////////////////////////
		//Display the total so far
		////////////////////////////////
		s.Format("%ld object(s)", dwCount );
		SetDlgItemText( IDC_TOTAL, s );
	
	} 
	while( (hr=m_pSearch->GetNextRow( hSearch)) != S_ADS_NOMORE_ROWS );	 

	

	m_pSearch->CloseSearchHandle( hSearch ); 



	


}
HRESULT FindUsers(IDirectorySearch *pContainerToSearch,  //IDirectorySearch pointer to Partitions container.
		 LPOLESTR szFilter, //Filter for finding specific crossrefs.
                            //NULL returns all attributeSchema objects.
         LPOLESTR *pszPropertiesToReturn, //Properties to return for crossRef objects found
					                    //NULL returns all set properties.
		 unsigned long ulNumPropsToReturn, // Number of property strings in pszPropertiesToReturn
		 BOOL bIsVerbose //TRUE means all properties for the found objects are displayed.
		                 //FALSE means only the RDN
							)
{
	if (!pContainerToSearch)
		return E_POINTER;
    //Create search filter
	LPOLESTR pszSearchFilter = new OLECHAR[MAX_PATH*2];
	if ( !pszSearchFilter )
			return E_OUTOFMEMORY;
	wchar_t szFormat[] = L"(&(objectClass=user)(objectCategory=person)%s)";

	// Check the buffer first
	 if ( IS_BUFFER_ENOUGH(MAX_PATH*2, szFormat, szFilter) > 0 )
	 {
		 //Add the filter.
          swprintf_s(pszSearchFilter, MAX_PATH*2, szFormat,szFilter);
	 }
	 else
	 {
		 wprintf(L"The filter is too large for buffer, aborting...");
		 delete [] pszSearchFilter; 
         return FALSE;
	 }
	
    

    //Specify subtree search
	ADS_SEARCHPREF_INFO SearchPrefs;
	SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
	SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
	SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
    DWORD dwNumPrefs = 1;

	// COL for iterations
	LPOLESTR pszColumn = NULL;    
	ADS_SEARCH_COLUMN col;
    HRESULT hr;
    
    // Interface Pointers
    IADs    *pObj = NULL;
    IADs	* pIADs = NULL;

    // Handle used for searching
    ADS_SEARCH_HANDLE hSearch = NULL;
	
	// Set the search preference
    hr = pContainerToSearch->SetSearchPreference( &SearchPrefs, dwNumPrefs);
    if (FAILED(hr))
	{
		delete [] pszSearchFilter;
        return hr;
	}

	LPOLESTR pszBool = NULL;
	DWORD dwBool;
	PSID pObjectSID = NULL;
	LPOLESTR szSID = NULL;
	LPOLESTR szDSGUID = new WCHAR [39];
	LPGUID pObjectGUID = NULL;
	FILETIME filetime;
	SYSTEMTIME systemtime;
	DATE date;
	VARIANT varDate;
	LARGE_INTEGER liValue;
	LPOLESTR *pszPropertyList = NULL;
	LPOLESTR pszNonVerboseList[] = {L"name",L"distinguishedName"};
	unsigned long ulNonVbPropsCount = 2;

	LPOLESTR szName = new OLECHAR[MAX_PATH];
	LPOLESTR szDN = new OLECHAR[MAX_PATH];

	if ( !szName || !szDN )
	{
		delete [] pszSearchFilter;
		if ( szDN )
			delete [] szDN;
		if ( szName  )
			delete [] szName ;

		return E_OUTOFMEMORY;
	}

	int iCount = 0;
	DWORD x = 0L;



	if (!bIsVerbose)
	{
		 //Return non-verbose list properties only
         hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
		                          pszNonVerboseList,
								  ulNonVbPropsCount,
								  &hSearch
								  );
	}
	else
	{
		if (!pszPropertiesToReturn)
		{
			//Return all properties.
			hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
		                          NULL,
								  -1L,
								  &hSearch
								  );
		}
		else
		{
			//specified subset.
		    pszPropertyList = pszPropertiesToReturn;
		   //Return specified properties
		   hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
		                          pszPropertyList,
								  sizeof(pszPropertyList)/sizeof(LPOLESTR),
								  &hSearch
								  );
		}
	}
 	if ( SUCCEEDED(hr) )
	{    
    // Call IDirectorySearch::GetNextRow() to retrieve the next row 
    //of data
	  hr = pContainerToSearch->GetFirstRow( hSearch);
	  if (SUCCEEDED(hr))
	  {
        while( hr != S_ADS_NOMORE_ROWS )
		{
			//Keep track of count.
			iCount++;
			if (bIsVerbose)
			  wprintf(L"----------------------------------\n");
            // loop through the array of passed column names,
            // print the data for each column

			while( pContainerToSearch->GetNextColumnName( hSearch, &pszColumn ) != S_ADS_NOMORE_COLUMNS )
            {
                hr = pContainerToSearch->GetColumn( hSearch, pszColumn, &col );
			    if ( SUCCEEDED(hr) )
			    {
		            // Print the data for the column and free the column
				  if(bIsVerbose)
				  {
			        // Get the data for this column
				    wprintf(L"%s\n",col.pszAttrName);
					switch (col.dwADsType)
					{
						case ADSTYPE_DN_STRING:
                          for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %s\r\n",col.pADsValues[x].DNString);
						  }
						  break;
						case ADSTYPE_CASE_EXACT_STRING:	    
						case ADSTYPE_CASE_IGNORE_STRING:	    
						case ADSTYPE_PRINTABLE_STRING:	    
						case ADSTYPE_NUMERIC_STRING:	        
						case ADSTYPE_TYPEDNAME:	            
						case ADSTYPE_FAXNUMBER:	            
						case ADSTYPE_PATH:	                
						case ADSTYPE_OBJECT_CLASS:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %s\r\n",col.pADsValues[x].CaseIgnoreString);
						  }
						  break;
						case ADSTYPE_BOOLEAN:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  dwBool = col.pADsValues[x].Boolean;
							  pszBool = dwBool ? L"TRUE" : L"FALSE";
							  wprintf(L"  %s\r\n",pszBool);
						  }
						  break;
						case ADSTYPE_INTEGER:
					      for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  %d\r\n",col.pADsValues[x].Integer);
						  }
						  break;
						case ADSTYPE_OCTET_STRING:
						    if ( _wcsicmp(col.pszAttrName,L"objectSID") == 0 )
							{
						      for (x = 0; x< col.dwNumValues; x++)
							  {
								  pObjectSID = (PSID)(col.pADsValues[x].OctetString.lpValue);
								  //Convert SID to string.
								  ConvertSidToStringSid(pObjectSID, &szSID);
								  wprintf(L"  %s\r\n",szSID);
								  LocalFree(szSID);
							  }
							}
						    else if ( (_wcsicmp(col.pszAttrName,L"objectGUID") == 0) )
							{
						      for (x = 0; x< col.dwNumValues; x++)
							  {
								//Cast to LPGUID
								pObjectGUID = (LPGUID)(col.pADsValues[x].OctetString.lpValue);
								//Convert GUID to string.
								::StringFromGUID2(*pObjectGUID, szDSGUID, 39); 
								//Print the GUID
								wprintf(L"  %s\r\n",szDSGUID);
							  }
							}
							else
							  wprintf(L"  Value of type Octet String. No Conversion.");
						    break;
						case ADSTYPE_UTC_TIME:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							systemtime = col.pADsValues[x].UTCTime;
							if (SystemTimeToVariantTime(&systemtime,
														&date) != 0) 
							{
								//Pack in variant.vt
								varDate.vt = VT_DATE;
								varDate.date = date;
								VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
							    wprintf(L"  %s\r\n",varDate.bstrVal);
								VariantClear(&varDate);
							}
							else
								wprintf(L"Could not convert UTC-Time.\n");
						  }
						  break;
						case ADSTYPE_LARGE_INTEGER:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
						    liValue = col.pADsValues[x].LargeInteger;
							filetime.dwLowDateTime = liValue.LowPart;
							filetime.dwHighDateTime = liValue.HighPart;
							if((filetime.dwHighDateTime==0) && (filetime.dwLowDateTime==0))
							{
								wprintf(L"  No value set.\n");
							}
							else
							{
								//Check for properties of type LargeInteger that represent time
								//if TRUE, then convert to variant time.
								if ((0==wcscmp(L"accountExpires", col.pszAttrName))|
									(0==wcscmp(L"badPasswordTime", col.pszAttrName))||
									(0==wcscmp(L"lastLogon", col.pszAttrName))||
									(0==wcscmp(L"lastLogoff", col.pszAttrName))||
									(0==wcscmp(L"lockoutTime", col.pszAttrName))||
									(0==wcscmp(L"pwdLastSet", col.pszAttrName))
								   )
								{
									//Handle special case for Never Expires where low part is -1
									if (filetime.dwLowDateTime==-1)
									{
										wprintf(L"  Never Expires.\n");
									}
									else
									{
										if (FileTimeToLocalFileTime(&filetime, &filetime) != 0) 
										{
											if (FileTimeToSystemTime(&filetime,
																 &systemtime) != 0)
											{
												if (SystemTimeToVariantTime(&systemtime,
																			&date) != 0) 
												{
													//Pack in variant.vt
													varDate.vt = VT_DATE;
													varDate.date = date;
													VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
													wprintf(L"  %s\r\n",varDate.bstrVal);
													VariantClear(&varDate);
												}
												else
												{
													wprintf(L"  FileTimeToVariantTime failed\n");
												}
											}
											else
											{
												wprintf(L"  FileTimeToSystemTime failed\n");
											}

										}
										else
										{
											wprintf(L"  FileTimeToLocalFileTime failed\n");
										}
									}
								}
								else
								{
									//Print the LargeInteger.
									wprintf(L"  high: %d low: %d\r\n",filetime.dwHighDateTime, filetime.dwLowDateTime);
								}
							}
						  }
						  break;
						case ADSTYPE_NT_SECURITY_DESCRIPTOR:
						  for (x = 0; x< col.dwNumValues; x++)
						  {
							  wprintf(L"  Security descriptor.\n");
						  }
						  break;
						default:
				          wprintf(L"Unknown type %d.\n",col.dwADsType);
					}
				  }
			      else
				  {
					//Verbose handles only the two single-valued attributes: cn and ldapdisplayname
					//so this is a special case.
					
					if (0==wcscmp(L"name", pszColumn))
					{
					  szName[0]=L'\0';
					  if( IS_BUFFER_ENOUGH(MAX_PATH, szName, col.pADsValues->CaseIgnoreString) > 0 )
					  {
					       wcscpy_s(szName,MAX_PATH,col.pADsValues->CaseIgnoreString);
					  }
					}
					if (0==wcscmp(L"distinguishedName", pszColumn))
					{
						szDN[0]=L'\0';
						if( IS_BUFFER_ENOUGH(MAX_PATH, szDN, col.pADsValues->CaseIgnoreString) > 0 )
						{
					       wcscpy_s(szDN,MAX_PATH,col.pADsValues->CaseIgnoreString);
						}
					}
				  }
			      pContainerToSearch->FreeColumn( &col );
			    }
				FreeADsMem( pszColumn );
            }
		   if (!bIsVerbose)
			   wprintf(L"%s\n  DN: %s\n\n",szName,szDN);
 		   //Get the next row
		   hr = pContainerToSearch->GetNextRow( hSearch);
		}

	  }
	  // Close the search handle to clean up
      pContainerToSearch->CloseSearchHandle(hSearch);
	} 
	if (SUCCEEDED(hr) && 0==iCount)
		hr = S_FALSE;
	delete [] pszSearchFilter;
	delete [] szName;
	delete [] szDN;
    return hr;
}
void CDlgIDirectoryObject::OnGet() 
{
   CStringList sList;
   UINT nCount;
   HRESULT hr;
   

   UpdateData(TRUE);

   StringToStringList(m_sAttributes, sList );
   nCount = sList.GetCount();
   if ( nCount == 0 )
   {
	   return;
   }

   
   
   ///////////////////////////////////////
   // Now build the Attribute Names List
   ///////////////////////////////////////
   POSITION			pos;
   DWORD			dwNumAttr;
   LPWSTR			*pAttrNames=NULL;
   ADS_ATTR_INFO	*pAttrInfo;
   DWORD			dwReturn;
   

   USES_CONVERSION;


   pAttrNames = (LPWSTR*) AllocADsMem( sizeof(LPWSTR) * nCount );
   pos = sList.GetHeadPosition();
   dwNumAttr = 0;
   while( pos != NULL )
   {
	   pAttrNames[dwNumAttr] = T2OLE(sList.GetAt(pos));
	   dwNumAttr++;
	   sList.GetNext(pos);
   }

   
 
   
   /////////////////////////////////////////
   // Get attributes value requested
   // Note: The order is not necessarily the same as
   //       requested via pAttrNames.
   ///////////////////////////////////////////
   hr = m_pDirObject->GetObjectAttributes( pAttrNames, dwNumAttr, &pAttrInfo, &dwReturn );

   

   if ( SUCCEEDED(hr) )
   {
	  DWORD idx;
	  CString sDisplay;
	  CStringList sValueList;
	  UINT nCount;
	  POSITION pos;

	  m_cValueList.ResetContent();

	  for( idx=0; idx < dwReturn; idx++) 
	  {		  
          ADsToStringList( pAttrInfo[idx].pADsValues, pAttrInfo[idx].dwNumValues, sValueList );
		  sDisplay = OLE2T(pAttrInfo[idx].pszAttrName);
		  sDisplay += _T(":");
		  m_cValueList.AddString( sDisplay );
		  nCount = sValueList.GetCount();
		  if ( nCount == 0 ) // can not find/convert the value
		  {
			  m_cValueList.AddString(_T(" > [No Value]"));
			  continue;
		  }
		  else
		  {
			  pos = sValueList.GetHeadPosition();
			  while( pos != NULL )
			  {
				  sDisplay = _T(" > ");
				  sDisplay += sValueList.GetAt(pos);
				  m_cValueList.AddString( sDisplay );
				  sValueList.GetNext(pos);
			  }

		  }
		  
	  }

	  sValueList.RemoveAll();
   }

   

   ///////////////////////////////////////////////////////////
   // Use FreADsMem for all memory obtained from ADSI call 
   /////////////////////////////////////////////////////////////
   FreeADsMem( pAttrInfo );
   FreeADsMem( pAttrNames );

	
}