|
|
//=============================================================================
//
// Copyright (c) 1996-1999, Microsoft Corporation, All rights reserved
//
// CONPROV.CPP
//
// This file implements the classes for event consumer provider caching.
//
// Classes implemented:
//
// CConsumerProviderRecord --- a single consumer provider record
// CConsumerProviderCache --- a collection of records.
//
// History:
//
// 11/27/96 a-levn Compiles.
//
//=============================================================================
#include "precomp.h"
#include "ess.h"
#include "consprov.h"
#include <genutils.h>
#include <cominit.h>
#include "NCEvents.h"
CConsumerProviderRecord::CConsumerProviderRecord(CEssNamespace* pNamespace) : m_pLogicalProvider(NULL), m_pConsumerProvider(NULL), m_pSink(NULL), m_bResolved(FALSE), m_pNamespace(pNamespace), m_lRef(0), m_wszMachineName(NULL), m_wszProviderName(NULL), m_wszProviderRef(NULL), m_bAnonymous(FALSE) { m_pNamespace->AddRef(); }
HRESULT CConsumerProviderRecord::Initialize( IWbemClassObject* pLogicalProvider, LPCWSTR wszProviderRef, LPCWSTR wszProviderName, LPCWSTR wszMachineName) { m_LastAccess = CWbemTime::GetCurrentTime();
m_pLogicalProvider = pLogicalProvider; m_pLogicalProvider->AddRef();
if(wszMachineName) m_wszMachineName = CloneWstr(wszMachineName);
m_wszProviderName = CloneWstr(wszProviderName); m_wszProviderRef = CloneWstr(wszProviderRef);
if(m_wszProviderName == NULL || m_wszProviderRef == NULL) return WBEM_E_OUT_OF_MEMORY;
// Extract the CLSID
// =================
VARIANT vClassId; VariantInit(&vClassId); CClearMe cm(&vClassId);
HRESULT hres = pLogicalProvider->Get(CONSPROV_CLSID_PROPNAME, 0, &vClassId, NULL, NULL);
if(FAILED(hres) || V_VT(&vClassId) != VT_BSTR) { ERRORTRACE((LOG_ESS, "Class ID is missing from consumer " "provider record!!\n")); return hres; }
if(FAILED(CLSIDFromString(V_BSTR(&vClassId), &m_clsid))) { ERRORTRACE((LOG_ESS, "INVALID Class ID in consumer " "provider record!!\n")); return WBEM_E_INVALID_PROVIDER_REGISTRATION; }
return WBEM_S_NO_ERROR; }
CConsumerProviderRecord::~CConsumerProviderRecord() { _DBG_ASSERT( m_pNamespace != NULL );
if(m_pLogicalProvider) m_pLogicalProvider->Release(); if(m_pSink) m_pNamespace->PostponeRelease(m_pSink); if(m_pConsumerProvider) m_pNamespace->PostponeRelease(m_pConsumerProvider); if(m_pSink || m_pConsumerProvider) { //
// Report the MSFT_WmiConsumerProviderUnloaded event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiConsumerProviderUnloaded], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_pNamespace->GetName(), m_wszProviderName, m_wszMachineName); } if(m_pNamespace) m_pNamespace->Release(); delete [] m_wszMachineName; delete [] m_wszProviderName; delete [] m_wszProviderRef; }
long CConsumerProviderRecord::AddRef() { return InterlockedIncrement(&m_lRef); }
long CConsumerProviderRecord::Release() { long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; }
void CConsumerProviderRecord::Invalidate() { IWbemUnboundObjectSink* pSink; IWbemEventConsumerProvider* pConsumerProvider;
{ CInCritSec ics(&m_cs);
pSink = m_pSink; m_pSink = NULL;
pConsumerProvider = m_pConsumerProvider; m_pConsumerProvider = NULL;
m_bResolved = FALSE; } _DBG_ASSERT( m_pNamespace != NULL );
if (pSink) m_pNamespace->PostponeRelease(pSink); if (pConsumerProvider) m_pNamespace->PostponeRelease(pConsumerProvider);
if (pConsumerProvider || pSink) { //
// Report the MSFT_WmiConsumerProviderUnloaded event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiConsumerProviderUnloaded], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_pNamespace->GetName(), m_wszProviderName, m_wszMachineName); } }
HRESULT CConsumerProviderRecord::ValidateConsumer( IWbemClassObject* pLogicalConsumer) { HRESULT hres;
// Check if consumer provider is cached
// ====================================
IWbemEventConsumerProvider* pConsumerProvider = NULL; IWbemEventConsumerProviderEx* pConsumerProviderEx = NULL;
BOOL bResolved = FALSE; { CInCritSec ics(&m_cs); m_LastAccess = CWbemTime::GetCurrentTime();
if(m_bResolved) { if(m_pConsumerProviderEx) { pConsumerProviderEx = m_pConsumerProviderEx; pConsumerProviderEx->AddRef(); } else { pConsumerProvider = m_pConsumerProvider; if(pConsumerProvider) pConsumerProvider->AddRef(); }
bResolved = TRUE; } }
// Resolve if not cached
// =====================
if(!bResolved) { IWbemUnboundObjectSink* pGlobalSink;
hres = ResolveAndCache(&pGlobalSink, &pConsumerProvider, &pConsumerProviderEx); if(FAILED(hres)) return hres;
if(pGlobalSink) pGlobalSink->Release(); }
CReleaseMe rm1(pConsumerProvider); CReleaseMe rm2(pConsumerProviderEx);
if(pConsumerProvider == NULL && pConsumerProviderEx) { //
// Clearly, this consumer does not support validation
//
return WBEM_S_FALSE; }
try { if(pConsumerProviderEx) { hres = pConsumerProviderEx->ValidateSubscription(pLogicalConsumer); } else { //
// Old-type provider --- we can still achieve validation by calling
// FindConsumer --- it might reject this consumer at that time
//
IWbemUnboundObjectSink* pSink = NULL; hres = pConsumerProvider->FindConsumer(pLogicalConsumer, &pSink); if(SUCCEEDED(hres) && pSink) pSink->Release(); } } catch(...) { ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S " "threw an exception in ValidateConsumer/FindConsumer\n", m_wszProviderName, m_pNamespace->GetName())); hres = WBEM_E_PROVIDER_FAILURE; }
return hres; }
HRESULT CConsumerProviderRecord::GetGlobalObjectSink( OUT IWbemUnboundObjectSink** ppSink, IN IWbemClassObject *pLogicalProvider) { *ppSink = NULL;
// Check of a cached version is available
// ======================================
{ CInCritSec ics(&m_cs); m_LastAccess = CWbemTime::GetCurrentTime();
if(m_bResolved) { // It is --- return it
// ===================
*ppSink = m_pSink; if(m_pSink) m_pSink->AddRef(); return WBEM_S_NO_ERROR; } }
// No cached version --- retrieve it
// =================================
IWbemUnboundObjectSink* pSink; IWbemEventConsumerProvider* pConsumerProvider; IWbemEventConsumerProviderEx* pConsumerProviderEx;
HRESULT hres = ResolveAndCache(&pSink, &pConsumerProvider, &pConsumerProviderEx); if(FAILED(hres)) return hres;
if(pConsumerProvider) pConsumerProvider->Release(); if(pConsumerProviderEx) pConsumerProviderEx->Release(); *ppSink = pSink;
if (*ppSink != NULL) { //
// Report the MSFT_WmiConsumerProviderSinkLoaded event.
//
FireNCSinkEvent( MSFT_WmiConsumerProviderSinkLoaded, pLogicalProvider); }
return WBEM_S_NO_ERROR; }
HRESULT CConsumerProviderRecord::ResolveAndCache( IWbemUnboundObjectSink** ppSink, IWbemEventConsumerProvider** ppConsumerProvider, IWbemEventConsumerProviderEx** ppConsumerProviderEx) { // Resolve it first
// ================
HRESULT hres = Resolve(ppSink, ppConsumerProvider, ppConsumerProviderEx); if(FAILED(hres)) return hres;
// Cache if needed
// ===============
{ CInCritSec ics(&m_cs); m_LastAccess = CWbemTime::GetCurrentTime(); if(m_bResolved) { // Already cached. Release ours.
// ==============================
if(*ppSink) (*ppSink)->Release(); if(*ppConsumerProvider) (*ppConsumerProvider)->Release(); if(*ppConsumerProviderEx) (*ppConsumerProviderEx)->Release();
// Use the cached one
// ==================
*ppSink = m_pSink; if(m_pSink) m_pSink->AddRef();
*ppConsumerProvider = m_pConsumerProvider; if(m_pConsumerProvider) m_pConsumerProvider->AddRef();
*ppConsumerProviderEx = m_pConsumerProviderEx; if(m_pConsumerProviderEx) m_pConsumerProviderEx->AddRef(); } else { // Cache it
// ========
m_pSink = *ppSink; if(m_pSink) m_pSink->AddRef();
m_pConsumerProvider = *ppConsumerProvider; if(m_pConsumerProvider) m_pConsumerProvider->AddRef();
m_pConsumerProviderEx = *ppConsumerProviderEx; if(m_pConsumerProviderEx) m_pConsumerProviderEx->AddRef(); m_bResolved = TRUE; } }
return S_OK; }
void CConsumerProviderRecord::FireNCSinkEvent( DWORD dwIndex, IWbemClassObject *pLogicalConsumer) { if (IS_NCEVENT_ACTIVE(dwIndex)) { // Get the path of the logical consumer.
VARIANT vPath; BSTR strLogicalConsumerPath; VariantInit(&vPath);
if (pLogicalConsumer && SUCCEEDED(pLogicalConsumer->Get(L"__PATH", 0, &vPath, NULL, NULL))) strLogicalConsumerPath = V_BSTR(&vPath); else strLogicalConsumerPath = NULL;
//
// Report the event.
//
FIRE_NCEVENT( g_hNCEvents[dwIndex], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_pNamespace->GetName(), m_wszProviderName, m_wszMachineName, strLogicalConsumerPath); VariantClear(&vPath); } }
HRESULT CConsumerProviderRecord::FindConsumer( IN IWbemClassObject* pLogicalConsumer, OUT IWbemUnboundObjectSink** ppSink) { HRESULT hres;
// Check if consumer provider is cached
// ====================================
IWbemEventConsumerProvider* pConsumerProvider = NULL; BOOL bResolved = FALSE; { CInCritSec ics(&m_cs); m_LastAccess = CWbemTime::GetCurrentTime();
if(m_bResolved) { pConsumerProvider = m_pConsumerProvider; if(pConsumerProvider) pConsumerProvider->AddRef();
bResolved = TRUE; } }
// Resolve if not cached
// =====================
if(!bResolved) { IWbemUnboundObjectSink* pGlobalSink; IWbemEventConsumerProviderEx* pConsumerProviderEx = NULL;
hres = ResolveAndCache(&pGlobalSink, &pConsumerProvider, &pConsumerProviderEx); if(FAILED(hres)) return hres;
if(pGlobalSink) pGlobalSink->Release(); if(pConsumerProviderEx) pConsumerProviderEx->Release(); }
if(pConsumerProvider == NULL) return E_NOINTERFACE;
try { hres = pConsumerProvider->FindConsumer(pLogicalConsumer, ppSink); } catch(...) { ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S " "threw an exception in FindConsumer\n", m_wszProviderName, m_pNamespace->GetName())); hres = WBEM_E_PROVIDER_FAILURE; }
if(SUCCEEDED(hres) && ppSink != NULL) { if(*ppSink == NULL) { ERRORTRACE((LOG_ESS, "Event consumer provider %S in namespace %S " "returned success from IWbemEventConsumerProvider::FindConsumer" " call while returning a NULL sink. This behavior is invalid! " " Consumers will not receive events.\n", m_wszProviderName, m_pNamespace->GetName())); return E_NOINTERFACE; }
//
// Report the MSFT_WmiConsumerProviderSinkLoaded event.
//
FireNCSinkEvent( MSFT_WmiConsumerProviderSinkLoaded, pLogicalConsumer);
// Configure proxy settings
// ========================
if(m_bAnonymous) { hres = SetInterfaceSecurity(*ppSink, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS); } else { hres = WbemSetDynamicCloaking(*ppSink, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IDENTIFY); } if(FAILED(hres)) return hres; else hres = WBEM_S_NO_ERROR;
} pConsumerProvider->Release();
return hres; }
HRESULT CConsumerProviderRecord::Resolve( IWbemUnboundObjectSink** ppSink, IWbemEventConsumerProvider** ppConsumerProvider, IWbemEventConsumerProviderEx** ppConsumerProviderEx) { HRESULT hres;
// Prepare for CoCreateInstance(Ex)
// ================================
COSERVERINFO* pServerInfo = NULL; DWORD dwClsCtx; if(m_wszMachineName) { pServerInfo = _new COSERVERINFO; if(pServerInfo == NULL) return WBEM_E_OUT_OF_MEMORY; pServerInfo->pwszName = m_wszMachineName; pServerInfo->pAuthInfo = NULL; pServerInfo->dwReserved1 = 0; pServerInfo->dwReserved2 = 0; dwClsCtx = CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER; } else { dwClsCtx = CLSCTX_ALL; }
CDeleteMe<COSERVERINFO> dm(pServerInfo); IUnknown* pProtoSink = NULL; if(m_wszMachineName) { //
// Remote activation --- do everything ourselves
//
IClassFactory* pFactory; hres = WbemCoGetClassObject(m_clsid, dwClsCtx, pServerInfo, IID_IClassFactory, (void**)&pFactory); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Failed to get a class factory for CLSID on server %S. " "Return code %X\n", (pServerInfo?pServerInfo->pwszName:L"(local)"), hres)); return hres; } CReleaseMe rm0(pFactory); if(pFactory == NULL) { ERRORTRACE((LOG_ESS, "NULL Class Factory received from event consumer " "%S. Consumer needs to have its code examined\n", m_wszProviderName)); return WBEM_E_PROVIDER_LOAD_FAILURE; } // Get the instance
// ================
hres = pFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pProtoSink); if(FAILED(hres)) { //
// Try again at lower security
//
SetInterfaceSecurity(pFactory, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS); hres = pFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pProtoSink); if(SUCCEEDED(hres)) m_bAnonymous = TRUE; } if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Failed to create an instance from a class factory for %S. " " Return code: %X\n", m_wszProviderName, hres)); return hres; } if(pProtoSink == NULL) { ERRORTRACE((LOG_ESS, "NULL object received from event consumer " "%S factory. Consumer needs to have its code examined\n", m_wszProviderName)); return WBEM_E_PROVIDER_LOAD_FAILURE; } } else // not REMOTE_SERVER
{ //
// Use PSS
//
hres = m_pNamespace->LoadConsumerProvider(m_wszProviderName, &pProtoSink); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "ESS unable to load consumer provider %S from " "provider subsystem: 0x%X\n", (LPCWSTR)m_wszProviderName, hres)); return hres; } }
CReleaseMe rm1(pProtoSink);
if(m_bAnonymous) SetInterfaceSecurity(pProtoSink, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS);
// Query for the interfaces
// ========================
*ppSink = NULL; hres = pProtoSink->QueryInterface(IID_IWbemUnboundObjectSink, (void**)ppSink); if(FAILED(hres)) { DEBUGTRACE((LOG_ESS, "Consumer provider %S does not support " "IWbemUnboundObjectSink: error code %X\n", m_wszProviderName, hres)); } else { if(*ppSink == NULL) { ERRORTRACE((LOG_ESS, "NULL object received from event consumer " "%S QueryInterface. Consumer needs to have its code examined\n", m_wszProviderName)); return WBEM_E_PROVIDER_LOAD_FAILURE; }
// Configure proxy settings
// ========================
if(m_bAnonymous) { hres = SetInterfaceSecurity(*ppSink, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS); } else { hres = WbemSetDynamicCloaking(*ppSink, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IDENTIFY); } if(FAILED(hres)) return hres; }
*ppConsumerProvider = NULL; hres = pProtoSink->QueryInterface(IID_IWbemEventConsumerProvider, (void**)ppConsumerProvider); if(FAILED(hres)) { } else if(*ppConsumerProvider == NULL) { ERRORTRACE((LOG_ESS, "NULL object received from event consumer " "%S QueryInterface. Consumer needs to have its code examined\n", m_wszProviderName));
return WBEM_E_PROVIDER_LOAD_FAILURE; } else { if(m_bAnonymous) SetInterfaceSecurity(*ppConsumerProvider, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS); }
*ppConsumerProviderEx = NULL; hres = pProtoSink->QueryInterface(IID_IWbemEventConsumerProviderEx, (void**)ppConsumerProviderEx); if(FAILED(hres)) { } else if(*ppConsumerProviderEx == NULL) { ERRORTRACE((LOG_ESS, "NULL object received from event consumer " "%S QueryInterface. Consumer needs to have its code examined\n", m_wszProviderName));
return WBEM_E_PROVIDER_LOAD_FAILURE; } else { if(m_bAnonymous) SetInterfaceSecurity(*ppConsumerProviderEx, NULL, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS); }
// Inform the cache that unloading may be required
// ===============================================
m_pNamespace->GetConsumerProviderCache().EnsureUnloadInstruction();
//
// Report the MSFT_WmiConsumerProviderLoaded event.
//
FIRE_NCEVENT( g_hNCEvents[MSFT_WmiConsumerProviderLoaded], WMI_SENDCOMMIT_SET_NOT_REQUIRED,
// Data follows...
m_pNamespace->GetName(), m_wszProviderName, m_wszMachineName);
return S_OK; }
CConsumerProviderCache::~CConsumerProviderCache() { if(m_pInstruction) { m_pInstruction->Terminate(); m_pInstruction->Release(); } }
BOOL CConsumerProviderCache::DoesContain(IWbemClassObject* pProvReg, IWbemClassObject* pConsumerReg) { HRESULT hres;
// Get its class list
// ==================
VARIANT v; VariantInit(&v); CClearMe cm(&v);
hres = pProvReg->Get(L"ConsumerClassNames", 0, &v, NULL, NULL);
if(SUCCEEDED(hres) && V_VT(&v) == (VT_BSTR | VT_ARRAY)) { SAFEARRAY* psa = V_ARRAY(&v); long lLBound, lUBound; BSTR* astrData; SafeArrayGetLBound(psa, 1, &lLBound); SafeArrayGetUBound(psa, 1, &lUBound); SafeArrayAccessData(psa, (void**)&astrData); CUnaccessMe um(psa); for(int i = 0; i <= lUBound - lLBound; i++) { if(pConsumerReg->InheritsFrom(astrData[i]) == S_OK) return TRUE; } }
return FALSE; } //
// Need a class for dynamic enumeration of consumer provider registrations
//
class CProviderRegistrationSink : public CObjectSink { protected: CConsumerProviderCache* m_pCache; IWbemClassObject* m_pLogicalConsumer; IWbemClassObject** m_ppReg; public: CProviderRegistrationSink(CConsumerProviderCache* pCache, IWbemClassObject* pLogicalConsumer, IWbemClassObject** ppReg) : m_pCache(pCache), m_pLogicalConsumer(pLogicalConsumer), m_ppReg(ppReg) { AddRef(); // same thread --- no need to AddRef paramters
} ~CProviderRegistrationSink(){} STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects) { for(long i = 0; i < lNumObjects; i++) { //
// Check if this one is ours
//
if(m_pCache->DoesContain(apObjects[i], m_pLogicalConsumer)) { *m_ppReg = apObjects[i]; (*m_ppReg)->AddRef(); return WBEM_E_CALL_CANCELLED; } } return WBEM_S_NO_ERROR; } };
INTERNAL CConsumerProviderRecord* CConsumerProviderCache::GetRecord(IN IWbemClassObject* pLogicalConsumer) { CInCritSec ics(&m_cs); HRESULT hres;
//
// Enumerate all the registrations into a sink that will check if this
// one is the right one
//
IWbemClassObject* pReg = NULL; CProviderRegistrationSink Sink(this, pLogicalConsumer, &pReg);
hres = m_pNamespace->CreateInstanceEnum( CONSUMER_PROVIDER_REGISTRATION_CLASS, 0, &Sink);
if(pReg == NULL) { // Not found
return NULL; } CReleaseMe rm1(pReg);
// Get the Win32Provider record
// ============================
VARIANT vPath; hres = pReg->Get(CONSPROV_PROVIDER_REF_PROPNAME, 0, &vPath, NULL, NULL); if(FAILED(hres) || V_VT(&vPath) != VT_BSTR) { ERRORTRACE((LOG_ESS, "Event consumer provider registration is invalid: " "Provider property is missing\n")); return NULL; }
INTERNAL BSTR strProviderRef = V_BSTR(&vPath); CClearMe cm2(&vPath);
_IWmiObject* pProv = NULL; hres = m_pNamespace->GetInstance(V_BSTR(&vPath), &pProv); if(FAILED(hres)) { ERRORTRACE((LOG_ESS, "Invalid event consumer provider registration: " "dangling provider reference %S\n", V_BSTR(&vPath))); return NULL; }
CReleaseMe rm(pProv);
// Get the name of the provider
// ============================
VARIANT vProvName; VariantInit(&vProvName); CClearMe cm3(&vProvName);
hres = pProv->Get(PROVIDER_NAME_PROPNAME, 0, &vProvName, NULL, NULL); if(FAILED(hres) || V_VT(&vProvName) != VT_BSTR) { ERRORTRACE((LOG_ESS, "Event provider registration without a name at " "%S\n", V_BSTR(&vPath))); return NULL; } INTERNAL BSTR strProviderName = V_BSTR(&vProvName);
// Get the machine name
// ====================
VARIANT vMachine; VariantInit(&vMachine); CClearMe cm4(&vMachine);
hres = pLogicalConsumer->Get(CONSUMER_MACHINE_NAME_PROPNAME, 0, &vMachine, NULL, NULL); if(FAILED(hres)) return NULL;
INTERNAL BSTR strMachineName = NULL; if(V_VT(&vMachine) != VT_NULL) strMachineName = V_BSTR(&vMachine);
// Search for the record
// =====================
BOOL bFound = FALSE; CConsumerProviderRecord* pRecord; for(int i = 0; i < m_apRecords.GetSize(); i++) { pRecord = m_apRecords[i];
if(wbem_wcsicmp(pRecord->GetProviderName(), strProviderName)) continue; if(pRecord->GetMachineName() && strMachineName) { if(wbem_wcsicmp(pRecord->GetMachineName(), strMachineName)) continue; } else { if(pRecord->GetMachineName() != strMachineName) continue; }
bFound = TRUE; break; }
if(!bFound) { pRecord = new CConsumerProviderRecord(m_pNamespace); if(pRecord == NULL) return NULL; hres = pRecord->Initialize(pProv, strProviderRef, strProviderName, strMachineName); if(m_apRecords.Add(pRecord) < 0) { delete pRecord; return NULL; } }
pRecord->AddRef(); return pRecord; }
void CConsumerProviderCache::EnsureUnloadInstruction() { CInCritSec ics(&m_cs);
if(m_pInstruction == NULL) { m_pInstruction = new CConsumerProviderWatchInstruction(this); if(m_pInstruction) { m_pInstruction->AddRef(); m_pNamespace->GetTimerGenerator().Set(m_pInstruction); } } }
HRESULT CConsumerProviderCache::UnloadUnusedProviders(CWbemInterval Interval) { CRefedPointerArray<CConsumerProviderRecord> apToInvalidate; BOOL bUnloaded = FALSE;
{ CInCritSec ics(&m_cs); BOOL bActiveLeft = FALSE; for(int i = 0; i < m_apRecords.GetSize(); i++) { CConsumerProviderRecord* pRecord = m_apRecords[i]; // Prevent the record from being used while its fate is determined
// ===============================================================
if(pRecord->IsActive()) { if(CWbemTime::GetCurrentTime() - pRecord->GetLastAccess() > Interval) { apToInvalidate.Add(pRecord); DEBUGTRACE((LOG_ESS, "Unloading consumer provider %S on " "%S\n", pRecord->GetProviderName(), pRecord->GetMachineName())); bUnloaded = TRUE; } else bActiveLeft = TRUE; } }
if(m_pInstruction && !bActiveLeft) { m_pInstruction->Terminate(); m_pInstruction->Release(); m_pInstruction = NULL; } } // Actually unload
// ===============
for(int i = 0; i < apToInvalidate.GetSize(); i++) { apToInvalidate[i]->Invalidate(); }
if(bUnloaded) m_pNamespace->GetTimerGenerator().ScheduleFreeUnusedLibraries(); return WBEM_S_NO_ERROR; }
HRESULT CConsumerProviderCache::RemoveConsumerProvider(LPCWSTR wszProviderRef) { CInCritSec ics(&m_cs); for(int i = 0; i < m_apRecords.GetSize(); i++) { CConsumerProviderRecord* pRecord = m_apRecords[i]; if(!wbem_wcsicmp(pRecord->GetProviderRef(), wszProviderRef)) { // Matches --- remove
// ==================
DEBUGTRACE((LOG_ESS, "Removing consumer provider record: %S in %S" "\n", m_pNamespace->GetName(), wszProviderRef));
m_apRecords.RemoveAt(i); i--; } }
return WBEM_S_NO_ERROR; }
// static
SYSFREE_ME BSTR CConsumerProviderCache::GetProviderRefFromRecord( IWbemClassObject* pReg) { VARIANT v; VariantInit(&v); if(FAILED(pReg->Get(CONSPROV_PROVIDER_REF_PROPNAME, 0, &v, NULL, NULL)) || V_VT(&v) != VT_BSTR) { VariantClear(&v); return NULL; } else { // Variant intentionally not cleared
return V_BSTR(&v); } }
class CSingleElementSink : public CObjectSink { protected: IWbemClassObject** m_ppObj; public: CSingleElementSink(IWbemClassObject** ppObj) : m_ppObj(ppObj) { AddRef(); }
STDMETHOD(Indicate)(long lNumObjects, IWbemClassObject** apObjects) { if(lNumObjects > 0) { *m_ppObj = apObjects[0]; apObjects[0]->AddRef(); } return S_OK; } };
HRESULT CConsumerProviderCache::GetConsumerProviderRegFromProviderReg( IWbemClassObject* pProv, IWbemClassObject** ppConsProv) { HRESULT hres;
// Get the path
// ============
VARIANT vPath; VariantInit(&vPath); if(FAILED(pProv->Get(L"__RELPATH", 0, &vPath, NULL, NULL)) || V_VT(&vPath) != VT_BSTR) { return WBEM_E_INVALID_PROVIDER_REGISTRATION; } WString wsPath = WString(V_BSTR(&vPath)).EscapeQuotes(); VariantClear(&vPath);
// Construct the query
// ===================
DWORD cLen = wsPath.Length()*2 + 100; BSTR strQuery = SysAllocStringLen( NULL, cLen );
if ( NULL == strQuery ) { return WBEM_E_OUT_OF_MEMORY; }
CSysFreeMe sfm(strQuery);
StringCchPrintfW( strQuery, cLen, L"select * from " CONSUMER_PROVIDER_REGISTRATION_CLASS L" where " L"Provider = \"%s\"", (LPWSTR)wsPath); // Issue the query
// ===============
*ppConsProv = NULL; CSingleElementSink Sink(ppConsProv); hres = m_pNamespace->ExecQuery(strQuery, 0, &Sink); if(FAILED(hres)) return hres; else if(*ppConsProv == NULL) return WBEM_E_NOT_FOUND; else return WBEM_S_NO_ERROR; } void CConsumerProviderCache::Clear() { CInCritSec ics(&m_cs);
m_apRecords.RemoveAll(); if(m_pInstruction) { m_pInstruction->Terminate(); m_pInstruction->Release(); m_pInstruction = NULL; } }
void CConsumerProviderCache::DumpStatistics(FILE* f, long lFlags) { fprintf(f, "%d consumer provider records\n", m_apRecords.GetSize()); }
// static
CWbemInterval CConsumerProviderWatchInstruction::mstatic_Interval; void CConsumerProviderWatchInstruction::staticInitialize(IWbemServices* pRoot) { mstatic_Interval = CBasicUnloadInstruction::staticRead(pRoot, GetCurrentEssContext(), L"__EventConsumerProviderCacheControl=@"); }
CConsumerProviderWatchInstruction::CConsumerProviderWatchInstruction( CConsumerProviderCache* pCache) : CBasicUnloadInstruction(mstatic_Interval), m_pCache(pCache) {}
HRESULT CConsumerProviderWatchInstruction::Fire(long, CWbemTime) { if(!m_bTerminate) { CEssThreadObject Obj(NULL); SetConstructedEssThreadObject(&Obj); m_pCache->UnloadUnusedProviders(m_Interval);
m_pCache->m_pNamespace->FirePostponedOperations(); ClearCurrentEssThreadObject(); return WBEM_S_NO_ERROR; } else return WBEM_S_FALSE; }
|