Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

284 lines
6.2 KiB

//////////////////////////////////////////////////////////////////////////////
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
SortedSdoCollection.cpp
Abstract:
Implements the get__NewSortedEnum function.
Given an ISdoCollection interface pointer and a property ID, this function
gives back an IEnumVARIANT interface which can be used to iterate through
the Sdo's in a sorted order.
Include directly in file where needed.
Author:
Michael A. Maguire 05/19/98
Revision History:
mmaguire 05/19/98 - created
sbens 05/27/98 - Always return an enumerator even if the collection does
not need to be sorted.
--*/
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// BEGIN INCLUDES
//
#include <ias.h>
#include <sdoias.h>
#include <vector>
#include <algorithm>
#include <SortedSdoCollection.h>
//
// END INCLUDES
//////////////////////////////////////////////////////////////////////////////
// VC smart pointer typedefs.
_COM_SMARTPTR_TYPEDEF(ISdo, __uuidof(ISdo));
_COM_SMARTPTR_TYPEDEF(ISdoCollection, __uuidof(ISdoCollection));
//////////////////////////////////////////////////////////////////////////////
// Functor needed for sort routine used below
//////////////////////////////////////////////////////////////////////////////
class MySort
{
public:
MySort(LONG propertyID)
: m_lpropertyID(propertyID) { }
bool operator()(const _variant_t& x, const _variant_t& y) const throw ()
{
bool bReturnValue = FALSE;
IDispatch * pDispatchX = NULL;
IDispatch * pDispatchY = NULL;
_variant_t varSequenceX;
_variant_t varSequenceY;
HRESULT hr;
try
{
// Remember that we must free these.
pDispatchX = (IDispatch *) (x);
pDispatchY = (IDispatch *) (y);
ISdoPtr spSdoX(pDispatchX);
if( spSdoX == NULL )
throw FALSE;
ISdoPtr spSdoY(pDispatchY);
if( spSdoY == NULL )
throw FALSE;
hr = spSdoX->GetProperty( m_lpropertyID, &varSequenceX );
if( FAILED(hr ) )
throw FALSE;
hr = spSdoY->GetProperty( m_lpropertyID, &varSequenceY );
if( FAILED(hr ) )
throw FALSE;
long lValX = (long) (varSequenceX);
long lValY = (long) (varSequenceY);
bReturnValue = (lValX < lValY);
}
catch(...)
{
// Catch all exceptions -- we'll just return FALSE.
;
}
if( NULL != pDispatchX )
{
pDispatchX->Release();
}
if( NULL != pDispatchY )
{
pDispatchY->Release();
}
return bReturnValue;
}
private:
LONG m_lpropertyID;
};
/////////////////////////////////////////////////////////////////////////////
// get__NewSortedEnum() - Get the SDO collection item enumerator
/////////////////////////////////////////////////////////////////////////////
HRESULT get__NewSortedEnum( ISdoCollection *pSdoCollection, IUnknown** pVal, LONG lPropertyID )
{
HRESULT hr = S_OK;
// Don't know why get__Count takes a long but Next takes unsigned long.
long lCount;
unsigned long ulCountReceived;
//
// Check function preconditions
//
_ASSERT ( NULL != pSdoCollection );
if( pSdoCollection == NULL )
return E_POINTER;
_ASSERT ( NULL != pVal );
if (pVal == NULL)
return E_POINTER;
//
// Get the underlying collection.
//
ISdoCollectionPtr spSdoCollection = pSdoCollection;
//
// We check the count of items in our collection and don't bother sorting the
// enumerator if the count is zero.
// This saves time and also helps us to a void a bug in the the enumerator which
// causes it to fail if we call next when it is empty.
//
spSdoCollection->get_Count( & lCount );
if( lCount <= 1 )
{
// No point in sorting.
return spSdoCollection->get__NewEnum(pVal);
}
std::vector< _variant_t > vaObjects;
//
// Load values from the items from ISdoCollection into our local container item.
//
CComPtr< IUnknown > spUnknown;
hr = spSdoCollection->get__NewEnum( (IUnknown **) & spUnknown );
if( FAILED( hr ) || spUnknown == NULL )
{
return E_FAIL;
}
CComQIPtr<IEnumVARIANT, &IID_IEnumVARIANT> spEnumVariant(spUnknown);
spUnknown.Release();
if( spEnumVariant == NULL )
{
return E_FAIL;
}
CComVariant spVariant;
// Get the first item.
hr = spEnumVariant->Next( 1, & spVariant, &ulCountReceived );
while( SUCCEEDED( hr ) && ulCountReceived == 1 )
{
vaObjects.push_back( spVariant );
// Clear the variant of whatever it had --
// this will release any data associated with it.
//ISSUE: Need to make sure that each item we copy here is being AddRef'ed.
// Check that copy into _variant_t is causing AddRef.
spVariant.Clear();
// Get the next item.
hr = spEnumVariant->Next( 1, & spVariant, &ulCountReceived );
}
//
// Now that we have the objects in our STL vector of variant's,
// let's sort them.
//
std::sort( vaObjects.begin(), vaObjects.end(), MySort(lPropertyID) );
//
// Use ATL implementation of IEnumVARIANT
//
typedef CComEnum< IEnumVARIANT,
&__uuidof(IEnumVARIANT),
VARIANT,
_Copy<VARIANT>,
CComSingleThreadModel
> EnumVARIANT;
EnumVARIANT* newEnum = new (std::nothrow) CComObject<EnumVARIANT>;
if (newEnum == NULL)
{
// ISSUE: Check that cleanup code for vector calls cleanup code for
// _variant_t which should automatically call release on IDispatch pointers.
return E_OUTOFMEMORY;
}
//
// The AtlFlagCopy below should ensure that a new copy of the vector is made
// which will persist in the enumerator once we've left this routine.
//
hr = newEnum->Init(
vaObjects.begin(),
vaObjects.end(),
NULL,
AtlFlagCopy
);
//
// Hand out the enumerator to our consumer.
//
if (SUCCEEDED(hr))
{
// Enumerator object will be destroyed when the caller releases it.
(*pVal = newEnum)->AddRef();
// LEAVE!
return S_OK;
}
//
// ISSUE: Check that cleanup code for vector calls cleanup code for
// _variant_t which should automatically call release on IDispatch pointers.
//
delete newEnum;
return hr;
}