326 lines
9.8 KiB
C++
326 lines
9.8 KiB
C++
/*++
|
||
|
||
Copyright (C) 1996-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
INTERNALMERGER.H
|
||
|
||
Abstract:
|
||
|
||
CInternalMerger class.
|
||
|
||
History:
|
||
|
||
30-Nov-00 sanjes Created.
|
||
|
||
--*/
|
||
|
||
#ifndef _INTERNALMERGER_H_
|
||
#define _INTERNALMERGER_H_
|
||
|
||
#include "mergerthrottling.h"
|
||
#include "wstlallc.h"
|
||
|
||
// Forward class definitions
|
||
class CWmiMergerRecord;
|
||
|
||
// Base class for merger sinks - all of these will be created by the
|
||
// merger and will AddRef() the merger. The merger class will be used
|
||
// to create the sinks. When the Merger is destroyed, it will delete
|
||
// all of the sink. Internal Merger objects MUST NOT AddRef these sinks
|
||
// so we don't create a circular dependency.
|
||
|
||
typedef enum
|
||
{
|
||
eMergerFinalSink,
|
||
eMergerOwnSink,
|
||
eMergerChildSink,
|
||
eMergerOwnInstanceSink
|
||
} MergerSinkType;
|
||
|
||
class CMergerSink : public CBasicObjectSink
|
||
{
|
||
protected:
|
||
CWmiMerger* m_pMerger;
|
||
long m_lRefCount;
|
||
|
||
virtual HRESULT OnFinalRelease( void ) = 0;
|
||
|
||
public:
|
||
CMergerSink( CWmiMerger* pMerger );
|
||
virtual ~CMergerSink();
|
||
|
||
/* IUnknown methods */
|
||
STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
|
||
STDMETHOD_(ULONG, AddRef)(THIS);
|
||
STDMETHOD_(ULONG, Release)(THIS);
|
||
|
||
virtual HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ) = 0L;
|
||
};
|
||
|
||
class CMergerTargetSink : public CMergerSink
|
||
{
|
||
protected:
|
||
IWbemObjectSink* m_pDest;
|
||
|
||
virtual HRESULT OnFinalRelease( void );
|
||
|
||
public:
|
||
CMergerTargetSink( CWmiMerger* pMerger, IWbemObjectSink* pDest );
|
||
~CMergerTargetSink();
|
||
|
||
HRESULT STDMETHODCALLTYPE Indicate(long lObjectCount, IWbemClassObject** pObjArray);
|
||
HRESULT STDMETHODCALLTYPE SetStatus( long lFlags, long lParam, BSTR strParam,
|
||
IWbemClassObject* pObjParam );
|
||
|
||
// Function allows us to track the lowest level call in the merger so we can decide
|
||
// if we need to automagically report all indicated objects to the arbitrator
|
||
HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
|
||
};
|
||
|
||
// Causes the stl Map to use our allocator instead of the default
|
||
|
||
struct CInternalMergerRecord
|
||
{
|
||
CWbemInstance* m_pData;
|
||
DWORD m_dwObjSize;
|
||
BOOL m_bOwn;
|
||
};
|
||
|
||
// Defines an allocator so we can throw exceptions
|
||
class CKeyToInstRecordAlloc : public wbem_allocator<CInternalMergerRecord>
|
||
{
|
||
};
|
||
|
||
inline bool operator==(const CKeyToInstRecordAlloc&, const CKeyToInstRecordAlloc&)
|
||
{ return (true); }
|
||
inline bool operator!=(const CKeyToInstRecordAlloc&, const CKeyToInstRecordAlloc&)
|
||
{ return (false); }
|
||
|
||
typedef std::map<WString, CInternalMergerRecord, WSiless, CKeyToInstRecordAlloc> MRGRKEYTOINSTMAP;
|
||
typedef std::map<WString, CInternalMergerRecord, WSiless, CKeyToInstRecordAlloc>::iterator MRGRKEYTOINSTMAPITER;
|
||
|
||
// This is the actual workhorse class for merging instances returned from
|
||
// queries.
|
||
|
||
class CInternalMerger
|
||
{
|
||
protected:
|
||
|
||
// Helper class for scoped cleanup of memory usage
|
||
class CScopedMemoryUsage
|
||
{
|
||
CInternalMerger* m_pInternalMerger;
|
||
bool m_bCleanup;
|
||
long m_lMemUsage;
|
||
|
||
public:
|
||
CScopedMemoryUsage( CInternalMerger* pInternalMerger )
|
||
: m_pInternalMerger( pInternalMerger ), m_bCleanup( false ), m_lMemUsage( 0L ) {};
|
||
~CScopedMemoryUsage();
|
||
|
||
HRESULT ReportMemoryUsage( long lMemUsage );
|
||
HRESULT Cleanup( void );
|
||
};
|
||
|
||
class CMemberSink : public CMergerSink
|
||
{
|
||
protected:
|
||
CInternalMerger* m_pInternalMerger;
|
||
|
||
public:
|
||
CMemberSink( CInternalMerger* pMerger, CWmiMerger* pWmiMerger )
|
||
: CMergerSink( pWmiMerger ), m_pInternalMerger( pMerger )
|
||
{}
|
||
|
||
STDMETHOD_(ULONG, AddRef)(THIS);
|
||
|
||
STDMETHOD(SetStatus)(long lFlags, long lParam, BSTR strParam,
|
||
IWbemClassObject* pObjParam);
|
||
};
|
||
friend CMemberSink;
|
||
|
||
class COwnSink : public CMemberSink
|
||
{
|
||
protected:
|
||
virtual HRESULT OnFinalRelease( void );
|
||
|
||
public:
|
||
COwnSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger) : CMemberSink(pMerger, pWmiMerger){};
|
||
~COwnSink();
|
||
|
||
STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray);
|
||
|
||
// Function allows us to track the lowest level call in the merger so we can decide
|
||
// if we need to automagically report all indicated objects to the arbitrator
|
||
HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
|
||
|
||
};
|
||
friend COwnSink;
|
||
|
||
class CChildSink : public CMemberSink
|
||
{
|
||
protected:
|
||
virtual HRESULT OnFinalRelease( void );
|
||
|
||
public:
|
||
CChildSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger) : CMemberSink(pMerger, pWmiMerger){};
|
||
~CChildSink();
|
||
|
||
STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray);
|
||
|
||
// Function allows us to track the lowest level call in the merger so we can decide
|
||
// if we need to automagically report all indicated objects to the arbitrator
|
||
HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
|
||
};
|
||
|
||
class COwnInstanceSink : public CMemberSink
|
||
{
|
||
CCritSec m_cs;
|
||
WString m_wsInstPath;
|
||
IWbemClassObject* m_pMergedInstance;
|
||
bool m_bTriedRetrieve;
|
||
HRESULT m_hFinalStatus;
|
||
|
||
protected:
|
||
virtual HRESULT OnFinalRelease( void );
|
||
|
||
public:
|
||
COwnInstanceSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger)
|
||
: CMemberSink(pMerger, pWmiMerger), m_pMergedInstance( NULL ), m_wsInstPath(),
|
||
m_cs(), m_bTriedRetrieve( false ), m_hFinalStatus( WBEM_S_NO_ERROR )
|
||
{};
|
||
~COwnInstanceSink();
|
||
|
||
STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray);
|
||
STDMETHOD(SetStatus)(long lFlags, long lParam, BSTR strParam,
|
||
IWbemClassObject* pObjParam);
|
||
|
||
// This should never be called here
|
||
HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
|
||
HRESULT SetInstancePath( LPCWSTR pwszPath );
|
||
HRESULT GetObject( IWbemClassObject** ppMergedInst );
|
||
void SetFinalStatus( HRESULT hRes )
|
||
{ if ( SUCCEEDED( m_hFinalStatus ) ) m_hFinalStatus = hRes; };
|
||
};
|
||
|
||
friend CChildSink;
|
||
|
||
public:
|
||
|
||
// Helpers for creating sinks
|
||
static HRESULT CreateMergingSink( MergerSinkType eType, CInternalMerger* pMerger, CWmiMerger* pWmiMerger, CMergerSink** ppSink );
|
||
|
||
// 2 stage initialization
|
||
HRESULT Initialize( void );
|
||
|
||
protected:
|
||
COwnSink* m_pOwnSink;
|
||
CChildSink* m_pChildSink;
|
||
CMergerSink* m_pDest;
|
||
|
||
BOOL m_bDerivedFromTarget;
|
||
CWbemClass* m_pOwnClass;
|
||
CWbemNamespace* m_pNamespace;
|
||
IWbemContext* m_pContext;
|
||
CWmiMergerRecord* m_pWmiMergerRecord;
|
||
|
||
MRGRKEYTOINSTMAP m_map;
|
||
|
||
BOOL m_bOwnDone;
|
||
BOOL m_bChildrenDone;
|
||
WString m_wsClass;
|
||
long m_lRef;
|
||
|
||
IServerSecurity* m_pSecurity;
|
||
|
||
// This is set when we encounter an error condition and are cancelled
|
||
HRESULT m_hErrorRes;
|
||
|
||
// m_Throttler - sounds like a Supervillain...hmmm...
|
||
CMergerThrottling m_Throttler;
|
||
|
||
// Helps debug how much data this internal merger is consuming
|
||
long m_lTotalObjectData;
|
||
|
||
// Iterator which may require state to be kept
|
||
MRGRKEYTOINSTMAPITER m_DispatchOwnIter;
|
||
|
||
protected:
|
||
HRESULT AddOwnObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
HRESULT AddChildObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated );
|
||
HRESULT AddOwnInstance( IWbemClassObject* pObj, LPCWSTR wszTargetKey,
|
||
IWbemClassObject** ppMergedInstance);
|
||
HRESULT RemoveInstance( LPCWSTR pwszInstancePath );
|
||
|
||
HRESULT GetObjectLength( IWbemClassObject* pObj, long* plObjectSize );
|
||
|
||
// inline helper - adjusts throttler totals, then allows it to release itself if
|
||
// apropriate
|
||
void AdjustThrottle( long lNumParentObjects, long lNumChildObjects )
|
||
{
|
||
// Adjust the throttler now.
|
||
m_Throttler.AdjustNumParentObjects( lNumParentObjects );
|
||
m_Throttler.AdjustNumChildObjects( lNumChildObjects );
|
||
|
||
// Let the Throttler release itself if it can
|
||
m_Throttler.ReleaseThrottle();
|
||
}
|
||
|
||
// Helper function to perform Indicating and throttling - a lot of the code is more or
|
||
// less the same so this at least attempts to encapsulate it.
|
||
HRESULT IndicateArrayAndThrottle( long lObjectCount, CRefedPointerArray<IWbemClassObject>* pObjArray,
|
||
CWStringArray* pwsKeyArray, long lMapAdjustmentSize, long lNewObjectSize, bool bThrottle,
|
||
bool bParent, long* plNumIndicated );
|
||
|
||
void Enter() { m_Throttler.Enter(); }
|
||
void Leave() { m_Throttler.Leave(); }
|
||
|
||
long AddRef();
|
||
long Release();
|
||
|
||
void OwnIsDone();
|
||
void ChildrenAreDone();
|
||
|
||
void DispatchChildren();
|
||
void DispatchOwn();
|
||
void GetKey(IWbemClassObject* pInst, WString& wsKey);
|
||
HRESULT GetOwnInstance(LPCWSTR wszKey, IWbemClassObject** ppMergedInstance);
|
||
BOOL IsDone() {return m_bOwnDone && m_bChildrenDone;}
|
||
|
||
void AdjustLocalObjectSize( long lAdjust )
|
||
{
|
||
m_lTotalObjectData += lAdjust;
|
||
_DBG_ASSERT( m_lTotalObjectData >= 0L );
|
||
}
|
||
|
||
HRESULT ReportMemoryUsage( long lMemUsage );
|
||
|
||
public:
|
||
CInternalMerger(CWmiMergerRecord* pWmiMergerRecord, CMergerSink* pDest, CWbemClass* pOwnClass,
|
||
CWbemNamespace* pNamespace = NULL,
|
||
IWbemContext* pContext = NULL);
|
||
~CInternalMerger();
|
||
|
||
void SetIsDerivedFromTarget(BOOL bIs);
|
||
|
||
void Cancel( HRESULT hRes = WBEM_E_CALL_CANCELLED );
|
||
|
||
CMergerSink* GetOwnSink() { if ( NULL != m_pOwnSink ) m_pOwnSink->AddRef(); return m_pOwnSink;}
|
||
CMergerSink* GetChildSink() { if ( NULL != m_pChildSink ) m_pChildSink->AddRef(); return m_pChildSink; }
|
||
|
||
CWmiMerger* GetWmiMerger( void );
|
||
|
||
// Helper to cancel a child sink when we don't need one (i.e. if we're fully static).
|
||
void CancelChildSink( void ) { ChildrenAreDone(); }
|
||
};
|
||
|
||
#endif
|
||
|
||
|
||
|