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.
468 lines
12 KiB
468 lines
12 KiB
//***************************************************************************
|
|
//
|
|
// Copyright (c) 1998-2000 Microsoft Corporation
|
|
//
|
|
// objsink.cpp
|
|
//
|
|
// rogerbo 22-May-98 Created.
|
|
//
|
|
// Defines the implementation of IWbemObjectSink
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
#include "objsink.h"
|
|
|
|
DWORD CIWbemObjectSinkMethodCache::sm_dwTlsForInterfaceCache = -1;
|
|
|
|
CWbemObjectSink::CWbemObjectSink(CSWbemServices *pServices, IDispatch *pSWbemSink, IDispatch *pContext,
|
|
bool putOperation, BSTR bsClassName) :
|
|
m_pServices (NULL),
|
|
m_pUnsecuredApartment (NULL),
|
|
m_bsNamespace (NULL),
|
|
m_bsUser (NULL),
|
|
m_bsPassword (NULL),
|
|
m_bsLocale (NULL)
|
|
{
|
|
_RD(static char *me = "CWbemObjectSink::CWbemObjectSink";)
|
|
_RPrint(me, "Called", 0, "");
|
|
|
|
CIWbemObjectSinkMethodCache::AddRefForThread();
|
|
m_cRef = 0;
|
|
|
|
m_pObjectStub = NULL;
|
|
m_pSWbemSink = NULL;
|
|
m_putOperation = putOperation;
|
|
m_pContext = pContext;
|
|
m_bsClassName = NULL;
|
|
|
|
m_operationInProgress = TRUE;
|
|
m_setStatusCompletedCalled = FALSE;
|
|
|
|
if (pSWbemSink)
|
|
{
|
|
ISWbemPrivateSinkLocator *pSinkLocator = NULL;
|
|
HRESULT hr = pSWbemSink->QueryInterface(IID_ISWbemPrivateSinkLocator, (PPVOID)&pSinkLocator);
|
|
if(SUCCEEDED(hr) && pSinkLocator)
|
|
{
|
|
IUnknown *pUnk = NULL;
|
|
hr = pSinkLocator->GetPrivateSink(&pUnk);
|
|
if(SUCCEEDED(hr) && pUnk)
|
|
{
|
|
pUnk->QueryInterface(IID_ISWbemPrivateSink, (PPVOID)&m_pSWbemSink);
|
|
pUnk->Release();
|
|
}
|
|
pSinkLocator->Release();
|
|
}
|
|
}
|
|
|
|
if (bsClassName)
|
|
m_bsClassName = SysAllocString(bsClassName);
|
|
|
|
/*
|
|
* Copy the services proxy to ensure independence of security attributes
|
|
* from the parent CSWbemServices.
|
|
*/
|
|
if (pServices)
|
|
{
|
|
m_pServices = new CSWbemServices (pServices, NULL);
|
|
|
|
if (m_pServices)
|
|
m_pServices->AddRef ();
|
|
|
|
m_pUnsecuredApartment = pServices->GetCachedUnsecuredApartment ();
|
|
}
|
|
|
|
if (m_pContext)
|
|
m_pContext->AddRef();
|
|
|
|
InterlockedIncrement(&g_cObj);
|
|
}
|
|
|
|
|
|
CWbemObjectSink::~CWbemObjectSink(void)
|
|
{
|
|
_RD(static char *me = "CWbemObjectSink::~CWbemObjectSink";)
|
|
_RPrint(me, "Called", 0, "");
|
|
|
|
CIWbemObjectSinkMethodCache::ReleaseForThread();
|
|
InterlockedDecrement(&g_cObj);
|
|
|
|
RELEASEANDNULL(m_pServices)
|
|
RELEASEANDNULL(m_pUnsecuredApartment)
|
|
RELEASEANDNULL(m_pSWbemSink)
|
|
RELEASEANDNULL(m_pContext)
|
|
FREEANDNULL(m_bsClassName)
|
|
FREEANDNULL(m_bsNamespace)
|
|
FREEANDNULL(m_bsUser)
|
|
FREEANDNULL(m_bsPassword)
|
|
FREEANDNULL(m_bsLocale)
|
|
}
|
|
|
|
IWbemObjectSink *CWbemObjectSink::CreateObjectSink (CWbemObjectSink **pWbemObjectSink,
|
|
CSWbemServices *pServices,
|
|
IDispatch *pSWbemSink,
|
|
IDispatch *pContext,
|
|
bool putOperation,
|
|
BSTR bsClassName)
|
|
{
|
|
IWbemObjectSink *pIWbemObjectSink = NULL;
|
|
CWbemObjectSink *pTmpSink = NULL;
|
|
|
|
if (pSWbemSink)
|
|
{
|
|
pTmpSink = new CWbemObjectSink(pServices, pSWbemSink, pContext, putOperation, bsClassName);
|
|
|
|
if (pTmpSink)
|
|
{
|
|
pIWbemObjectSink = pTmpSink->GetObjectStub();
|
|
if (pIWbemObjectSink && FAILED(pTmpSink->AddObjectSink(pIWbemObjectSink)))
|
|
pIWbemObjectSink = NULL;
|
|
|
|
if (!pIWbemObjectSink)
|
|
{
|
|
delete pTmpSink;
|
|
pTmpSink = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pWbemObjectSink = pTmpSink;
|
|
return pIWbemObjectSink;
|
|
}
|
|
|
|
void CWbemObjectSink::ReleaseTheStubIfNecessary(HRESULT hResult) {
|
|
|
|
/*
|
|
* If we failed locally and SetStatus has not been called
|
|
* then we need to remove object from list of outstanding sinks
|
|
*/
|
|
if (FAILED(hResult) && !m_setStatusCompletedCalled)
|
|
RemoveObjectSink();
|
|
|
|
/*
|
|
* SetStatus can be called whilst we were in the async op.
|
|
* if this happens then SetStatus will not release the sink
|
|
* but will set a flag (m_setStatusCompletedCalled). In this
|
|
* case we will need to release the stub here (the call has completed)
|
|
* Of course we could have also failed locally (regardless of whether
|
|
* SetStatus has been called or not) - in this case we must also
|
|
* release the stub.
|
|
*/
|
|
if (m_pObjectStub && (FAILED(hResult) || m_setStatusCompletedCalled)) {
|
|
// Call to release is same as (delete this !)
|
|
IWbemObjectSink *tmpSink = m_pObjectStub;
|
|
m_pObjectStub = NULL;
|
|
tmpSink->Release();
|
|
} else {
|
|
m_operationInProgress = FALSE;
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
// HRESULT CWbemObjectSink::QueryInterface
|
|
// long CWbemObjectSink::AddRef
|
|
// long CWbemObjectSink::Release
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Standard Com IUNKNOWN functions.
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CWbemObjectSink::QueryInterface (
|
|
|
|
IN REFIID riid,
|
|
OUT LPVOID *ppv
|
|
)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if (IID_IUnknown==riid)
|
|
*ppv = reinterpret_cast<IUnknown*>(this);
|
|
else if (IID_IWbemObjectSink==riid)
|
|
*ppv = (IWbemObjectSink *)this;
|
|
else if (IID_IDispatch==riid)
|
|
*ppv = (IDispatch *)this;
|
|
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CWbemObjectSink::AddRef(void)
|
|
{
|
|
InterlockedIncrement(&m_cRef);
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CWbemObjectSink::Release(void)
|
|
{
|
|
_RD(static char *me = "CWbemObjectSink::Release";)
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
_RPrint(me, "After decrement", m_cRef, "RefCount: ");
|
|
if (0 != cRef)
|
|
{
|
|
_ASSERT(cRef > 0);
|
|
return cRef;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __RTEST_RPC_FAILURE
|
|
int __Rx = 0;
|
|
bool __Rdone = true;
|
|
#endif
|
|
|
|
HRESULT STDMETHODCALLTYPE CWbemObjectSink::Indicate(
|
|
/* [in] */ long lObjectCount,
|
|
/* [size_is][in] */ IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray)
|
|
{
|
|
_RD(static char *me = "CWbemObjectSink::Indicate";)
|
|
_RPrint(me, "Called", 0, "");
|
|
|
|
// See if we need to cache this method call if we are already in another
|
|
// IWbemObjectSink interface method
|
|
CIWbemObjectSinkMethodCache *pSinkMethodCache = CIWbemObjectSinkMethodCache::GetThreadsCache();
|
|
|
|
if(pSinkMethodCache && !pSinkMethodCache->TestOkToRunIndicate(this, lObjectCount, apObjArray))
|
|
{
|
|
_RPrint(me, ">>>Re-entrant Indicate call", 0, "");
|
|
return S_OK;
|
|
}
|
|
|
|
//------------------------------
|
|
// walk though the classObjects...
|
|
for (int i = 0; i < lObjectCount; i++)
|
|
{
|
|
#ifdef __RTEST_RPC_FAILURE
|
|
__Rx++;
|
|
#endif
|
|
/*
|
|
* NB: Although the CSWbemObject constructor has AddRef'd the
|
|
* apObjArray[i] above, we do not balance this with a Release call
|
|
* before leaving this function. According to CIMOM documentation
|
|
* this is correct behavior if it cannot be gauranteed that the
|
|
* objects will not be used after this call has returned.
|
|
*
|
|
* Also it appears the case that when calling into the OnObjectReady
|
|
* function, the ISWbemObject should have a RefCount of 0 to be
|
|
* garbage collected properly.
|
|
*/
|
|
|
|
CSWbemObject *pObject = new CSWbemObject(m_pServices, apObjArray[i]);
|
|
|
|
if (pObject)
|
|
{
|
|
CComPtr<IDispatch> pObjDisp;
|
|
|
|
if (SUCCEEDED(pObject->QueryInterface(IID_IDispatch, (PPVOID)&pObjDisp)))
|
|
{
|
|
if (m_pSWbemSink)
|
|
m_pSWbemSink->OnObjectReady(pObjDisp, m_pContext);
|
|
|
|
} else {
|
|
|
|
delete pObject;
|
|
}
|
|
}
|
|
|
|
} // endfor
|
|
|
|
|
|
#ifdef __RTEST_RPC_FAILURE
|
|
if ((__Rx >= 15) && !__Rdone)
|
|
{
|
|
__Rdone = true;
|
|
return RPC_E_SERVERFAULT;
|
|
}
|
|
#endif
|
|
|
|
// Recall any cached interface methods if nested calls were received
|
|
if (pSinkMethodCache)
|
|
pSinkMethodCache->Cleanup();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CWbemObjectSink::SetStatus(
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ HRESULT hResult,
|
|
/* [in] */ BSTR strParam,
|
|
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam)
|
|
{
|
|
// See if we need to cache this method call if we are already in another
|
|
// IWbemObjectSink interface method
|
|
CIWbemObjectSinkMethodCache *pSinkMethodCache = CIWbemObjectSinkMethodCache::GetThreadsCache();
|
|
|
|
if(pSinkMethodCache && !pSinkMethodCache->TestOkToRunSetStatus(this, lFlags, hResult, strParam, pObjParam))
|
|
return S_OK;
|
|
|
|
if (lFlags == WBEM_STATUS_COMPLETE)
|
|
{
|
|
IDispatch *pCSWbemObjectDisp = NULL;
|
|
IDispatch *pObjectPathDisp = NULL;
|
|
|
|
if (pObjParam)
|
|
{
|
|
/*
|
|
* NB: Although the CSWbemObject constructor has AddRef'd the
|
|
* pObjParam above, we do not balance this with a Release call
|
|
* before leaving this function. According to CIMOM documentation
|
|
* this is correct behavior if it cannot be gauranteed that the
|
|
* objects will not be used after this call has returned.
|
|
* Also it appears the case that when calling into the OnObjectReady
|
|
* function, the ISWbemObject should have a RefCount of 0 to be
|
|
* garbage collected properly.
|
|
*/
|
|
|
|
CSWbemObject *pCSWbemObject = new CSWbemObject(m_pServices, pObjParam);
|
|
|
|
if (pCSWbemObject)
|
|
{
|
|
if (FAILED(pCSWbemObject->QueryInterface(IID_IDispatch, (PPVOID)&pCSWbemObjectDisp)))
|
|
{
|
|
delete pCSWbemObject;
|
|
pCSWbemObjectDisp = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_putOperation && m_pServices)
|
|
{
|
|
CSWbemSecurity *pSecurity = m_pServices->GetSecurityInfo ();
|
|
ISWbemObjectPath *pObjectPath = new CSWbemObjectPath (pSecurity);
|
|
|
|
if (pSecurity)
|
|
pSecurity->Release ();
|
|
|
|
if (pObjectPath)
|
|
{
|
|
if (SUCCEEDED(pObjectPath->QueryInterface(IID_IDispatch, (PPVOID)&pObjectPathDisp)))
|
|
{
|
|
pObjectPath->put_Path (m_pServices->GetPath ());
|
|
|
|
if (m_bsClassName)
|
|
pObjectPath->put_RelPath (m_bsClassName);
|
|
else if (strParam)
|
|
pObjectPath->put_RelPath (strParam);
|
|
}
|
|
else
|
|
{
|
|
delete pObjectPath;
|
|
pObjectPathDisp = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
RemoveObjectSink();
|
|
|
|
// Transform the error code if need be
|
|
if (WBEM_S_ACCESS_DENIED == hResult)
|
|
hResult = wbemErrAccessDenied;
|
|
else if (WBEM_S_OPERATION_CANCELLED == hResult)
|
|
hResult = wbemErrCallCancelled;
|
|
else if (SUCCEEDED(hResult))
|
|
hResult = wbemNoErr; // Ignore the other success codes for now.
|
|
|
|
if (m_pSWbemSink)
|
|
m_pSWbemSink->OnCompleted((WbemErrorEnum)hResult, pCSWbemObjectDisp, pObjectPathDisp, m_pContext);
|
|
|
|
// Release the stub but only if an op is not in progress
|
|
// If an op is in progress, stub will be removed on exit from op
|
|
// If op is in Progress - stash hResult for later
|
|
if (m_pObjectStub && !m_operationInProgress) {
|
|
IWbemObjectSink *tmpStub = m_pObjectStub;
|
|
m_pObjectStub = NULL;
|
|
tmpStub->Release();
|
|
}
|
|
else {
|
|
m_setStatusCompletedCalled = TRUE;
|
|
}
|
|
|
|
if (pCSWbemObjectDisp)
|
|
pCSWbemObjectDisp->Release();
|
|
|
|
if (pObjectPathDisp)
|
|
pObjectPathDisp->Release();
|
|
|
|
} else if (lFlags & WBEM_STATUS_PROGRESS)
|
|
{
|
|
if (m_pSWbemSink)
|
|
m_pSWbemSink->OnProgress(HIWORD(hResult), LOWORD(hResult), strParam, m_pContext);
|
|
}
|
|
|
|
// Recall any cached interface methods if nested calls were received
|
|
if (pSinkMethodCache)
|
|
pSinkMethodCache->Cleanup();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
IWbemObjectSink *CWbemObjectSink::GetObjectStub()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_pObjectStub && m_pUnsecuredApartment)
|
|
{
|
|
// Create the object stub using unsecapp
|
|
IUnknown *pSubstitute = NULL;
|
|
|
|
// If we are called before this object has been handed out
|
|
// we'd better protect our ref count
|
|
bool bBumpUpRefCount = false;
|
|
|
|
if (0 == m_cRef)
|
|
{
|
|
m_cRef++;
|
|
bBumpUpRefCount = true;
|
|
}
|
|
|
|
if (SUCCEEDED (hr = m_pUnsecuredApartment->CreateObjectStub(this, &pSubstitute)))
|
|
{
|
|
// Ensure we QI for IWbemObjectSink
|
|
hr = pSubstitute->QueryInterface (IID_IWbemObjectSink, (PPVOID) &m_pObjectStub);
|
|
if (FAILED(hr))
|
|
m_pObjectStub = NULL;
|
|
|
|
// Now we're done with the returned stub
|
|
pSubstitute->Release ();
|
|
}
|
|
|
|
if (bBumpUpRefCount)
|
|
m_cRef--;
|
|
}
|
|
|
|
return m_pObjectStub;
|
|
}
|
|
|
|
HRESULT CWbemObjectSink::AddObjectSink(IWbemObjectSink *pSink)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pSWbemSink)
|
|
{
|
|
if(m_pServices)
|
|
{
|
|
CComPtr<IWbemServices> pIWbemServices;
|
|
pIWbemServices.Attach( m_pServices->GetIWbemServices ());
|
|
|
|
// Is AddObjectSink assuming these 2 args have been AddRef'd already??
|
|
m_pSWbemSink->AddObjectSink(pSink, pIWbemServices);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void CWbemObjectSink::RemoveObjectSink()
|
|
{
|
|
if (m_pSWbemSink)
|
|
m_pSWbemSink->RemoveObjectSink(GetObjectStub());
|
|
}
|
|
|