//*************************************************************************** // // 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; // Encryption/Decryption helpers void EncryptString(BSTR bsString) { ULONG len = 0; if (bsString && (0 < wcslen (bsString))) { for ( ULONG x = 0; x < len; x++ ) { bsString[x] += 1; } } } void DecryptString(BSTR bsString) { ULONG len = 0; if (bsString && (0 < wcslen (bsString))) { for ( ULONG x = 0; x < len; x++ ) { bsString[x] -= 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(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";) InterlockedDecrement(&m_cRef); _RPrint(me, "After decrement", m_cRef, "RefCount: "); if (0L!=m_cRef) return m_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 pObjDisp; if (SUCCEEDED(pObject->QueryInterface(IID_IDispatch, (PPVOID)&pObjDisp))) { if (m_pSWbemSink) m_pSWbemSink->OnObjectReady(pObjDisp, m_pContext); } } } // 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 pIWbemServices = 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()); }