849 lines
21 KiB
C++
849 lines
21 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: cenumdom.cxx
|
|
//
|
|
// Contents: LDAP Object Enumeration Code
|
|
//
|
|
// CLDAPGenObjectEnum::CLDAPGenObjectEnum()
|
|
// CLDAPGenObjectEnum::CLDAPGenObjectEnum
|
|
//
|
|
// History:
|
|
//----------------------------------------------------------------------------
|
|
#include "ldap.hxx"
|
|
#pragma hdrstop
|
|
|
|
HRESULT
|
|
BuildLDAPFilterArray(
|
|
VARIANT vFilter,
|
|
LPTSTR *ppszFilter
|
|
);
|
|
|
|
#define FILTER_BUFFER_LEN 256
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPEnumVariant::Create
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pCollection]
|
|
// [ppEnumVariant]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 01-30-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CLDAPGenObjectEnum::Create(
|
|
CLDAPGenObjectEnum FAR* FAR* ppenumvariant,
|
|
BSTR ADsPath,
|
|
PADSLDP pLdapHandle,
|
|
IADs *pADs,
|
|
VARIANT vFilter,
|
|
CCredentials& Credentials,
|
|
DWORD dwOptReferral,
|
|
DWORD dwPageSize
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
CLDAPGenObjectEnum FAR* penumvariant = NULL;
|
|
TCHAR *pszLDAPServer = NULL;
|
|
DWORD dwModificationTime = 0L;
|
|
DWORD dwNumberOfEntries = 0L;
|
|
LPTSTR aStrings[2];
|
|
DWORD dwPort = 0;
|
|
WCHAR **aValues = NULL;
|
|
int nCount = 0;
|
|
DWORD totalCount = 0;
|
|
DWORD dwcEntriesReturned = 0;
|
|
|
|
|
|
PLDAPControl pPagedControl = NULL;
|
|
LDAPControl referralControl =
|
|
{
|
|
LDAP_CONTROL_REFERRALS_W,
|
|
{
|
|
sizeof( DWORD ), (PCHAR) &dwOptReferral
|
|
},
|
|
TRUE
|
|
};
|
|
|
|
PLDAPControl clientControls[2] =
|
|
{
|
|
&referralControl,
|
|
NULL
|
|
};
|
|
|
|
|
|
PLDAPControl serverControls[2] = {NULL, NULL};
|
|
PLDAPControl *serverReturnedControls = NULL;
|
|
|
|
penumvariant = new CLDAPGenObjectEnum();
|
|
if (!penumvariant) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = ADsAllocString( ADsPath, &penumvariant->_ADsPath);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
penumvariant->_dwOptReferral = dwOptReferral;
|
|
penumvariant->_dwPageSize = dwPageSize;
|
|
|
|
hr = BuildLDAPFilterArray(
|
|
vFilter,
|
|
&penumvariant->_pszFilter
|
|
);
|
|
|
|
if ( FAILED(hr) || !penumvariant->_pszFilter ) // this might happen when vFilter is empty
|
|
{
|
|
hr = S_OK;
|
|
penumvariant->_pszFilter = AllocADsStr(TEXT("(objectClass=*)"));
|
|
|
|
if ( penumvariant->_pszFilter == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
}
|
|
|
|
penumvariant->_Credentials = Credentials;
|
|
|
|
hr = BuildLDAPPathFromADsPath2(
|
|
ADsPath,
|
|
&pszLDAPServer,
|
|
&penumvariant->_pszLDAPDn,
|
|
&dwPort
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
penumvariant->_pLdapHandle = pLdapHandle;
|
|
|
|
// Need to AddRef since we are storing the ld that is owned by the object
|
|
pADs->AddRef();
|
|
penumvariant->_pADs = pADs;
|
|
|
|
aStrings[0] = TEXT("objectClass");
|
|
aStrings[1] = NULL;
|
|
|
|
|
|
//
|
|
// Check if paged search control is supported; if so, we will use it.
|
|
//
|
|
|
|
hr = ReadPagingSupportedAttr(
|
|
pszLDAPServer,
|
|
&penumvariant->_fPagedSearch,
|
|
Credentials,
|
|
dwPort
|
|
) ;
|
|
|
|
if (penumvariant->_fPagedSearch) {
|
|
|
|
//
|
|
// In this case we wont to use the ldap paging API
|
|
// wrapper rather than use cookies directly.
|
|
//
|
|
hr = LdapSearchInitPage(
|
|
penumvariant->_pLdapHandle,
|
|
penumvariant->_pszLDAPDn,
|
|
LDAP_SCOPE_ONELEVEL,
|
|
penumvariant->_pszFilter,
|
|
aStrings,
|
|
0,
|
|
NULL,
|
|
clientControls,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&penumvariant->_phPagedSearch
|
|
);
|
|
|
|
if (FAILED(hr) || (penumvariant->_phPagedSearch == NULL)) {
|
|
//
|
|
// Some error in setting up the paged control, default to non
|
|
// paged search.
|
|
//
|
|
penumvariant->_fPagedSearch = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!penumvariant->_fPagedSearch) {
|
|
|
|
hr = LdapSearchExtS(
|
|
penumvariant->_pLdapHandle,
|
|
penumvariant->_pszLDAPDn,
|
|
LDAP_SCOPE_ONELEVEL,
|
|
penumvariant->_pszFilter,
|
|
aStrings,
|
|
0,
|
|
NULL,
|
|
clientControls,
|
|
NULL,
|
|
0,
|
|
&penumvariant->_res
|
|
);
|
|
|
|
|
|
//
|
|
// Error out only if there are no entries returned.
|
|
//
|
|
|
|
dwcEntriesReturned = LdapCountEntries(
|
|
penumvariant->_pLdapHandle,
|
|
penumvariant->_res
|
|
);
|
|
|
|
if (FAILED(hr) && !dwcEntriesReturned) {
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
} // if not do the paged search case
|
|
else {
|
|
|
|
if (penumvariant->_fPagedSearch) {
|
|
|
|
//
|
|
// Get the first page full of results.
|
|
//
|
|
hr = LdapGetNextPageS(
|
|
penumvariant->_pLdapHandle,
|
|
penumvariant->_phPagedSearch,
|
|
NULL,
|
|
penumvariant->_dwPageSize,
|
|
&totalCount,
|
|
&penumvariant->_res
|
|
);
|
|
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
|
|
|
|
penumvariant->_fLastPage = TRUE;
|
|
goto error;
|
|
|
|
} else if ((hr == HRESULT_FROM_WIN32(ERROR_DS_SIZELIMIT_EXCEEDED))
|
|
&& totalCount != 0) {
|
|
|
|
penumvariant->_fLastPage = TRUE;
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
} // the paged search case
|
|
|
|
|
|
error:
|
|
|
|
if ( pszLDAPServer )
|
|
FreeADsStr( pszLDAPServer);
|
|
|
|
if (pPagedControl) {
|
|
LdapControlFree(pPagedControl);
|
|
}
|
|
|
|
if (serverReturnedControls) {
|
|
LdapControlsFree(serverReturnedControls);
|
|
}
|
|
|
|
|
|
if (FAILED(hr) && !dwcEntriesReturned) {
|
|
|
|
if (penumvariant) delete penumvariant;
|
|
|
|
*ppenumvariant = NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// entries successfully retrieved from server, return them
|
|
// to client even if error and let client decide
|
|
//
|
|
|
|
*ppenumvariant = penumvariant;
|
|
}
|
|
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
CLDAPGenObjectEnum::CLDAPGenObjectEnum():
|
|
_ADsPath(NULL),
|
|
_fAllEntriesReturned(FALSE),
|
|
_fPagedSearch(FALSE),
|
|
_fLastPage(FALSE),
|
|
_dwOptReferral(LDAP_CHASE_EXTERNAL_REFERRALS),
|
|
_pszFilter(NULL),
|
|
_pszLDAPDn(NULL),
|
|
_phPagedSearch(NULL)
|
|
|
|
{
|
|
_pObjList = NULL;
|
|
|
|
_pLdapHandle = NULL;
|
|
_pADs = NULL;
|
|
|
|
_res = NULL;
|
|
_entry = NULL;
|
|
}
|
|
|
|
|
|
CLDAPGenObjectEnum::~CLDAPGenObjectEnum()
|
|
{
|
|
if ( _res )
|
|
LdapMsgFree( _res );
|
|
|
|
if (_pszFilter) {
|
|
FreeADsMem(_pszFilter);
|
|
}
|
|
|
|
if (_pszLDAPDn) {
|
|
FreeADsMem(_pszLDAPDn);
|
|
}
|
|
|
|
if (_fPagedSearch) {
|
|
LdapSearchAbandonPage(_pLdapHandle, _phPagedSearch);
|
|
|
|
}
|
|
|
|
if ( _pADs )
|
|
_pADs->Release();
|
|
|
|
if ( _ADsPath )
|
|
ADsFreeString( _ADsPath );
|
|
|
|
if ( _pObjList )
|
|
delete _pObjList;
|
|
|
|
_pLdapHandle = NULL;
|
|
_phPagedSearch = NULL;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CLDAPGenObjectEnum::EnumGenericObjects(
|
|
ULONG cElements,
|
|
VARIANT FAR* pvar,
|
|
ULONG FAR* pcElementFetched
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDispatch *pDispatch = NULL;
|
|
DWORD i = 0;
|
|
BOOL fRepeat = FALSE;
|
|
DWORD dwFailureCount = 0;
|
|
DWORD dwPermitFailure = 1000;
|
|
|
|
|
|
while (i < cElements) {
|
|
|
|
hr = GetGenObject(&pDispatch);
|
|
if (hr == S_FALSE) {
|
|
break;
|
|
}
|
|
else if (FAILED(hr)) {
|
|
//
|
|
// Got an error while retrieving the object, ignore the
|
|
// error and continue with the next object.
|
|
// If continuously getting error more than dwPermitFailure,
|
|
// make the return value S_FALSE, leave the loop.
|
|
//
|
|
if (fRepeat) {
|
|
dwFailureCount++;
|
|
if(dwFailureCount > dwPermitFailure) {
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
fRepeat = TRUE;
|
|
dwFailureCount = 1;
|
|
}
|
|
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
|
|
|
|
if (fRepeat) {
|
|
fRepeat = FALSE;
|
|
}
|
|
|
|
VariantInit(&pvar[i]);
|
|
pvar[i].vt = VT_DISPATCH;
|
|
pvar[i].pdispVal = pDispatch;
|
|
(*pcElementFetched)++;
|
|
i++;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CLDAPGenObjectEnum::GetGenObject(
|
|
IDispatch ** ppDispatch
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPTSTR pszObjectName = NULL;
|
|
TCHAR **aValues = NULL;
|
|
int nCount = 0;
|
|
DWORD totalCount = 0;
|
|
TCHAR szADsClassName[64];
|
|
LPWSTR aStrings[2] = {TEXT("objectClass"), NULL};
|
|
|
|
DWORD dwPort;
|
|
LPWSTR pszLDAPServer = NULL;
|
|
LPWSTR pszLDAPDn = NULL;
|
|
LPWSTR pszADsPathParent = NULL;
|
|
|
|
BOOL fGCNameSpace = FALSE;
|
|
|
|
|
|
PLDAPControl pPagedControl = NULL;
|
|
PLDAPControl serverControls[2] = {NULL, NULL};
|
|
PLDAPControl *serverReturnedControls = NULL;
|
|
|
|
LDAPControl referralControl =
|
|
{
|
|
LDAP_CONTROL_REFERRALS_W,
|
|
{
|
|
sizeof( DWORD ), (PCHAR) &_dwOptReferral
|
|
},
|
|
TRUE
|
|
};
|
|
|
|
PLDAPControl clientControls[2] =
|
|
{
|
|
&referralControl,
|
|
NULL
|
|
};
|
|
|
|
OBJECTINFO ObjectInfoLocal;
|
|
|
|
memset(&ObjectInfoLocal, 0, sizeof(OBJECTINFO));
|
|
|
|
*ppDispatch = NULL;
|
|
|
|
if ( _fAllEntriesReturned )
|
|
{
|
|
hr = S_FALSE;
|
|
goto error;
|
|
}
|
|
|
|
if ( _entry == NULL )
|
|
hr = LdapFirstEntry( _pLdapHandle, _res, &_entry );
|
|
else
|
|
hr = LdapNextEntry( _pLdapHandle, _entry, &_entry );
|
|
|
|
if (FAILED(hr) ) {
|
|
|
|
_fAllEntriesReturned = TRUE;
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
else if ( _entry == NULL ) {
|
|
|
|
if (!_fPagedSearch || _fLastPage) { // reached the end of enumeration
|
|
|
|
hr = S_FALSE;
|
|
_fAllEntriesReturned = TRUE;
|
|
goto error;
|
|
}
|
|
else { // more pages are remaining
|
|
//
|
|
// release this page
|
|
//
|
|
if (_res) {
|
|
LdapMsgFree(
|
|
_res
|
|
);
|
|
}
|
|
|
|
//
|
|
// Get the next page of results
|
|
//
|
|
//
|
|
// Get the first page full of results.
|
|
//
|
|
hr = LdapGetNextPageS(
|
|
_pLdapHandle,
|
|
_phPagedSearch,
|
|
NULL,
|
|
_dwPageSize,
|
|
&totalCount,
|
|
&_res
|
|
);
|
|
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
|
|
|
|
_fLastPage = TRUE;
|
|
hr = S_FALSE;
|
|
goto error;
|
|
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LdapFirstEntry(_pLdapHandle, _res, &_entry );
|
|
|
|
if (FAILED(hr) ) {
|
|
|
|
_fAllEntriesReturned = TRUE;
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
else if ( (_entry == NULL) ) { // reached the end of enumeration
|
|
|
|
hr = S_FALSE;
|
|
_fAllEntriesReturned = TRUE;
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = LdapGetDn( _pLdapHandle, _entry, &pszObjectName );
|
|
|
|
if (FAILED(hr) ) {
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = LdapGetValues( _pLdapHandle, _entry, TEXT("objectClass"),
|
|
&aValues, &nCount );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if ( nCount == 0 )
|
|
{
|
|
// This object exists but does not contain objectClass attribute
|
|
// which is required for all DS objects. Hence, ignore the object
|
|
// and return error.
|
|
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Now send back the current object
|
|
//
|
|
|
|
{
|
|
CLexer Lexer(pszObjectName);
|
|
hr = InitObjectInfo(pszObjectName,
|
|
&ObjectInfoLocal);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
Lexer.SetAtDisabler(TRUE);
|
|
|
|
Lexer.SetFSlashDisabler(TRUE);
|
|
|
|
hr = PathName(&Lexer,
|
|
&ObjectInfoLocal);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
Lexer.SetFSlashDisabler(FALSE);
|
|
|
|
if (ObjectInfoLocal.ComponentArray[0].szValue == NULL) {
|
|
BAIL_ON_FAILURE(hr=E_ADS_BAD_PATHNAME);
|
|
}
|
|
DWORD len;
|
|
|
|
len = wcslen(ObjectInfoLocal.ComponentArray[0].szComponent) +
|
|
wcslen(ObjectInfoLocal.ComponentArray[0].szValue) +
|
|
1; // For equal to sign
|
|
|
|
pszObjectName[len] = '\0';
|
|
|
|
|
|
//
|
|
// We form the ADsPath to the parent by taking the _ADsPath of this
|
|
// object (which is the parent ADsPath), chopping off the DN portion,
|
|
// and attaching the parent DN portion of the object retrieved. This
|
|
// is so that the enumerated child objects get a proper parent ADsPath
|
|
// even if the parent object was bound using a GUID.
|
|
//
|
|
hr = BuildLDAPPathFromADsPath2(
|
|
_ADsPath,
|
|
&pszLDAPServer,
|
|
&pszLDAPDn,
|
|
&dwPort
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// _ADsPath could not be NULL
|
|
if(!_wcsnicmp(L"GC:", _ADsPath, wcslen(L"GC:")))
|
|
{
|
|
fGCNameSpace = TRUE;
|
|
}
|
|
|
|
if (ObjectInfoLocal.NumComponents > 1) {
|
|
//
|
|
// pszObjectName[0 ... len] = object name (e.g., "CN=child")
|
|
// pszObjectName[len+1 ....] = parent name (e.g., "OU=parent, DC=....")
|
|
//
|
|
hr = BuildADsPathFromLDAPPath2(
|
|
(pszLDAPServer ? TRUE : FALSE),
|
|
fGCNameSpace ? L"GC:" : L"LDAP:",
|
|
pszLDAPServer,
|
|
dwPort,
|
|
&(pszObjectName[len+1]),
|
|
&pszADsPathParent
|
|
);
|
|
}
|
|
else {
|
|
//
|
|
// If the count is zero or less, then the objectName will
|
|
// need to be created with a parent path of NULL. In this case
|
|
// pszObjectName[len+1] is not necessarily valid. This is
|
|
// espescially true when we have a defaultNamingContext
|
|
// that is NULL or no defaultNamingContext with an object
|
|
// directly underneath it (say dn is just o=testObject.
|
|
//
|
|
hr = BuildADsPathFromLDAPPath2(
|
|
(pszLDAPServer ? TRUE : FALSE),
|
|
fGCNameSpace ? L"GC:" : L"LDAP:",
|
|
pszLDAPServer,
|
|
dwPort,
|
|
NULL,
|
|
&pszADsPathParent
|
|
);
|
|
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = CLDAPGenObject::CreateGenericObject(
|
|
pszADsPathParent,
|
|
pszObjectName,
|
|
aValues,
|
|
nCount,
|
|
_Credentials,
|
|
ADS_OBJECT_BOUND,
|
|
IID_IDispatch,
|
|
(void **) ppDispatch
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
FreeObjectInfo(&ObjectInfoLocal);
|
|
|
|
if ( pszObjectName )
|
|
LdapMemFree( pszObjectName );
|
|
|
|
if ( aValues )
|
|
LdapValueFree( aValues );
|
|
|
|
if (pPagedControl) {
|
|
LdapControlFree(pPagedControl);
|
|
}
|
|
|
|
if (serverReturnedControls) {
|
|
LdapControlsFree(serverReturnedControls);
|
|
}
|
|
|
|
if (pszADsPathParent) {
|
|
FreeADsMem(pszADsPathParent);
|
|
}
|
|
|
|
if (pszLDAPServer) {
|
|
FreeADsMem(pszLDAPServer);
|
|
}
|
|
|
|
if (pszLDAPDn) {
|
|
FreeADsMem(pszLDAPDn);
|
|
}
|
|
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPGenObjectEnum::Next
|
|
//
|
|
// Synopsis: Returns cElements number of requested NetOle objects in the
|
|
// array supplied in pvar.
|
|
//
|
|
// Arguments: [cElements] -- The number of elements requested by client
|
|
// [pvar] -- ptr to array of VARIANTs to for return objects
|
|
// [pcElementFetched] -- if non-NULL, then number of elements
|
|
// -- actually returned is placed here
|
|
//
|
|
// Returns: HRESULT -- S_OK if number of elements requested are returned
|
|
// -- S_FALSE if number of elements is < requested
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 11-3-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CLDAPGenObjectEnum::Next(
|
|
ULONG cElements,
|
|
VARIANT FAR* pvar,
|
|
ULONG FAR* pcElementFetched
|
|
)
|
|
{
|
|
ULONG cElementFetched = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = EnumGenericObjects(
|
|
cElements,
|
|
pvar,
|
|
&cElementFetched
|
|
);
|
|
|
|
|
|
if (pcElementFetched) {
|
|
*pcElementFetched = cElementFetched;
|
|
}
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
BuildLDAPFilterArray(
|
|
VARIANT var,
|
|
LPTSTR *ppszFilter
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG dwSLBound = 0;
|
|
LONG dwSUBound = 0;
|
|
VARIANT v;
|
|
LONG i;
|
|
LONG dwBracketCount = 0;
|
|
DWORD dwFilterBufLen = 0;
|
|
DWORD dwCurrentFilterLen = 0;
|
|
LPTSTR pszFilter = NULL, pszTempFilter = NULL;
|
|
|
|
*ppszFilter = NULL;
|
|
|
|
if(!(V_VT(&var) == (VT_VARIANT|VT_ARRAY))) {
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
//
|
|
// Check that there is only one dimension in this array
|
|
//
|
|
|
|
if ((V_ARRAY(&var))->cDims != 1) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
//
|
|
// Check that there is at least one element in this array
|
|
//
|
|
|
|
if ((V_ARRAY(&var))->rgsabound[0].cElements == 0){
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// We know that this is a valid single dimension array
|
|
//
|
|
|
|
hr = SafeArrayGetLBound(V_ARRAY(&var),
|
|
1,
|
|
(long FAR *)&dwSLBound
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = SafeArrayGetUBound(V_ARRAY(&var),
|
|
1,
|
|
(long FAR *)&dwSUBound
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwCurrentFilterLen = 0;
|
|
dwFilterBufLen = FILTER_BUFFER_LEN;
|
|
|
|
pszFilter = (LPTSTR) AllocADsMem( (dwFilterBufLen + 1) * sizeof(WCHAR));
|
|
if ( pszFilter == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
for (i = dwSLBound; i <= dwSUBound; i++) {
|
|
|
|
VariantInit(&v);
|
|
hr = SafeArrayGetElement(V_ARRAY(&var),
|
|
(long FAR *)&i,
|
|
&v
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// The last length below is the string length of
|
|
// "(| (objectClass=))" which is 18.
|
|
//
|
|
|
|
while ( dwCurrentFilterLen + _tcslen(V_BSTR(&v)) + 18 > dwFilterBufLen)
|
|
{
|
|
pszTempFilter = (LPTSTR) ReallocADsMem(
|
|
pszFilter,
|
|
(dwFilterBufLen + 1) * sizeof(WCHAR),
|
|
(dwFilterBufLen*2 + 1) * sizeof(WCHAR));
|
|
if ( pszTempFilter == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
pszFilter = pszTempFilter;
|
|
dwFilterBufLen *= 2;
|
|
}
|
|
|
|
if ( i == dwSUBound )
|
|
{
|
|
_tcscat( pszFilter, TEXT("(objectClass="));
|
|
}
|
|
else
|
|
{
|
|
dwBracketCount++;
|
|
_tcscat( pszFilter, TEXT("(| (objectClass="));
|
|
}
|
|
|
|
_tcscat( pszFilter, V_BSTR(&v));
|
|
_tcscat( pszFilter, TEXT(")"));
|
|
dwCurrentFilterLen = _tcslen(pszFilter);
|
|
|
|
VariantClear(&v);
|
|
}
|
|
|
|
for ( i = 0; i < dwBracketCount; i++ )
|
|
_tcscat( pszFilter, TEXT(")"));
|
|
|
|
*ppszFilter = pszFilter;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
VariantClear(&v);
|
|
|
|
if ( pszFilter != NULL)
|
|
FreeADsMem( pszFilter );
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|