508 lines
14 KiB
C
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
|