windows-nt/Source/XPSP1/NT/admin/wmi/wbem/scripting/objsink.h
2020-09-26 16:20:57 +08:00

508 lines
14 KiB
C++

//***************************************************************************
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// objsink.h
//
// rogerbo 22-May-98 Created.
//
// Implementation of IWbemObjectSink for async stuff
//
//***************************************************************************
#ifndef _OBJSINK_H_
#define _OBJSINK_H_
// CIWbemObjectSinkCachedMethodItem is the base class of link list items
// representing cached method calls to IWbemObjectSink. Whenever we are inside
// an IWbemObjectSink method, and we receive a nested call to IWbemObjectSink,
// we store the parameters to the nested call and redo the call just before the
// original method returns. It is important to cache all methods on the sink to
// preserve the order that they are seen by the client. This means that
// if calls to SetStatus come in during a call to Indicate, it must be cached.
// In addition, we cache calls across all instances of IWbemObjectSink. In
// other words, suppose we have two async requests (request1 and request2). If
// we are processing an Indicate for request1 and get an Indicate for request2,
// we have to cache the nested Indicate (including the this pointer for the
// IWbemObjectSink), and call the recall the nested Indicate at the end of the
// Indicate for request1.
class CIWbemObjectSinkCachedMethodItem
{
public:
CIWbemObjectSinkCachedMethodItem(IWbemObjectSink *pSink) :
m_pSink (pSink),
m_pNext (NULL)
{
if (m_pSink)
m_pSink->AddRef();
}
virtual ~CIWbemObjectSinkCachedMethodItem()
{
if (m_pSink)
m_pSink->Release();
}
// DoCallAgain is to be overridden in derived classes to recall cached
// methods.
virtual void DoCallAgain() = 0;
// This is a pointer to the next cached interface call
CIWbemObjectSinkCachedMethodItem *m_pNext;
protected:
// Pointer to the original IWbemObjectSink for the cached call
IWbemObjectSink *m_pSink;
};
// CIWbemObjectSinkCachedIndicate represents a cached call to Indicate
class CIWbemObjectSinkCachedIndicate : public CIWbemObjectSinkCachedMethodItem
{
public:
CIWbemObjectSinkCachedIndicate(IWbemObjectSink *pSink, long lObjectCount, IWbemClassObject **apObjArray)
: CIWbemObjectSinkCachedMethodItem (pSink)
{
_RD(static char *me = "CIWbemObjectSinkCachedIndicate::CIWbemObjectSinkCachedIndicate";)
_RPrint(me, "", 0, "");
// Store the original parameters to the Indicate call
// TODO: What if lObjectCount = 0 ?
m_lObjectCount = lObjectCount;
m_apObjArray = new IWbemClassObject*[lObjectCount];
if (m_apObjArray)
{
for(int i=0;i<lObjectCount;i++)
{
apObjArray[i]->AddRef();
m_apObjArray[i] = apObjArray[i];
}
}
}
~CIWbemObjectSinkCachedIndicate()
{
_RD(static char *me = "CIWbemObjectSinkCachedIndicate::~CIWbemObjectSinkCachedIndicate";)
_RPrint(me, "", 0, "");
// Free memory used to store original parameters to Indicate
if (m_apObjArray)
{
for(int i=0;i<m_lObjectCount;i++)
{
RELEASEANDNULL(m_apObjArray[i])
}
delete [] m_apObjArray;
}
}
void DoCallAgain()
{
// Recall the Indicate method with the cached parameters
if (m_pSink && m_apObjArray)
m_pSink->Indicate(m_lObjectCount, m_apObjArray);
}
private:
// Parameters to Indicate that we must store
long m_lObjectCount;
IWbemClassObject **m_apObjArray;
};
// CIWbemObjectSinkCachedSetStatus represents a cached call to SetStatus
class CIWbemObjectSinkCachedSetStatus : public CIWbemObjectSinkCachedMethodItem
{
public:
CIWbemObjectSinkCachedSetStatus(
IWbemObjectSink *pSink,
long lFlags,
HRESULT hResult,
BSTR strParam,
IWbemClassObject *pObjParam) :
CIWbemObjectSinkCachedMethodItem (pSink),
m_lFlags (lFlags),
m_hResult (hResult),
m_strParam (NULL),
m_pObjParam (pObjParam)
{
_RD(static char *me = "CIWbemObjectSinkCachedSetStatus::CIWbemObjectSinkCachedSetStatus";)
_RPrint(me, "", 0, "");
if(strParam)
m_strParam = SysAllocString(strParam);
if(m_pObjParam)
m_pObjParam->AddRef();
}
~CIWbemObjectSinkCachedSetStatus()
{
_RD(static char *me = "CIWbemObjectSinkCachedSetStatus::~CIWbemObjectSinkCachedSetStatus";)
_RPrint(me, "", 0, "");
// Free memory used to store original parameters to SetStatus
FREEANDNULL(m_strParam)
RELEASEANDNULL(m_pObjParam)
}
void DoCallAgain()
{
// Recall the SetStatus method with the cached parameters
if (m_pSink)
m_pSink->SetStatus(m_lFlags, m_hResult, m_strParam, m_pObjParam);
}
private:
// Parameters to SetStatus that we must store
long m_lFlags;
HRESULT m_hResult;
BSTR m_strParam;
IWbemClassObject *m_pObjParam;
};
// This is the class that manages all cached calls to IWbemObjectSink. To
// cache the interface method calls, each interface method should call
// TestOkToRunXXX where XXX is the method name. If this function returns
// FALSE, it means that we are already inside another method call. The
// parameters will have been cached, the the method should return immediately.
// At the end of the method, Cleanup should be called so that all cached method
// calls can be recalled.
class CIWbemObjectSinkMethodCache
{
protected:
// Constructor/destructor are protected since this object should only be
// created/destroyed by the static methods AddRefForThread/ReleaseForThread
CIWbemObjectSinkMethodCache() :
m_fInInterface (FALSE),
m_pFirst (NULL),
m_pLast (NULL),
m_fOverrideTest (FALSE),
m_fOverrideCleanup (FALSE),
m_dwRef (1)
{
_RD(static char *me = "CIWbemObjectSinkMethodCache::CIWbemObjectSinkMethodCache";)
_RPrint(me, "", 0, "");
}
~CIWbemObjectSinkMethodCache()
{
_RD(static char *me = "CIWbemObjectSinkMethodCache::~CIWbemObjectSinkMethodCache";)
_RPrint(me, "", 0, "");
_RPrint(me, "m_pFirst: ", long(m_pFirst), "");
_RPrint(me, "m_pLast: ", long(m_pLast), "");
// TODO: ASSERT that m_pFirst and m_pLast are NULL. In other words,
// as long as Cleanup is called at the end of each interface method,
// the internal link list should be completely empty.
}
public:
// Public Methods
static void Initialize () {
sm_dwTlsForInterfaceCache = TlsAlloc();
}
static void TidyUp () {
if (-1 != sm_dwTlsForInterfaceCache)
{
TlsFree (sm_dwTlsForInterfaceCache);
sm_dwTlsForInterfaceCache = -1;
}
}
static void AddRefForThread()
{
if(-1 == sm_dwTlsForInterfaceCache)
return; // We failed the original alloc
// The Tls value for sm_dwTlsForInterfaceCache is guaranteed to
// initialize to NULL
CIWbemObjectSinkMethodCache *pSinkMethodCache = (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
if(NULL == pSinkMethodCache)
TlsSetValue(sm_dwTlsForInterfaceCache, new CIWbemObjectSinkMethodCache);
else
pSinkMethodCache->AddRef();
}
static void ReleaseForThread()
{
if(-1 == sm_dwTlsForInterfaceCache)
return; // We failed the original alloc
CIWbemObjectSinkMethodCache *pSinkMethodCache = (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
if(NULL != pSinkMethodCache)
{
DWORD dwCount = pSinkMethodCache->Release();
if(dwCount == 0)
{
delete pSinkMethodCache;
TlsSetValue(sm_dwTlsForInterfaceCache, NULL);
}
}
}
static CIWbemObjectSinkMethodCache *GetThreadsCache()
{
if(-1 == sm_dwTlsForInterfaceCache)
return NULL; // We failed the original alloc
return (CIWbemObjectSinkMethodCache *)TlsGetValue(sm_dwTlsForInterfaceCache);
}
protected:
// TLS slot for Interface Cache pointer
static DWORD sm_dwTlsForInterfaceCache;
public:
// Public Instance Methods
// Call this method at the start of the Indicate method. If this method
// returns TRUE, Indicate should return immediately.
BOOL TestOkToRunIndicate(IWbemObjectSink *pSink, long lObjectCount, IWbemClassObject **apObjArray)
{
// If there was a problem allocating the TLS instance of the cache,
// 'this' might be NULL. In that case, act as if there was no cache
if(NULL == this)
return TRUE;
// If m_fOverrideTest is TRUE, it means that we are recalling a cached
// call to Indicate. We therefore must complete the body of Indicate.
if(m_fOverrideTest)
{
m_fOverrideTest = FALSE;
return TRUE;
}
// If we are already in an interface method, cache this call
if(m_fInInterface)
{
CIWbemObjectSinkCachedIndicate *pItem = new CIWbemObjectSinkCachedIndicate(pSink, lObjectCount, apObjArray);
// TODO: What if allocation fails?
if(pItem)
AddItem(pItem);
return FALSE;
}
// We are not already in another interface method, but we set
// m_fInInterface to TRUE to prevent nested calls
m_fInInterface = TRUE;
return TRUE;
}
// Call this method at the start of the SetStatus method. If this method
// returns TRUE, SetStatus should return immediately.
BOOL TestOkToRunSetStatus(IWbemObjectSink *pSink, long lFlags, HRESULT hResult, BSTR strParam, IWbemClassObject *pObjParam)
{
// If there was a problem allocating the TLS instance of the cache,
// 'this' might be NULL. In that case, act as if there was no cache
if(NULL == this)
return TRUE;
// If m_fOverrideTest is TRUE, it means that we are recalling a cached
// call to SetStatus. We therefore must complete the body of SetStatus.
if(m_fOverrideTest)
{
m_fOverrideTest = FALSE;
return TRUE;
}
// If we are already in an interface method, cache this call
if(m_fInInterface)
{
CIWbemObjectSinkCachedSetStatus *pItem = new CIWbemObjectSinkCachedSetStatus(pSink, lFlags, hResult, strParam, pObjParam);
// TODO: What if allocation fails?
if(pItem)
AddItem(pItem);
return FALSE;
}
// We are not already in another interface method, but we set
// m_fInInterface to TRUE to prevent nested calls
m_fInInterface = TRUE;
return TRUE;
}
// At the end of every IWbemObjectSink method, Cleanup should be called.
// This will recall any cached method parameters
void Cleanup()
{
// If there was a problem allocating the TLS instance of the cache,
// 'this' might be NULL. In that case, act as if there was no cache
if(NULL == this)
return;
// If m_fOverridCleanup is TRUE, we are in an interface method because
// we are recalling it. There is nothing more that Cleanup should do
if(m_fOverrideCleanup)
{
m_fOverrideCleanup = FALSE;
return;
}
// While there are any items in the link list, recall the methods.
// NOTE: It is possible that new items will be added to the end of the
// link list during DoCallAgain, but when this 'while' loop finishes
// we will be in a state where all cached methods have been called
while(m_pFirst)
{
// Set override flags so that the interface methods know that they
// are not receiving a nested call
m_fOverrideTest = TRUE;
m_fOverrideCleanup = TRUE;
// Recall the cached method
m_pFirst->DoCallAgain();
// Remove this item from the start of the link list
CIWbemObjectSinkCachedMethodItem *pItem = m_pFirst;
m_pFirst = pItem->m_pNext;
delete pItem;
}
// The link list is empty
m_pLast = NULL;
// We are about to leave the interface method
m_fInInterface = FALSE;
}
protected:
// Add cached method information to the link list
void AddItem(CIWbemObjectSinkCachedMethodItem *pItem)
{
if(NULL == m_pLast)
{
m_pFirst = pItem;
m_pLast = pItem;
}
else
{
m_pLast->m_pNext = pItem;
m_pLast = pItem;
}
}
protected:
// Reference counting of thread local object
void AddRef()
{
m_dwRef++;
}
int Release()
{
m_dwRef--;
return m_dwRef;
}
DWORD m_dwRef;
protected:
// Member Variables
// Flag that specifies if we are currently processing an interface method
BOOL m_fInInterface;
// Pointer to the first and last items of the link list of cached methods
CIWbemObjectSinkCachedMethodItem *m_pFirst;
CIWbemObjectSinkCachedMethodItem *m_pLast;
// Flags to tell interface method implementations that they are being called
// to recall a cached method as opposed to receiving a nested call.
BOOL m_fOverrideTest;
BOOL m_fOverrideCleanup;
};
//***************************************************************************
//
// CLASS NAME:
//
// CWbemObjectSink
//
// DESCRIPTION:
//
// Implements the IWbemObjectSink interface.
//
//***************************************************************************
class CWbemObjectSink : public IWbemObjectSink
{
private:
CSWbemServices *m_pServices;
IUnsecuredApartment *m_pUnsecuredApartment;
ISWbemPrivateSink *m_pSWbemSink;
IDispatch *m_pContext;
IWbemObjectSink *m_pObjectStub;
BSTR m_bsClassName;
bool m_putOperation;
bool m_operationInProgress;
bool m_setStatusCompletedCalled;
// Members required for just-in-time initialization of m_pServices
BSTR m_bsNamespace;
BSTR m_bsUser;
BSTR m_bsPassword;
BSTR m_bsLocale;
void RemoveObjectSink();
HRESULT AddObjectSink(IWbemObjectSink *pSink);
protected:
long m_cRef; //Object reference count
public:
CWbemObjectSink(CSWbemServices *pServices, IDispatch *pSWbemSink, IDispatch *pContext,
bool putOperation = false, BSTR bsClassName = NULL);
~CWbemObjectSink(void);
static IWbemObjectSink *CreateObjectSink(CWbemObjectSink **pWbemObjectSink,
CSWbemServices *pServices,
IDispatch *pSWbemSink,
IDispatch *pContext,
bool putOperation = false,
BSTR bsClassName = NULL);
//Non-delegating object IUnknown
STDMETHODIMP QueryInterface(REFIID, LPVOID*);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{return E_NOTIMPL;}
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{return E_NOTIMPL;}
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames,
UINT cNames, LCID lcid, DISPID* rgdispid)
{return E_NOTIMPL;}
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{return E_NOTIMPL;}
// IWbemObjectSink methods
HRESULT STDMETHODCALLTYPE Indicate(
/* [in] */ long lObjectCount,
/* [size_is][in] */ IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray);
HRESULT STDMETHODCALLTYPE SetStatus(
/* [in] */ long lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam);
IWbemObjectSink *GetObjectStub();
void ReleaseTheStubIfNecessary(HRESULT hResult);
};
#endif