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.
1298 lines
39 KiB
1298 lines
39 KiB
|
|
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
WMIMERGER.CPP
|
|
|
|
Abstract:
|
|
|
|
Implements the _IWmiMerger interface
|
|
|
|
History:
|
|
|
|
sanjes 16-Nov-00 Created.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#pragma warning (disable : 4786)
|
|
#include <wbemcore.h>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <genutils.h>
|
|
#include <oahelp.inl>
|
|
#include <wqllex.h>
|
|
#include "wmimerger.h"
|
|
#include <scopeguard.h>
|
|
static long g_lNumMergers = 0L;
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
CWmiMerger::CWmiMerger( CWbemNamespace* pNameSpace )
|
|
: m_lRefCount( 0 ),
|
|
m_pTargetSink( NULL ),
|
|
m_pTask( NULL ),
|
|
m_pNamespace( pNameSpace ),
|
|
m_wsTargetClassName(),
|
|
m_dwProviderDeliveryPing( 0L ),
|
|
m_pArbitrator( NULL ),
|
|
m_lNumArbThrottled( 0L ),
|
|
m_lDebugMemUsed( 0L ),
|
|
m_hOperationRes( WBEM_S_NO_ERROR ),
|
|
m_cs(),
|
|
m_dwMaxLevel( 0 ),
|
|
m_pRequestMgr( NULL ),
|
|
m_dwMinReqLevel( 0xFFFFFFFF ),
|
|
m_bMergerThrottlingEnabled( true )
|
|
{
|
|
if ( NULL != m_pNamespace )
|
|
{
|
|
m_pNamespace->AddRef();
|
|
}
|
|
|
|
InterlockedIncrement( &g_lNumMergers );
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWmiMerger::~CWmiMerger
|
|
//
|
|
// Notifies the ESS of namespace closure and frees up all the class providers.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CWmiMerger::~CWmiMerger()
|
|
{
|
|
_DBG_ASSERT( 0L == m_lNumArbThrottled );
|
|
_DBG_ASSERT( 0L == m_lDebugMemUsed );
|
|
|
|
if ( NULL != m_pNamespace )
|
|
{
|
|
m_pNamespace->Release();
|
|
}
|
|
|
|
if ( NULL != m_pArbitrator )
|
|
{
|
|
m_pArbitrator->Release();
|
|
}
|
|
|
|
if ( NULL != m_pTask )
|
|
{
|
|
m_pTask->Release();
|
|
}
|
|
|
|
if ( NULL != m_pRequestMgr )
|
|
{
|
|
delete m_pRequestMgr;
|
|
m_pRequestMgr = NULL;
|
|
}
|
|
|
|
InterlockedDecrement( &g_lNumMergers );
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWmiMerger::QueryInterface
|
|
//
|
|
// Exports _IWmiMerger interface.
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CWmiMerger::QueryInterface(
|
|
IN REFIID riid,
|
|
OUT LPVOID *ppvObj
|
|
)
|
|
{
|
|
if ( riid == IID__IWmiArbitratee )
|
|
{
|
|
*ppvObj = (_IWmiArbitratee*) this;
|
|
}
|
|
else if ( riid == IID__IWmiArbitratedQuery )
|
|
{
|
|
*ppvObj = (_IWmiArbitratedQuery*) this;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
|
|
ULONG CWmiMerger::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRefCount);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
ULONG CWmiMerger::Release()
|
|
{
|
|
long lNewCount = InterlockedDecrement(&m_lRefCount);
|
|
if (0 != lNewCount)
|
|
return lNewCount;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// Sets initial parameters for merger. Establishes the target class and sink for the
|
|
// query associated with the merger
|
|
STDMETHODIMP CWmiMerger::Initialize( _IWmiArbitrator* pArbitrator, _IWmiCoreHandle* pTask, LPCWSTR pwszTargetClass,
|
|
IWbemObjectSink* pTargetSink, CMergerSink** ppFinalSink )
|
|
{
|
|
if ( NULL == pwszTargetClass || NULL == pTargetSink )
|
|
{
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Cannot initialize twice
|
|
if ( NULL != m_pTargetSink )
|
|
{
|
|
return WBEM_E_INVALID_OPERATION;
|
|
}
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
try
|
|
{
|
|
m_wsTargetClassName = pwszTargetClass; // throws
|
|
|
|
// Create the final target sink
|
|
hr = CreateMergingSink( eMergerFinalSink, pTargetSink,
|
|
NULL, (CMergerSink**) &m_pTargetSink );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
*ppFinalSink = m_pTargetSink;
|
|
m_pTargetSink->AddRef();
|
|
|
|
m_pArbitrator = pArbitrator;
|
|
m_pArbitrator->AddRef();
|
|
|
|
// AddRef the Task here
|
|
m_pTask = pTask;
|
|
|
|
// Only register for arbitration if we have a task handle
|
|
if ( NULL != pTask )
|
|
{
|
|
m_pTask->AddRef();
|
|
hr = m_pArbitrator->RegisterArbitratee( 0L, m_pTask, this );
|
|
}
|
|
|
|
}
|
|
}
|
|
catch ( CX_Exception & )
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// Called to request a delivery sink for a class in the query chain. The returned
|
|
// sink is determined by the specified flags as well as settings on the parent class
|
|
STDMETHODIMP CWmiMerger::RegisterSinkForClass( LPCWSTR pwszClass, _IWmiObject* pClass,
|
|
IWbemContext* pContext,
|
|
BOOL fHasChildren, BOOL fHasInstances,
|
|
BOOL fDerivedFromTarget,
|
|
bool bStatic, CMergerSink* pDestSink,
|
|
CMergerSink** ppOwnSink, CMergerSink** ppChildSink )
|
|
{
|
|
try
|
|
{
|
|
LPCWSTR pwszParentClass = NULL;
|
|
|
|
DWORD dwSize = NULL;
|
|
BOOL fIsNull = NULL;
|
|
|
|
// Get the derivation information. The number of antecedents determines our
|
|
// level in the hierarchy (we're 0 based)
|
|
HRESULT hr;
|
|
DWORD dwLevel = 0L;
|
|
_variant_t vSuperClass;
|
|
|
|
hr = GetLevelAndSuperClass( pClass, &dwLevel, vSuperClass );
|
|
if (FAILED(hr)) return hr;
|
|
|
|
BSTR wsSuperClass = V_BSTR(&vSuperClass); // it can be NULL if no SuperClass
|
|
|
|
CCheckedInCritSec ics( &m_cs );
|
|
|
|
// We're dead - take no positive adjustments
|
|
if (FAILED (m_hOperationRes)) return m_hOperationRes;
|
|
|
|
wmilib::auto_ptr<CWmiMergerRecord> pRecord;
|
|
pRecord.reset(new CWmiMergerRecord( this, fHasInstances, fHasChildren,
|
|
pwszClass, pDestSink, dwLevel, bStatic )); // throw
|
|
|
|
if ( NULL == pRecord.get() ) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// Now attach aninternal merger if we have both instances and children
|
|
if ( fHasInstances && fHasChildren )
|
|
{
|
|
// We shouldn't have a NULL task here if this is not a static class.
|
|
// Note that the only case this appears to happen is when ESS calls
|
|
// into us on internal APIs and uses requests on its own queues and
|
|
// not the main Core Queue.
|
|
|
|
_DBG_ASSERT( NULL != m_pTask || ( NULL == m_pTask && bStatic ) );
|
|
// throws
|
|
hr = pRecord->AttachInternalMerger( (CWbemClass*) pClass, m_pNamespace, pContext, fDerivedFromTarget, bStatic );
|
|
}
|
|
|
|
// Check that we're still okay
|
|
if (FAILED(hr)) return hr;
|
|
|
|
|
|
// Find the record for the superclass if there is one (unless the array is
|
|
// empty of course).
|
|
if ( wsSuperClass && wsSuperClass[0] && m_MergerRecord.GetSize() > 0 )
|
|
{
|
|
// There MUST be a record, or something is quite not okay.
|
|
CWmiMergerRecord* pSuperClassRecord = m_MergerRecord.Find( wsSuperClass );
|
|
|
|
_DBG_ASSERT( NULL != pSuperClassRecord );
|
|
|
|
// Now add the new record to the child array for the superclass record
|
|
// This will allow us to quickly determine the classes we need to obtain
|
|
// submit requests for if the parent class is throttled.
|
|
|
|
if ( NULL == pSuperClassRecord ) return WBEM_E_FAILED;
|
|
|
|
hr = pSuperClassRecord->AddChild(pRecord.get());
|
|
}
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
// Make sure the add is successful
|
|
if ( m_MergerRecord.Insert( pRecord.get() ) < 0 ) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
// Verify the sort order for now
|
|
m_MergerRecord.Verify();
|
|
#endif
|
|
|
|
|
|
*ppOwnSink = pRecord->GetOwnSink();
|
|
*ppChildSink = pRecord->GetChildSink();
|
|
pRecord.release(); // array took ownership
|
|
|
|
// Store the maximum level in the hierarchy
|
|
if ( dwLevel > m_dwMaxLevel )
|
|
{
|
|
m_dwMaxLevel = dwLevel;
|
|
}
|
|
|
|
if ( !bStatic && dwLevel < m_dwMinReqLevel )
|
|
{
|
|
m_dwMinReqLevel = dwLevel;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
catch(CX_Exception & )
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// Called to request a delivery sink for child classes in the query chain. This is especially
|
|
// important when instances are merged under the covers.
|
|
STDMETHODIMP CWmiMerger::GetChildSink( LPCWSTR pwszClass, CBasicObjectSink** ppSink )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
// Search for a parent class's child sink
|
|
for ( int x = 0; SUCCEEDED( hr ) && x < m_MergerRecord.GetSize(); x++ )
|
|
{
|
|
if ( m_MergerRecord[x]->IsClass( pwszClass ) )
|
|
{
|
|
*ppSink = m_MergerRecord[x]->GetChildSink();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// We should never get a failure
|
|
_DBG_ASSERT( x < m_MergerRecord.GetSize() );
|
|
|
|
if ( x >= m_MergerRecord.GetSize() )
|
|
{
|
|
hr = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Can be used to hold off indicates - if we're merging instances from multiple providers, we need
|
|
// to ensure that we don't get lopsided in the number of objects we've got queued up for merging.
|
|
STDMETHODIMP CWmiMerger::Throttle( void )
|
|
{
|
|
// We're dead - take no positive adjustments
|
|
if ( FAILED ( m_hOperationRes ) )
|
|
{
|
|
return m_hOperationRes;
|
|
}
|
|
|
|
// Check for NULL m_pTask
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( NULL != m_pTask )
|
|
{
|
|
hr = m_pArbitrator->Throttle( 0L, m_pTask );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Merger will hold information regarding the total number of objects it has queued up waiting
|
|
// for merging and the amount of memory consumed by those objects.
|
|
STDMETHODIMP CWmiMerger::GetQueuedObjectInfo( DWORD* pdwNumQueuedObjects, DWORD* pdwQueuedObjectMemSize )
|
|
{
|
|
return WBEM_E_NOT_AVAILABLE;
|
|
}
|
|
|
|
// If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
|
|
// objects. This will also automatically free up resources consumed by queued objects.
|
|
STDMETHODIMP CWmiMerger::Cancel( void )
|
|
{
|
|
return Cancel( WBEM_E_CALL_CANCELLED );
|
|
}
|
|
|
|
// Helper function to control sink creation. The merger is responsible for deletion of
|
|
// all internally created sinks. So this function ensures that the sinks are added into
|
|
// the array that will destroy them.
|
|
HRESULT CWmiMerger::CreateMergingSink( MergerSinkType eType, IWbemObjectSink* pDestSink, CInternalMerger* pMerger, CMergerSink** ppSink )
|
|
{
|
|
|
|
|
|
if ( eType == eMergerFinalSink )
|
|
{
|
|
*ppSink = new CMergerTargetSink( this, pDestSink );
|
|
if ( NULL == *ppSink ) return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
HRESULT hr;
|
|
hr = CInternalMerger::CreateMergingSink( eType, pMerger, this, ppSink );
|
|
if (FAILED(hr)) return hr;
|
|
}
|
|
|
|
|
|
// If we have a sink, we should now add it to the
|
|
// Sink array, the MergerSinks array will do the operator delete call,
|
|
// but the objects will have a special callback on the last release
|
|
|
|
if ( m_MergerSinks.Add( *ppSink ) < 0 )
|
|
{
|
|
delete *ppSink;
|
|
*ppSink = NULL;
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
// Iterates the array of MergerRecords and cancels each of them.
|
|
HRESULT CWmiMerger::Cancel( HRESULT hRes )
|
|
{
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
DbgPrintfA(0,"CANCEL CALLED: Merger %p Cancelled with hRes: 0x%x on Thread 0x%x\n",this, hRes, GetCurrentThreadId() );
|
|
#endif
|
|
|
|
// We shouldn't be called with a success code
|
|
_DBG_ASSERT( FAILED( hRes ) );
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// If we're here and this is non-NULL, tell the Arbitrator to tank us.
|
|
if ( NULL != m_pTask )
|
|
{
|
|
m_pArbitrator->CancelTask( 0L, m_pTask );
|
|
}
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
if ( WBEM_S_NO_ERROR == m_hOperationRes ) // if it is the first time
|
|
{
|
|
m_hOperationRes = hRes;
|
|
}
|
|
|
|
// Search for a parent class's child sink
|
|
for ( int x = 0; SUCCEEDED( hr ) && x < m_MergerRecord.GetSize(); x++ )
|
|
{
|
|
m_MergerRecord[x]->Cancel( hRes );
|
|
}
|
|
|
|
// Copy into a temporary variable, clear the member, exit the critsec
|
|
// THEN call delete. Requests can have multiple releases, which could call
|
|
// back in here and cause all sorts of problems if we're inside a critsec.
|
|
CWmiMergerRequestMgr* pReqMgr = m_pRequestMgr;
|
|
m_pRequestMgr = NULL;
|
|
|
|
ics.Leave();
|
|
|
|
// Tank any and all outstanding requests
|
|
if ( NULL != pReqMgr )
|
|
{
|
|
delete pReqMgr;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Final Shutdown. Called when the target sink is released. At this point, we should
|
|
// unregister ourselves from the world
|
|
HRESULT CWmiMerger::Shutdown( void )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
_IWmiCoreHandle* pTask = m_pTask;
|
|
|
|
// Done with this, NULL it out - we release and unregister outside the critical section
|
|
if ( NULL != m_pTask )
|
|
{
|
|
m_pTask = NULL;
|
|
}
|
|
|
|
ics.Leave();
|
|
|
|
if ( NULL != pTask )
|
|
{
|
|
hr = m_pArbitrator->UnRegisterArbitratee( 0L, pTask, this );
|
|
pTask->Release();
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Pas-thru to arbitrator
|
|
HRESULT CWmiMerger::ReportMemoryUsage( long lAdjustment )
|
|
{
|
|
// Task can be NULL
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( NULL != m_pTask )
|
|
{
|
|
hr = m_pArbitrator->ReportMemoryUsage( 0L, lAdjustment, m_pTask );
|
|
}
|
|
|
|
// SUCCESS, WBEM_E_ARB_CANCEL or WBEM_E_ARB_THROTTLE means that we need to
|
|
// account for the memory
|
|
if ( ( SUCCEEDED( hr ) || hr == WBEM_E_ARB_CANCEL || hr == WBEM_E_ARB_THROTTLE ) )
|
|
{
|
|
InterlockedExchangeAdd( &m_lDebugMemUsed, lAdjustment );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* _IWmiArbitratee methods. */
|
|
|
|
STDMETHODIMP CWmiMerger::SetOperationResult( ULONG uFlags, HRESULT hRes )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( FAILED( hRes ) )
|
|
{
|
|
hr = Cancel( hRes );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Why are we here?
|
|
STDMETHODIMP CWmiMerger::SetTaskHandle( _IWmiCoreHandle* pTask )
|
|
{
|
|
_DBG_ASSERT( 0 );
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Noop for now
|
|
STDMETHODIMP CWmiMerger::DumpDebugInfo( ULONG uFlags, const BSTR strFile )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Returns SUCCESS for now
|
|
STDMETHODIMP CWmiMerger::IsMerger( void )
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CWmiMerger::GetLevelAndSuperClass( _IWmiObject* pObj, DWORD* pdwLevel,
|
|
_variant_t & vSuperClass )
|
|
{
|
|
// Get the derivation information. The number of antecedents determines our
|
|
// level in the hierarchy (we're 0 based)
|
|
DWORD dwTemp = 0L;
|
|
|
|
HRESULT hr = pObj->GetDerivation( 0L, 0L, pdwLevel, &dwTemp, NULL );
|
|
|
|
if ( FAILED( hr ) && WBEM_E_BUFFER_TOO_SMALL != hr )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pObj->Get( L"__SUPERCLASS", 0L, &vSuperClass, NULL, NULL );
|
|
|
|
if ( SUCCEEDED( hr ))
|
|
{
|
|
if ( VT_BSTR == V_VT(&vSuperClass)) return S_OK;
|
|
if ( VT_NULL == V_VT(&vSuperClass)) { V_BSTR(&vSuperClass) = NULL; return S_OK; };
|
|
throw CX_Exception();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWmiMerger::RegisterArbitratedInstRequest( CWbemObject* pClassDef, long lFlags,
|
|
IWbemContext* pCtx,
|
|
CBasicObjectSink* pSink,
|
|
BOOL bComplexQuery,
|
|
CWbemNamespace* pNs )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Allocate a new request then place it in the arbitrator.
|
|
try
|
|
{
|
|
wmilib::auto_ptr<CMergerDynReq_DynAux_GetInstances> pReq;
|
|
pReq.reset(new CMergerDynReq_DynAux_GetInstances(pNs, pClassDef,
|
|
lFlags, pCtx, pSink));
|
|
|
|
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// Make sure a context exists under the cover
|
|
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
if (FAILED(m_hOperationRes)) return m_hOperationRes;
|
|
|
|
// Allocate a request manager if we need one
|
|
if ( NULL == m_pRequestMgr )
|
|
{
|
|
m_pRequestMgr = new CWmiMergerRequestMgr(this);
|
|
if (NULL == m_pRequestMgr) return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// We need the record to find out what level we need to add
|
|
// the request to
|
|
CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
|
|
_DBG_ASSERT( NULL != pRecord );
|
|
|
|
if ( NULL == pRecord ) return WBEM_E_FAILED;
|
|
|
|
// Set the task for the request - we'll just use the existing one
|
|
m_pTask->AddRef();
|
|
pReq->m_phTask = m_pTask;
|
|
|
|
hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
|
|
// Cleanup the request if anything went wrong
|
|
if ( FAILED( hr ) ) return hr;
|
|
pReq.release();
|
|
|
|
}
|
|
catch(CX_Exception &)
|
|
{
|
|
ExceptionCounter c;
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CWmiMerger::RegisterArbitratedQueryRequest( CWbemObject* pClassDef, long lFlags,
|
|
LPCWSTR Query,LPCWSTR QueryFormat,
|
|
IWbemContext* pCtx,
|
|
CBasicObjectSink* pSink,
|
|
CWbemNamespace* pNs )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Allocate a new request then place it in the arbitrator.
|
|
try
|
|
{
|
|
wmilib::auto_ptr<CMergerDynReq_DynAux_ExecQueryAsync> pReq;
|
|
pReq.reset(new CMergerDynReq_DynAux_ExecQueryAsync(pNs, pClassDef, lFlags,
|
|
Query, QueryFormat,
|
|
pCtx, pSink ));
|
|
|
|
if (NULL == pReq.get()) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// Make sure a context was properly allocated
|
|
if (NULL == pReq->GetContext()) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// Make sure the request is functional
|
|
if (FAILED(hr = pReq->Initialize())) return hr;
|
|
|
|
|
|
CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
if (FAILED(m_hOperationRes)) return m_hOperationRes;
|
|
|
|
// Allocate a request manager if we need one
|
|
if ( NULL == m_pRequestMgr )
|
|
{
|
|
m_pRequestMgr = new CWmiMergerRequestMgr( this );
|
|
if ( NULL == m_pRequestMgr ) return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// We need the record to find out what level we need to add
|
|
// the request to
|
|
CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
|
|
_DBG_ASSERT( NULL != pRecord );
|
|
// Couldn't find the record
|
|
if ( NULL == pRecord ) return WBEM_E_FAILED;
|
|
|
|
// Set the task for the request - we'll just use the existing one
|
|
m_pTask->AddRef();
|
|
pReq->m_phTask = m_pTask;
|
|
|
|
hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
|
|
if (FAILED(hr)) return hr;
|
|
pReq.release();
|
|
}
|
|
catch(CX_Exception &)
|
|
{
|
|
ExceptionCounter c;
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWmiMerger::RegisterArbitratedStaticRequest( CWbemObject* pClassDef, long lFlags,
|
|
IWbemContext* pCtx, CBasicObjectSink* pSink, CWbemNamespace* pNs,
|
|
QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// Allocate a new request then place it in the arbitrator.
|
|
try
|
|
{
|
|
wmilib::auto_ptr<CMergerDynReq_Static_GetInstances> pReq;
|
|
pReq.reset(new CMergerDynReq_Static_GetInstances(
|
|
pNs, pClassDef, lFlags, pCtx, pSink,
|
|
pParsedQuery ));
|
|
if ( NULL == pReq.get() ) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// Make sure a context was properly allocated
|
|
if ( NULL == pReq->GetContext() ) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
if ( FAILED( m_hOperationRes ) ) return m_hOperationRes;
|
|
|
|
// Allocate a request manager if we need one
|
|
if ( NULL == m_pRequestMgr )
|
|
{
|
|
m_pRequestMgr = new CWmiMergerRequestMgr( this );
|
|
if ( NULL == m_pRequestMgr ) return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// We need the record to find out what level we need to add
|
|
// the request to
|
|
CWmiMergerRecord* pRecord = m_MergerRecord.Find( pReq->GetName() );
|
|
_DBG_ASSERT( NULL != pRecord );
|
|
|
|
// Couldn't find the record
|
|
if ( NULL == pRecord ) return WBEM_E_FAILED;
|
|
|
|
// Set the task for the request - we'll just use the existing one
|
|
m_pTask->AddRef();
|
|
pReq->m_phTask = m_pTask;
|
|
|
|
hr = m_pRequestMgr->AddRequest( pReq.get(), pRecord->GetLevel() );
|
|
if (FAILED(hr)) return hr;
|
|
pReq.release();
|
|
|
|
}
|
|
catch(CX_Exception &)
|
|
{
|
|
ExceptionCounter c;
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Executes the parent request. In this case, we simply ask the request manager for the
|
|
// next top level request and execute that request. We do this in a loop until something
|
|
// goes wrong.
|
|
//
|
|
|
|
|
|
HRESULT CWmiMerger::Exec_MergerParentRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
IWbemClassObject * pErr = NULL;
|
|
CSetStatusOnMe setOnMe(pSink,hr,pErr);
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
// While we have requests to execute, we should get each next logical one
|
|
while ( SUCCEEDED(hr ) && NULL != m_pRequestMgr && m_pRequestMgr->GetNumRequests() > 0 )
|
|
{
|
|
if ( FAILED( m_hOperationRes ) ) { hr = m_hOperationRes; break; }
|
|
|
|
// Obtain the next topmost parent record if we have to
|
|
if ( NULL == pParentRecord )
|
|
{
|
|
WString wsClassName; // throw
|
|
hr = m_pRequestMgr->GetTopmostParentReqName( wsClassName );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
pParentRecord = m_MergerRecord.Find( wsClassName );
|
|
|
|
// If there's a request, there better be a record
|
|
_DBG_ASSERT( NULL != pParentRecord );
|
|
|
|
if ( NULL == pParentRecord )
|
|
{
|
|
hr = WBEM_E_FAILED;
|
|
}
|
|
|
|
} // IF Got Topmost Parent Request
|
|
|
|
} // IF NULL == pParentRecord
|
|
|
|
if ( FAILED( hr ) ) break;
|
|
|
|
// This will remove the request from its array and return it
|
|
// to us - we need to delete it
|
|
wmilib::auto_ptr<CMergerReq> pReq;
|
|
hr = m_pRequestMgr->RemoveRequest( pParentRecord->GetLevel(),
|
|
pParentRecord->GetName(), pReq );
|
|
if (FAILED(hr)) break;
|
|
|
|
hr = pParentRecord->SetExecutionContext( pReq->GetContext() );
|
|
if (FAILED(hr)) break;
|
|
|
|
|
|
// Clearly, we should do this outside the critsec
|
|
ics.Leave();
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
DbgPrintfA(0,"BEGIN: Merger 0x%x querying instances of parent class: %S, Level %d on Thread 0x%x\n", (DWORD_PTR) this, pParentRecord->GetName(), pParentRecord->GetLevel(), GetCurrentThreadId() );
|
|
#endif
|
|
|
|
// This will delete the request when it is done with it
|
|
hr = CCoreQueue::ExecSubRequest( pReq.get() );
|
|
|
|
if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
DbgPrintfA(0,"END: Merger 0x%x querying instances of parent class: %S, Level %d on Thread 0x%x\n", (DWORD_PTR) this, pParentRecord->GetName(), pParentRecord->GetLevel(), GetCurrentThreadId() );// SEC:REVIEWED 2002-03-22 : OK
|
|
#endif
|
|
|
|
ics.Enter();
|
|
|
|
// We're done with this record, so we need to get the next top level
|
|
// record.
|
|
pParentRecord = NULL;
|
|
}
|
|
// SetStatus called by the guard
|
|
return hr;
|
|
}
|
|
|
|
void CWmiMerger::CleanChildRequests(CWmiMergerRecord* pParentRecord, int cleanFrom)
|
|
{
|
|
CCheckedInCritSec ics(&m_cs);
|
|
|
|
if (NULL == m_pRequestMgr) return;
|
|
// we want to see if there are un-executed requests laying around
|
|
|
|
int localClean = cleanFrom;
|
|
while(true)
|
|
{
|
|
CWmiMergerRecord* pChildRecord = pParentRecord->GetChildRecord( localClean++ );
|
|
if ( NULL == pChildRecord ){ break; }
|
|
|
|
// This will remove the request from its array and return it
|
|
// to us - we need to delete it
|
|
wmilib::auto_ptr<CMergerReq> pReq;
|
|
m_pRequestMgr->RemoveRequest( pChildRecord->GetLevel(),
|
|
pChildRecord->GetName(), pReq );
|
|
if (pReq.get() != 0)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE,"deleting un-executed requests for class %S\n",pReq->GetName()));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Executes the child request. In this case, we enumerate the child classes of the parent
|
|
// record, and execute the corresponding requests. We do so in a loop until we either
|
|
// finish or something goes wrong.
|
|
//
|
|
|
|
HRESULT CWmiMerger::Exec_MergerChildRequest( CWmiMergerRecord* pParentRecord,
|
|
CBasicObjectSink* pSink )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
IWbemClassObject * pErr = NULL;
|
|
CSetStatusOnMe setOnMe(pSink,hr,pErr);
|
|
int cleanFrom = 0;
|
|
ScopeGuard CleanChildReq = MakeObjGuard(*this, CWmiMerger::CleanChildRequests, pParentRecord, ByRef(cleanFrom));
|
|
bool bLast = false;
|
|
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
// While we have child requests to execute, we should get each one
|
|
for (int x = 0; SUCCEEDED( hr ) && NULL != m_pRequestMgr && !bLast; x++ )
|
|
{
|
|
// m_pRequestMgr will be NULL if we were cancelled, in which
|
|
// case m_hOperationRes will be a failure
|
|
if (FAILED(m_hOperationRes)){ hr = m_hOperationRes; break; };
|
|
|
|
CWmiMergerRecord* pChildRecord = pParentRecord->GetChildRecord( x );
|
|
if ( NULL == pChildRecord ){ bLast = true; break; }
|
|
|
|
// This will remove the request from its array and return it
|
|
// to us - we need to delete it
|
|
wmilib::auto_ptr<CMergerReq> pReq;
|
|
|
|
hr = m_pRequestMgr->RemoveRequest( pChildRecord->GetLevel(),
|
|
pChildRecord->GetName(), pReq );
|
|
|
|
if ( WBEM_E_NOT_FOUND == hr )
|
|
{
|
|
// If we don't find the request we're looking for, another thread
|
|
// already processed it. We should, however, still look for child
|
|
// requests to process before we go away.
|
|
hr = WBEM_S_NO_ERROR;
|
|
continue;
|
|
}
|
|
cleanFrom = x+1;
|
|
|
|
if ( FAILED( hr ) ) break;
|
|
|
|
hr = pChildRecord->SetExecutionContext(pReq->GetContext());
|
|
if (FAILED(hr)) break;
|
|
|
|
// Clearly, we should do this outside the critsec
|
|
ics.Leave();
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
DbgPrintfA(0,"BEGIN: Merger 0x%x querying instances of child class: %S, Level %d for parent class: %S on Thread 0x%x\n", (DWORD_PTR) this, pChildRecord->GetName(), pChildRecord->GetLevel(), pParentRecord->GetName(), GetCurrentThreadId() );
|
|
#endif
|
|
|
|
// This will delete the request when it is done with it
|
|
hr = CCoreQueue::ExecSubRequest( pReq.get() );
|
|
if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
DbgPrintfA(0,"END: Merger 0x%x querying instances of child class: %S, Level %d for parent class: %S on Thread 0x%x\n", (DWORD_PTR) this, pChildRecord->GetName(), pChildRecord->GetLevel(), pParentRecord->GetName(), GetCurrentThreadId() );
|
|
#endif
|
|
|
|
ics.Enter();
|
|
} // FOR enum child requests
|
|
|
|
// SetStatus invoked by the guard
|
|
return hr;
|
|
}
|
|
|
|
// Schedules the parent class request
|
|
HRESULT CWmiMerger::ScheduleMergerParentRequest( IWbemContext* pCtx )
|
|
{
|
|
// Check if query arbitration is enabled
|
|
if ( !ConfigMgr::GetEnableQueryArbitration() )
|
|
{
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
do
|
|
{
|
|
|
|
if (FAILED( m_hOperationRes )){ hr = m_hOperationRes; break; }
|
|
|
|
if ( NULL == m_pRequestMgr )
|
|
{
|
|
break; // The request manager will be non-NULL
|
|
// only if we had to add a request.
|
|
}
|
|
|
|
|
|
#ifdef __DEBUG_MERGER_THROTTLING
|
|
m_pRequestMgr->DumpRequestHierarchy();
|
|
#endif
|
|
|
|
// Make sure we've got at least one request
|
|
if ( 0 == m_pRequestMgr->GetNumRequests() ) break;
|
|
|
|
// If there isn't a task, we've got a BIG problem.
|
|
_DBG_ASSERT( NULL != m_pTask );
|
|
if ( NULL == m_pTask )
|
|
{
|
|
hr = WBEM_E_FAILED; break;
|
|
}
|
|
|
|
// If we have a single static request in the merger, we'll
|
|
// execute it now. Otherwise, we'll do normal processing.
|
|
// Note that we *could* theoretically do this for single
|
|
// dynamic requests as well
|
|
if ( IsSingleStaticRequest() )
|
|
{
|
|
// We MUST leave the critical section here, since the parent request
|
|
// could get cancelled or we may end up sleeping and we don't want
|
|
// to own the critical section in that time.
|
|
ics.Leave();
|
|
hr = Exec_MergerParentRequest( NULL, m_pTargetSink );
|
|
}
|
|
else
|
|
{
|
|
// If we've never retrieved the number of processors, do so
|
|
// now.
|
|
static g_dwNumProcessors = 8L;
|
|
|
|
/*
|
|
if ( 0L == g_dwNumProcessors )
|
|
{
|
|
SYSTEM_INFO sysInfo;
|
|
ZeroMemory( &sysInfo, sizeof( sysInfo ) ); // SEC:REVIEWED 2002-03-22 : OK
|
|
GetSystemInfo( &sysInfo );
|
|
|
|
_DBG_ASSERT( sysInfo.dwNumberOfProcessors > 0L );
|
|
|
|
// Ensure we're always at least 1
|
|
g_dwNumProcessors = ( 0L == sysInfo.dwNumberOfProcessors ?
|
|
1L : sysInfo.dwNumberOfProcessors );
|
|
}
|
|
*/
|
|
|
|
// We will generate a number of parent requests based on the minimum
|
|
// of the number of requests and the number of actual processors.
|
|
|
|
DWORD dwNumToSchedule = min( m_pRequestMgr->GetNumRequests(), g_dwNumProcessors );
|
|
|
|
for ( DWORD dwCtr = 0L; SUCCEEDED( hr ) && dwCtr < dwNumToSchedule; dwCtr++ )
|
|
{
|
|
// Parent request will search for the next available request
|
|
wmilib::auto_ptr<CMergerParentReq> pReq;
|
|
pReq.reset(new CMergerParentReq(this,NULL,m_pNamespace,m_pTargetSink,pCtx));
|
|
|
|
if ( NULL == pReq.get() ) {
|
|
hr = WBEM_E_OUT_OF_MEMORY; break;
|
|
}
|
|
|
|
if ( NULL == pReq->GetContext() ){
|
|
hr = WBEM_E_OUT_OF_MEMORY; break;
|
|
}
|
|
|
|
// Set the task for the request - we'll just use the existing one
|
|
m_pTask->AddRef();
|
|
pReq->m_phTask = m_pTask;
|
|
|
|
// This may sleep, so exit the critsec before calling into this
|
|
ics.Leave();
|
|
|
|
hr = ConfigMgr::EnqueueRequest( pReq.get() );
|
|
if ( SUCCEEDED(hr) ) pReq.release(); // queue took ownership
|
|
|
|
// reenter the critsec
|
|
ics.Enter();
|
|
} // For schedule requests
|
|
|
|
} // IF !SingleStaticRequest
|
|
}while(0);
|
|
|
|
// If we have to cancel, do so OUTSIDE of the critsec
|
|
ics.Leave();
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
Cancel( hr );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Schedules a child class request
|
|
HRESULT CWmiMerger::ScheduleMergerChildRequest( CWmiMergerRecord* pParentRecord )
|
|
{
|
|
// Check if query arbitration is enabled
|
|
if (!ConfigMgr::GetEnableQueryArbitration()) return WBEM_S_NO_ERROR;
|
|
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// We must be in a success state and not have previously scheduled a child
|
|
// request.
|
|
|
|
do
|
|
{
|
|
if (FAILED(m_hOperationRes))
|
|
{
|
|
hr = m_hOperationRes; break;
|
|
}
|
|
if (pParentRecord->ScheduledChildRequest())
|
|
{
|
|
break; // if already scheduled, bail out, with success
|
|
}
|
|
|
|
// If there isn't a task, we've got a BIG problem.
|
|
_DBG_ASSERT( NULL != m_pTask );
|
|
if ( NULL == m_pTask )
|
|
{
|
|
hr = WBEM_E_FAILED; break;
|
|
}
|
|
|
|
wmilib::auto_ptr<CMergerChildReq> pReq;
|
|
pReq.reset(new CMergerChildReq (this,pParentRecord,
|
|
m_pNamespace,m_pTargetSink,
|
|
pParentRecord->GetExecutionContext()));
|
|
|
|
if (NULL == pReq.get())
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY; break;
|
|
}
|
|
if ( NULL == pReq->GetContext())
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY; break;
|
|
}
|
|
// Set the task for the request - we'll just use the existing one
|
|
m_pTask->AddRef();
|
|
pReq->m_phTask = m_pTask;
|
|
|
|
// This may sleep, so exit the critsec before calling into this
|
|
ics.Leave();
|
|
hr = ConfigMgr::EnqueueRequest( pReq.get() );
|
|
ics.Enter();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// We've basically scheduled one at this point
|
|
pParentRecord->SetScheduledChildRequest();
|
|
pReq.release();
|
|
}
|
|
}while(0);
|
|
|
|
// If we have to cancel, do so OUTSIDE of the critsec
|
|
ics.Leave();
|
|
|
|
if (FAILED(hr)) Cancel(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Returns whether or not we have a single static class request in the merger
|
|
// or not
|
|
BOOL CWmiMerger::IsSingleStaticRequest( void )
|
|
{
|
|
CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
|
|
|
|
BOOL fRet = FALSE;
|
|
|
|
if ( NULL != m_pRequestMgr )
|
|
{
|
|
// Ask if we've got a single request
|
|
fRet = m_pRequestMgr->HasSingleStaticRequest();
|
|
} // IF NULL != m_pRequestMgr
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// CWmiMergerRecord
|
|
//
|
|
// Support class for CWmiMerger - encapsulates sub-sink functionality for the CWmiMerger
|
|
// class. The merger calls the records which actually know whether or not they sit on
|
|
// top of sinks or actual mergers.
|
|
//
|
|
|
|
CWmiMergerRecord::CWmiMergerRecord( CWmiMerger* pMerger, BOOL fHasInstances,
|
|
BOOL fHasChildren, LPCWSTR pwszClass, CMergerSink* pDestSink, DWORD dwLevel,
|
|
bool bStatic )
|
|
: m_pMerger( pMerger ),
|
|
m_fHasInstances( fHasInstances ),
|
|
m_fHasChildren( fHasChildren ),
|
|
m_dwLevel( dwLevel ),
|
|
m_wsClass( pwszClass ), // throw
|
|
m_pDestSink( pDestSink ),
|
|
m_pInternalMerger( NULL ),
|
|
m_ChildArray(),
|
|
m_bScheduledChildRequest( false ),
|
|
m_pExecutionContext( NULL ),
|
|
m_bStatic( bStatic )
|
|
{
|
|
// No Addrefing internal sinks, since they really AddRef the entire merger
|
|
// and we don't want to create Circular Dependencies
|
|
}
|
|
|
|
CWmiMergerRecord::~CWmiMergerRecord()
|
|
{
|
|
if ( NULL != m_pInternalMerger )
|
|
{
|
|
delete m_pInternalMerger;
|
|
}
|
|
|
|
if ( NULL != m_pExecutionContext )
|
|
{
|
|
m_pExecutionContext->Release();
|
|
}
|
|
}
|
|
|
|
HRESULT CWmiMergerRecord::AttachInternalMerger( CWbemClass* pClass, CWbemNamespace* pNamespace,
|
|
IWbemContext* pCtx, BOOL fDerivedFromTarget,
|
|
bool bStatic )
|
|
{
|
|
if ( NULL != m_pInternalMerger )
|
|
{
|
|
return WBEM_E_INVALID_OPERATION;
|
|
}
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
// m_pDestSink is not addrefed by the MergerRecord
|
|
m_pInternalMerger = new CInternalMerger( this, m_pDestSink, pClass, pNamespace, pCtx );
|
|
|
|
if ( NULL == m_pInternalMerger ) return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
hr = m_pInternalMerger->Initialize();
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
delete m_pInternalMerger;
|
|
m_pInternalMerger = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_pInternalMerger->SetIsDerivedFromTarget( fDerivedFromTarget );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
CMergerSink* CWmiMergerRecord::GetChildSink( void )
|
|
{
|
|
CMergerSink* pSink = NULL;
|
|
|
|
if ( NULL != m_pInternalMerger )
|
|
{
|
|
pSink = m_pInternalMerger->GetChildSink();
|
|
}
|
|
else if ( m_fHasChildren )
|
|
{
|
|
m_pDestSink->AddRef(); // addref-it before giving-it out, but not ref for itself
|
|
pSink = m_pDestSink;
|
|
}
|
|
|
|
return pSink;
|
|
}
|
|
|
|
CMergerSink* CWmiMergerRecord::GetOwnSink( void )
|
|
{
|
|
CMergerSink* pSink = NULL;
|
|
|
|
if ( NULL != m_pInternalMerger )
|
|
{
|
|
pSink = m_pInternalMerger->GetOwnSink();
|
|
}
|
|
else if ( !m_fHasChildren )
|
|
{
|
|
m_pDestSink->AddRef();
|
|
pSink = m_pDestSink; // addref-it before giving-it out, but not ref for itself
|
|
}
|
|
|
|
return pSink;
|
|
}
|
|
|
|
CMergerSink* CWmiMergerRecord::GetDestSink( void )
|
|
{
|
|
if ( NULL != m_pDestSink )
|
|
{
|
|
m_pDestSink->AddRef();
|
|
}
|
|
// addref-it before giving-it out, but not ref for itself
|
|
CMergerSink* pSink = m_pDestSink;
|
|
|
|
return pSink;
|
|
}
|
|
|
|
void CWmiMergerRecord::Cancel( HRESULT hRes )
|
|
{
|
|
if ( NULL != m_pInternalMerger )
|
|
{
|
|
m_pInternalMerger->Cancel( hRes );
|
|
}
|
|
|
|
}
|
|
|
|
HRESULT CWmiMergerRecord::AddChild( CWmiMergerRecord* pRecord )
|
|
{
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
|
|
if ( m_ChildArray.Add( pRecord ) < 0 )
|
|
{
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
CWmiMergerRecord* CWmiMergerRecord::GetChildRecord( int nIndex )
|
|
{
|
|
// Check if the index is a valid record, then return it
|
|
if ( nIndex < m_ChildArray.GetSize() )
|
|
{
|
|
return m_ChildArray[nIndex];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT CWmiMergerRecord::SetExecutionContext( IWbemContext* pContext )
|
|
{
|
|
// We can only do this once
|
|
|
|
_DBG_ASSERT( NULL == m_pExecutionContext );
|
|
|
|
if ( NULL != m_pExecutionContext )
|
|
{
|
|
return WBEM_E_INVALID_OPERATION;
|
|
}
|
|
|
|
if (pContext)
|
|
{
|
|
pContext->AddRef();
|
|
m_pExecutionContext = pContext;
|
|
}
|
|
else
|
|
{
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|