2025-04-27 07:49:33 -04:00

2678 lines
81 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
REFRCLI.CPP
Abstract:
Refresher Client Side Code.
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <process.h>
#include <wbemcomn.h>
#include <fastall.h>
#include <hiperfenum.h>
#include <refrenum.h>
#include <refrcli.h>
#include <sync.h>
#include <provinit.h>
#include <cominit.h>
//*****************************************************************************
//*****************************************************************************
// XCREATE
//*****************************************************************************
//*****************************************************************************
STDMETHODIMP CUniversalRefresher::XCreate::AddObjectByPath(
IWbemServices* pNamespace, LPCWSTR wszPath,
long lFlags, IWbemContext* pContext,
IWbemClassObject** ppRefreshable, long* plId)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Check for invalid parameters
if ( NULL == pNamespace || NULL == wszPath || NULL == ppRefreshable || NULL == *wszPath )
{
return WBEM_E_INVALID_PARAMETER;
}
// Validate flags
if ( ( lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS ) )
{
return WBEM_E_INVALID_PARAMETER;
}
// Make sure we are able to acquire the spinlock.
// The destructor will unlock us if we get access
CHiPerfLockAccess lock( &m_pObject->m_Lock );
if ( lock.IsLocked() )
{
// Acquire internal connection to WINMGMT
// ====================================
IWbemRefreshingServices* pRefServ = NULL;
// Storage for security settings we will need in order to propagate
// down to our internal interfaces.
COAUTHINFO CoAuthInfo;
// Make sure this is totally empty
ZeroMemory( &CoAuthInfo, sizeof(CoAuthInfo) );
hres = m_pObject->GetRefreshingServices( pNamespace, &pRefServ, &CoAuthInfo );
if ( FAILED( hres ) )
{
return hres;
}
// This guarantees this will be freed when we drop out of scope. If we store
// it we will need to allocate an internal copy.
CMemFreeMe mfm( CoAuthInfo.pwszServerPrincName );
// Forward this request
// ====================
CRefreshInfo Info;
DWORD dwRemoteRefrVersion = 0;
hres = pRefServ->AddObjectToRefresher(&m_pObject->m_Id, wszPath, lFlags,
pContext, WBEM_REFRESHER_VERSION, &Info, &dwRemoteRefrVersion);
if(FAILED(hres))
{
pRefServ->Release();
return hres;
}
// Act on the information
// ======================
switch(Info.m_lType)
{
case WBEM_REFRESH_TYPE_CLIENT_LOADABLE:
hres = m_pObject->AddClientLoadable(Info.m_Info.m_ClientLoadable,
pNamespace, ppRefreshable, plId);
break;
case WBEM_REFRESH_TYPE_DIRECT:
hres = m_pObject->AddDirect(Info.m_Info.m_Direct,
pNamespace, ppRefreshable, plId);
break;
case WBEM_REFRESH_TYPE_REMOTE:
if ( SUCCEEDED( hres ) )
{
hres = m_pObject->AddRemote( pRefServ, Info.m_Info.m_Remote, wszPath,
Info.m_lCancelId, ppRefreshable, plId, &CoAuthInfo);
}
break;
default:
hres = WBEM_E_INVALID_OPERATION;
}
pRefServ->Release();
}
else
{
hres = WBEM_E_REFRESHER_BUSY;
}
return hres;
}
STDMETHODIMP CUniversalRefresher::XCreate::AddObjectByTemplate(
IWbemServices* pNamespace,
IWbemClassObject* pTemplate,
long lFlags, IWbemContext* pContext,
IWbemClassObject** ppRefreshable, long* plId)
{
// Check for invalid parameters
if ( NULL == pNamespace || NULL == pTemplate || NULL == ppRefreshable || 0L != lFlags )
{
return WBEM_E_INVALID_PARAMETER;
}
// Check that this is an instance object
if ( ! ((CWbemObject*)pTemplate)->IsInstance() )
{
return WBEM_E_INVALID_PARAMETER;
}
CVar vPath;
((CWbemObject*)pTemplate)->GetRelPath(&vPath);
return AddObjectByPath(pNamespace, vPath.GetLPWSTR(), lFlags, pContext,
ppRefreshable, plId);
}
STDMETHODIMP CUniversalRefresher::XCreate::AddRefresher(
IWbemRefresher* pRefresher, long lFlags, long* plId)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Check for invalid parameters
if ( NULL == pRefresher || 0L != lFlags )
{
return WBEM_E_INVALID_PARAMETER;
}
// Make sure we are able to acquire the spinlock.
// The destructor will unlock us if we get access
CHiPerfLockAccess lock( &m_pObject->m_Lock );
if ( lock.IsLocked() )
{
hres = m_pObject->AddRefresher( pRefresher, lFlags, plId );
}
else
{
hres = WBEM_E_REFRESHER_BUSY;
}
return hres;
}
STDMETHODIMP CUniversalRefresher::XCreate::Remove(long lId, long lFlags)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Check for invalid flag values
if ( ( lFlags & ~WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT ) )
{
return WBEM_E_INVALID_PARAMETER;
}
// Make sure we are able to acquire the spinlock.
// The destructor will unlock us if we get access
CHiPerfLockAccess lock( &m_pObject->m_Lock );
if ( lock.IsLocked() )
{
hres = m_pObject->Remove(lId, lFlags);
}
else
{
hres = WBEM_E_REFRESHER_BUSY;
}
return hres;
}
HRESULT CUniversalRefresher::XCreate::AddEnum( IWbemServices* pNamespace, LPCWSTR wszClassName,
long lFlags, IWbemContext* pContext, IWbemHiPerfEnum** ppEnum,
long* plId)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Check for invalid parameters
if ( NULL == pNamespace || NULL == wszClassName || NULL == ppEnum || NULL == *wszClassName )
{
return WBEM_E_INVALID_PARAMETER;
}
// Validate flags
if ( ( lFlags & ~WBEM_FLAG_USE_AMENDED_QUALIFIERS ) )
{
return WBEM_E_INVALID_PARAMETER;
}
// Make sure we are able to acquire the spinlock.
// The destructor will unlock us if we get access
CHiPerfLockAccess lock( &m_pObject->m_Lock );
if ( lock.IsLocked() )
{
// Acquire internal connection to WINMGMT
// ====================================
IWbemRefreshingServices* pRefServ = NULL;
// Storage for security settings we will need in order to propagate
// down to our internal interfaces.
COAUTHINFO CoAuthInfo;
// Make sure this is totally empty
ZeroMemory( &CoAuthInfo, sizeof(CoAuthInfo) );
hres = m_pObject->GetRefreshingServices( pNamespace, &pRefServ, &CoAuthInfo );
if ( FAILED( hres ) )
{
return hres;
}
// This guarantees this will be freed when we drop out of scope
CMemFreeMe mfm( CoAuthInfo.pwszServerPrincName );
// Forward this request
// ====================
CRefreshInfo Info;
DWORD dwRemoteRefrVersion = 0;
hres = pRefServ->AddEnumToRefresher(&m_pObject->m_Id, wszClassName, lFlags,
pContext, WBEM_REFRESHER_VERSION, &Info, &dwRemoteRefrVersion);
if(FAILED(hres))
{
pRefServ->Release();
return hres;
}
// Act on the information
// ======================
switch(Info.m_lType)
{
case WBEM_REFRESH_TYPE_CLIENT_LOADABLE:
hres = m_pObject->AddClientLoadableEnum(Info.m_Info.m_ClientLoadable,
pNamespace, wszClassName, ppEnum, plId);
break;
case WBEM_REFRESH_TYPE_DIRECT:
hres = m_pObject->AddDirectEnum(Info.m_Info.m_Direct,
pNamespace, wszClassName, ppEnum, plId);
break;
case WBEM_REFRESH_TYPE_REMOTE:
if ( SUCCEEDED( hres ) )
{
hres = m_pObject->AddRemoteEnum( pRefServ, Info.m_Info.m_Remote, wszClassName,
Info.m_lCancelId, ppEnum, plId, &CoAuthInfo );
}
break;
}
pRefServ->Release();
}
else
{
hres = WBEM_E_REFRESHER_BUSY;
}
return hres;
}
//*****************************************************************************
//*****************************************************************************
// XREFRESHER
//*****************************************************************************
//*****************************************************************************
STDMETHODIMP CUniversalRefresher::XRefresher::Refresh(long lFlags)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Check for invalid flag values
if ( ( lFlags & ~WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT ) )
{
return WBEM_E_INVALID_PARAMETER;
}
// Make sure we are able to acquire the spinlock.
// The destructor will unlock us if we get access
CHiPerfLockAccess lock( &m_pObject->m_Lock );
if ( lock.IsLocked() )
{
hres = m_pObject->Refresh(lFlags);
}
else
{
hres = WBEM_E_REFRESHER_BUSY;
}
return hres;
}
//*****************************************************************************
//*****************************************************************************
// UNIVERSAL REFRESHER
//*****************************************************************************
//*****************************************************************************
CUniversalRefresher::~CUniversalRefresher()
{
// When we are destructed, we need to make sure that any remote refreshers
// that may still be trying to reconnect on separate threads are silenced
for ( long lCtr = 0; lCtr < m_apRemote.GetSize(); lCtr++ )
{
CRemote* pRemote = m_apRemote.GetAt( lCtr );
if ( NULL != pRemote )
{
pRemote->Quit();
}
} // FOR enum refreshers
}
CClientLoadableProviderCache CUniversalRefresher::mstatic_Cache;
long CUniversalRefresher::mstatic_lLastId = 0;
long CUniversalRefresher::GetNewId()
{
return InterlockedIncrement(&mstatic_lLastId);
}
void* CUniversalRefresher::GetInterface(REFIID riid)
{
if(riid == IID_IUnknown || riid == IID_IWbemRefresher)
return &m_XRefresher;
else if(riid == IID_IWbemConfigureRefresher)
return &m_XCreate;
else
return NULL;
}
HRESULT CUniversalRefresher::GetRefreshingServices( IWbemServices* pNamespace,
IWbemRefreshingServices** ppRefSvc,
COAUTHINFO* pCoAuthInfo )
{
// Acquire internal connection to WINMGMT
// ====================================
HRESULT hres = pNamespace->QueryInterface(IID_IWbemRefreshingServices,
(void**) ppRefSvc);
if ( SUCCEEDED( hres ) )
{
// We will query the namespace for its security settings so we can propagate
// those settings onto our own internal interfaces.
hres = CoQueryProxyBlanket( pNamespace, &pCoAuthInfo->dwAuthnSvc, &pCoAuthInfo->dwAuthzSvc,
&pCoAuthInfo->pwszServerPrincName, &pCoAuthInfo->dwAuthnLevel,
&pCoAuthInfo->dwImpersonationLevel, (RPC_AUTH_IDENTITY_HANDLE*) &pCoAuthInfo->pAuthIdentityData,
&pCoAuthInfo->dwCapabilities );
if ( SUCCEEDED( hres ) )
{
hres = WbemSetProxyBlanket( *ppRefSvc, pCoAuthInfo->dwAuthnSvc, pCoAuthInfo->dwAuthzSvc,
pCoAuthInfo->pwszServerPrincName, pCoAuthInfo->dwAuthnLevel,
pCoAuthInfo->dwImpersonationLevel, pCoAuthInfo->pAuthIdentityData,
pCoAuthInfo->dwCapabilities );
}
else if ( E_NOINTERFACE == hres )
{
// If we are in-proc to WMI, then CoQueryProxyBlanket can fail, but this
// is not really an error, per se, so we will fake it.
hres = WBEM_S_NO_ERROR;
}
if ( FAILED( hres ) )
{
(*ppRefSvc)->Release();
*ppRefSvc = NULL;
}
} // IF QI
return hres;
}
HRESULT CUniversalRefresher::AddInProcObject(
CHiPerfProviderRecord* pProvider,
IWbemObjectAccess* pTemplate,
IWbemServices* pNamespace,
IWbemClassObject** ppRefreshable, long* plId)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Look for a provider record with this provider pointer
// =====================================================
CDirect* pFoundRec = NULL;
for(int i = 0; i < m_apDirect.GetSize(); i++)
{
CDirect* pDirectRec = m_apDirect[i];
if(pDirectRec->GetProvider() == pProvider)
{
pFoundRec = pDirectRec;
break;
}
}
if(pFoundRec == NULL)
{
// Create a new one
// ================
IWbemRefresher* pRefresher;
try
{
hres = pProvider->m_pProvider->CreateRefresher(pNamespace, 0, &pRefresher);
}
catch(...)
{
// Provider threw an exception, so get out of here ASAP
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres))
{
return hres;
}
pFoundRec = _new CDirect(pProvider, pRefresher);
m_apDirect.Add(pFoundRec);
pRefresher->Release();
}
// Add request in provider
// =======================
IWbemObjectAccess* pProviderObject;
long lProviderId;
// If the user specified the WBEM_FLAG_USE_AMENDED_QUALIFIERS flag, then
// IWbemRefreshingServices::AddObjectToRefresher will return a localized
// instance definition. Since localized stuff should all be in the class
// definition, the provider doesn't really "need" toknow that we're sneaking
// this in. To protect our object, we'll clone it BEFORE we pass it to
// the provider. The instance that is returned by the provider BETTER be of
// the same class type we are, however.
CWbemInstance* pClientInstance = NULL;
hres = pTemplate->Clone( (IWbemClassObject**) &pClientInstance );
if ( FAILED( hres ) )
{
return hres;
}
try
{
hres = pProvider->m_pProvider->CreateRefreshableObject(pNamespace, pTemplate,
pFoundRec->GetRefresher(), 0, NULL, &pProviderObject,
&lProviderId);
}
catch(...)
{
// Provider threw an exception, so get out of here ASAP
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres))
{
pClientInstance->Release();
return hres;
}
// Now copy the provider returned instance data.
hres = pClientInstance->CopyBlobOf( (CWbemInstance*) pProviderObject );
if ( SUCCEEDED( hres ) )
{
hres = pFoundRec->AddRequest((CWbemObject*)pProviderObject, pClientInstance, lProviderId,
ppRefreshable, plId);
}
pProviderObject->Release();
pClientInstance->Release();
return hres;
}
HRESULT CUniversalRefresher::AddInProcEnum(
CHiPerfProviderRecord* pProvider,
IWbemObjectAccess* pTemplate,
IWbemServices* pNamespace, LPCWSTR wszClassName,
IWbemHiPerfEnum** ppEnum, long* plId)
{
HRESULT hres = WBEM_S_NO_ERROR;
// Look for a provider record with this provider pointer
// =====================================================
CDirect* pFoundRec = NULL;
for(int i = 0; i < m_apDirect.GetSize(); i++)
{
CDirect* pDirectRec = m_apDirect[i];
if(pDirectRec->GetProvider() == pProvider)
{
pFoundRec = pDirectRec;
break;
}
}
if(pFoundRec == NULL)
{
// Create a new one
// ================
IWbemRefresher* pRefresher;
try
{
hres = pProvider->m_pProvider->CreateRefresher(pNamespace, 0, &pRefresher);
}
catch(...)
{
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres))
{
return hres;
}
pFoundRec = _new CDirect(pProvider, pRefresher);
m_apDirect.Add(pFoundRec);
pRefresher->Release();
}
// Add request in provider
// =======================
CClientLoadableHiPerfEnum* pHPEnum = new CClientLoadableHiPerfEnum( m_pControl );
if ( NULL != pHPEnum )
{
pHPEnum->AddRef();
// Auto-release this guy when we're done
CReleaseMe rmEnum( pHPEnum );
long lProviderId;
// If the user specified the WBEM_FLAG_USE_AMENDED_QUALIFIERS flag, then
// IWbemRefreshingServices::AddEnumToRefresher will return a localized
// instance definition. Since localized stuff should all be in the class
// definition, the provider doesn't really "need" toknow that we're sneaking
// this in.
hres = pHPEnum->SetInstanceTemplate( (CWbemInstance*) pTemplate );
if ( FAILED( hres ) )
{
return hres;
}
try
{
hres = pProvider->m_pProvider->CreateRefreshableEnum(pNamespace, (LPWSTR) wszClassName,
pFoundRec->GetRefresher(), 0, NULL, (IWbemHiPerfEnum*) pHPEnum,
&lProviderId );
}
catch(...)
{
// Provider threw an exception, so get out of here ASAP
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres))
{
return hres;
}
hres = pFoundRec->AddEnumRequest( pHPEnum, lProviderId,
ppEnum, plId, m_pControl );
}
return hres;
}
HRESULT CUniversalRefresher::AddClientLoadable(
const WBEM_REFRESH_INFO_CLIENT_LOADABLE& Info,
IWbemServices* pNamespace,
IWbemClassObject** ppRefreshable, long* plId)
{
// Get this provider pointer from the cache
// ========================================
CHiPerfProviderRecord* pProvider = NULL;
HRESULT hres = GetProviderCache()->FindProvider(Info.m_clsid,
Info.m_wszNamespace, pNamespace, &pProvider);
if(FAILED(hres) || pProvider == NULL) return hres;
// Now use the helper function to do the rest of the work
hres = AddInProcObject( pProvider, Info.m_pTemplate, pNamespace, ppRefreshable, plId );
pProvider->Release();
return hres;
}
HRESULT CUniversalRefresher::AddClientLoadableEnum(
const WBEM_REFRESH_INFO_CLIENT_LOADABLE& Info,
IWbemServices* pNamespace, LPCWSTR wszClassName,
IWbemHiPerfEnum** ppEnum, long* plId)
{
// Get this provider pointer from the cache
// ========================================
CHiPerfProviderRecord* pProvider = NULL;
HRESULT hres = GetProviderCache()->FindProvider(Info.m_clsid,
Info.m_wszNamespace, pNamespace, &pProvider);
if(FAILED(hres) || pProvider == NULL) return hres;
// Now use the helper function to do the rest of the work
hres = AddInProcEnum( pProvider, Info.m_pTemplate, pNamespace, wszClassName, ppEnum, plId );
pProvider->Release();
return hres;
}
HRESULT CUniversalRefresher::AddDirect(
const WBEM_REFRESH_INFO_DIRECT& Info,
IWbemServices* pNamespace,
IWbemClassObject** ppRefreshable, long* plId)
{
// Get this provider pointer from the cache
// ========================================
CHiPerfProviderRecord* pProvider = NULL;
HRESULT hres = GetProviderCache()->FindProvider(Info.m_clsid,
Info.m_pProvider, Info.m_wszNamespace, &pProvider);
if(FAILED(hres) || pProvider == NULL) return hres;
// Now use the helper function to do the rest of the work
hres = AddInProcObject( pProvider, Info.m_pTemplate, pNamespace, ppRefreshable, plId );
pProvider->Release();
return hres;
}
HRESULT CUniversalRefresher::AddDirectEnum(
const WBEM_REFRESH_INFO_DIRECT& Info,
IWbemServices* pNamespace, LPCWSTR wszClassName,
IWbemHiPerfEnum** ppEnum, long* plId)
{
// Get this provider pointer from the cache
// ========================================
CHiPerfProviderRecord* pProvider = NULL;
HRESULT hres = GetProviderCache()->FindProvider(Info.m_clsid,
Info.m_pProvider, Info.m_wszNamespace, &pProvider);
if(FAILED(hres) || pProvider == NULL) return hres;
// Now use the helper function to do the rest of the work
hres = AddInProcEnum( pProvider, Info.m_pTemplate, pNamespace, wszClassName, ppEnum, plId );
pProvider->Release();
return hres;
}
HRESULT CUniversalRefresher::FindRemoteEntry( const WBEM_REFRESH_INFO_REMOTE& Info,
COAUTHINFO* pAuthInfo,
CRemote** ppRemoteRecord )
{
// We will identify remote enumerations by server and namespace
CVar varNameSpace;
HRESULT hr = ((CWbemObject*) Info.m_pTemplate)->GetServerAndNamespace( &varNameSpace );
if ( FAILED( hr ) )
{
return hr;
}
else if ( NULL == varNameSpace.GetLPWSTR() )
{
// This shouldn't happen, but protect against it
return WBEM_E_FAILED;
}
// Look for this remote connection in our list
// ===========================================
CRemote* pFoundRec = NULL;
for(int i = 0; i < m_apRemote.GetSize(); i++)
{
CRemote* pRec = m_apRemote[i];
// Original code:
// if(pRec->GetRemoteRefresher() == Info.m_pRefresher)
if ( wbem_wcsicmp( varNameSpace.GetLPWSTR(), pRec->GetNamespace() ) == 0 )
{
pFoundRec = pRec;
if ( NULL != pFoundRec )
{
pFoundRec->AddRef();
}
break;
}
}
if(pFoundRec == NULL)
{
// Create a new one
// ================
// Watch for errors, and do appropriate cleanup
try
{
// Get the server info from the object. If this returns a NULL, it just
// means that we will be unable to reconnect
CVar varServer;
hr = ((CWbemObject*) Info.m_pTemplate)->GetServer( &varServer );
if ( SUCCEEDED( hr ) )
{
pFoundRec = _new CRemote(Info.m_pRefresher, pAuthInfo, &Info.m_guid,
varNameSpace.GetLPWSTR(), varServer.GetLPWSTR(), this );
// Set the scurity appropriately
hr = pFoundRec->ApplySecurity();
if ( SUCCEEDED( hr ) )
{
m_apRemote.Add(pFoundRec);
}
}
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( FAILED( hr ) )
{
// Release the pointer as we no longer need it
if ( NULL != pFoundRec )
{
pFoundRec->Release();
pFoundRec = NULL;
}
}
} // IF NULL == pFoundRec
*ppRemoteRecord = pFoundRec;
return hr;
}
HRESULT CUniversalRefresher::AddRemote( IWbemRefreshingServices* pRefServ, const WBEM_REFRESH_INFO_REMOTE& Info,
LPCWSTR pwcsRequestName, long lCancelId, IWbemClassObject** ppRefreshable,
long* plId, COAUTHINFO* pAuthInfo )
{
// Look for this remote connection in our list
// ===========================================
CRemote* pFoundRec = NULL;
HRESULT hr = FindRemoteEntry( Info, pAuthInfo, &pFoundRec );
if ( SUCCEEDED( hr ) )
{
if ( !pFoundRec->IsConnected() )
{
hr = pFoundRec->Rebuild( pRefServ, Info.m_pRefresher, &Info.m_guid );
}
if ( SUCCEEDED( hr ) )
{
// Add a request to it
// ===================
IWbemObjectAccess* pAccess = Info.m_pTemplate;
CWbemObject* pObj = (CWbemObject*)pAccess;
hr = pFoundRec->AddRequest(pObj, pwcsRequestName, lCancelId, ppRefreshable, plId);
}
// Release the record
pFoundRec->Release();
}
return hr;
}
HRESULT CUniversalRefresher::AddRemoteEnum( IWbemRefreshingServices* pRefServ,
const WBEM_REFRESH_INFO_REMOTE& Info, LPCWSTR pwcsRequestName,
long lCancelId, IWbemHiPerfEnum** ppEnum, long* plId, COAUTHINFO* pAuthInfo )
{
// Look for this remote connection in our list
// ===========================================
CRemote* pFoundRec = NULL;
HRESULT hr = FindRemoteEntry( Info, pAuthInfo, &pFoundRec );
if ( SUCCEEDED( hr ) )
{
if ( !pFoundRec->IsConnected() )
{
hr = pFoundRec->Rebuild( pRefServ, Info.m_pRefresher, &Info.m_guid );
}
if ( SUCCEEDED( hr ) )
{
// Add a request to it
// ===================
IWbemObjectAccess* pAccess = Info.m_pTemplate;
CWbemObject* pObj = (CWbemObject*)pAccess;
hr = pFoundRec->AddEnumRequest(pObj, pwcsRequestName, lCancelId, ppEnum, plId, m_pControl );
}
// Release the record
pFoundRec->Release();
}
return hr;
}
HRESULT CUniversalRefresher::AddRefresher( IWbemRefresher* pRefresher, long lFlags, long* plId )
{
HRESULT hr = WBEM_S_NO_ERROR;
if ( NULL != pRefresher && 0L == lFlags )
{
CNestedRefresher* pNested = new CNestedRefresher( pRefresher );
if ( NULL != pNested )
{
if ( NULL != plId )
{
*plId = pNested->GetId();
}
m_apNestedRefreshers.Add( pNested );
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
hr = WBEM_E_INVALID_PARAMETER;
}
return hr;
}
HRESULT CUniversalRefresher::Remove(long lId, long lFlags)
{
HRESULT hres;
// Search through them all
// =======================
int i;
for(i = 0; i < m_apRemote.GetSize(); i++)
{
hres = m_apRemote[i]->Remove(lId, lFlags, this);
if(hres == WBEM_S_NO_ERROR)
return WBEM_S_NO_ERROR;
else if(FAILED(hres))
return hres;
}
for(i = 0; i < m_apDirect.GetSize(); i++)
{
hres = m_apDirect[i]->Remove(lId, this);
if(hres == WBEM_S_NO_ERROR)
return WBEM_S_NO_ERROR;
else if(FAILED(hres))
return hres;
}
// Check for a nested refresher
for ( i = 0; i < m_apNestedRefreshers.GetSize(); i++ )
{
if ( m_apNestedRefreshers[i]->GetId() == lId )
{
CNestedRefresher* pNested = m_apNestedRefreshers[i];
// This will delete the pointer
m_apNestedRefreshers.RemoveAt( i );
return WBEM_S_NO_ERROR;
}
}
return WBEM_S_FALSE;
}
HRESULT CUniversalRefresher::Refresh(long lFlags)
{
HRESULT hres = WBEM_S_NO_ERROR;
BOOL fPartialSuccess = FALSE;
// Search through them all
// =======================
// Keep track of how many different refresh calls we actually make.
int i;
HRESULT hrFirstRefresh = WBEM_S_NO_ERROR;
BOOL fOneSuccess = FALSE;
BOOL fOneRefresh = FALSE;
for(i = 0; i < m_apRemote.GetSize(); i++)
{
hres = m_apRemote[i]->Refresh(lFlags);
// Always keep the first return code. We also need to track
// whether or not we had at least one success, as well as if
// the partial flag should be set.
if ( !fOneRefresh )
{
fOneRefresh = TRUE;
hrFirstRefresh = hres;
}
// All other codes indicate something went awry
if ( WBEM_S_NO_ERROR == hres )
{
fOneSuccess = TRUE;
// A prior refresh may have failed, a later one didn't
if ( fOneRefresh && WBEM_S_NO_ERROR != hrFirstRefresh )
{
fPartialSuccess = TRUE;
}
}
else if ( fOneSuccess )
{
// We must have had at least one success for the partial success
// flag to be set.
fPartialSuccess = TRUE;
}
}
for(i = 0; i < m_apDirect.GetSize(); i++)
{
hres = m_apDirect[i]->Refresh(lFlags);
// Always keep the first return code. We also need to track
// whether or not we had at least one success, as well as if
// the partial flag should be set.
if ( !fOneRefresh )
{
fOneRefresh = TRUE;
hrFirstRefresh = hres;
}
// All other codes indicate something went awry
if ( WBEM_S_NO_ERROR == hres )
{
fOneSuccess = TRUE;
// A prior refresh may have failed, a later one didn't
if ( fOneRefresh && WBEM_S_NO_ERROR != hrFirstRefresh )
{
fPartialSuccess = TRUE;
}
}
else if ( fOneSuccess )
{
// We must have had at least one success for the partial success
// flag to be set.
fPartialSuccess = TRUE;
}
}
// Refresh nested refreshers too
for ( i = 0; i < m_apNestedRefreshers.GetSize(); i++ )
{
hres = m_apNestedRefreshers[i]->Refresh( lFlags );
// Always keep the first return code. We also need to track
// whether or not we had at least one success, as well as if
// the partial flag should be set.
if ( !fOneRefresh )
{
fOneRefresh = TRUE;
hrFirstRefresh = hres;
}
// All other codes indicate something went awry
if ( WBEM_S_NO_ERROR == hres )
{
fOneSuccess = TRUE;
// A prior refresh may have failed, a later one didn't
if ( fOneRefresh && WBEM_S_NO_ERROR != hrFirstRefresh )
{
fPartialSuccess = TRUE;
}
}
else if ( fOneSuccess )
{
// We must have had at least one success for the partial success
// flag to be set.
fPartialSuccess = TRUE;
}
}
// At this point, if the partial success flag is set, that will
// be our return. If we didn't have at least one success, then
// the return code will be the first one we got back. Otherwise,
// hres should contain the proper value
if ( fPartialSuccess )
{
hres = WBEM_S_PARTIAL_RESULTS;
}
else if ( !fOneSuccess )
{
hres = hrFirstRefresh;
}
return hres;
}
void CUniversalRefresher::Flush()
{
GetProviderCache()->Flush();
}
//*****************************************************************************
//*****************************************************************************
// CLIENT REQUEST
//*****************************************************************************
//*****************************************************************************
CUniversalRefresher::CClientRequest::CClientRequest(CWbemObject* pTemplate)
: m_pClientObject(NULL), m_lClientId(0)
{
if(pTemplate)
{
pTemplate->AddRef();
m_pClientObject = (CWbemObject*)pTemplate;
}
m_lClientId = CUniversalRefresher::GetNewId();
}
CUniversalRefresher::CClientRequest::~CClientRequest()
{
if(m_pClientObject)
m_pClientObject->Release();
}
void CUniversalRefresher::CClientRequest::SetClientObject(
CWbemObject* pClientObject)
{
if(m_pClientObject)
m_pClientObject->Release();
m_pClientObject = pClientObject;
if(m_pClientObject)
m_pClientObject->AddRef();
}
void CUniversalRefresher::CClientRequest::GetClientInfo(
RELEASE_ME IWbemClassObject** ppRefreshable, long* plId)
{
*ppRefreshable = m_pClientObject;
if(m_pClientObject)
m_pClientObject->AddRef();
if ( NULL != plId )
{
*plId = m_lClientId;
}
}
//*****************************************************************************
//*****************************************************************************
// DIRECT PROVIDER
//*****************************************************************************
//*****************************************************************************
CUniversalRefresher::CDirect::CDirect(CHiPerfProviderRecord* pProvider,
IWbemRefresher* pRefresher)
: m_pRefresher(pRefresher), m_pProvider(pProvider)
{
if(m_pRefresher)
m_pRefresher->AddRef();
if(m_pProvider)
m_pProvider->AddRef();
}
CUniversalRefresher::CDirect::~CDirect()
{
if(m_pRefresher)
m_pRefresher->Release();
if(m_pProvider)
m_pProvider->Release();
}
HRESULT CUniversalRefresher::CDirect::AddRequest(CWbemObject* pRefreshedObject, CWbemObject* pClientInstance,
long lCancelId, IWbemClassObject** ppRefreshable, long* plId)
{
CRequest* pRequest = NULL;
try
{
pRequest = _new CRequest(pRefreshedObject, pClientInstance, lCancelId);
m_apRequests.Add(pRequest);
pRequest->GetClientInfo(ppRefreshable, plId);
}
catch(...)
{
if ( NULL != pRequest )
{
delete pRequest;
}
return WBEM_E_OUT_OF_MEMORY;
}
return WBEM_S_NO_ERROR;
}
HRESULT CUniversalRefresher::CDirect::AddEnumRequest(CClientLoadableHiPerfEnum* pHPEnum,
long lCancelId, IWbemHiPerfEnum** ppEnum, long* plId, CLifeControl* pLifeControl )
{
HRESULT hr = WBEM_S_NO_ERROR;
CEnumRequest* pEnumRequest = NULL;
try
{
// We get away with this through inheritance and polymorphism
pEnumRequest = _new CEnumRequest(pHPEnum, lCancelId, pLifeControl);
m_apRequests.Add((CRequest*) pEnumRequest);
hr = pEnumRequest->GetClientInfo(ppEnum, plId);
}
catch(...)
{
if ( NULL != pEnumRequest )
{
delete pEnumRequest;
}
return WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
HRESULT CUniversalRefresher::CDirect::Refresh(long lFlags)
{
HRESULT hres;
if(m_pRefresher)
{
try
{
hres = m_pRefresher->Refresh(0L);
}
catch(...)
{
// Provider threw an exception, so get out of here ASAP
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres)) return hres;
}
int nSize = m_apRequests.GetSize();
for(int i = 0; i < nSize; i++)
{
m_apRequests[i]->Copy();
}
return WBEM_S_NO_ERROR;
}
HRESULT CUniversalRefresher::CDirect::Remove(long lId,
CUniversalRefresher* pContainer)
{
int nSize = m_apRequests.GetSize();
for(int i = 0; i < nSize; i++)
{
CRequest* pRequest = m_apRequests[i];
if(pRequest->GetClientId() == lId)
{
pRequest->Cancel(this);
m_apRequests.RemoveAt(i);
return WBEM_S_NO_ERROR;
}
}
return WBEM_S_FALSE;
}
CUniversalRefresher::CDirect::CRequest::CRequest( CWbemObject* pProviderObject,
CWbemObject* pClientInstance,
long lProviderId )
: CClientRequest(pClientInstance), m_pProviderObject(pProviderObject),
m_lProviderId(lProviderId)
{
if(m_pProviderObject)
m_pProviderObject->AddRef();
}
HRESULT CUniversalRefresher::CDirect::CRequest::Cancel(
CUniversalRefresher::CDirect* pDirect)
{
if(pDirect->GetProvider())
{
try
{
return pDirect->GetProvider()->m_pProvider->StopRefreshing(pDirect->GetRefresher(),
m_lProviderId, 0);
}
catch(...)
{
// Provider threw an exception, so get out of here ASAP
return WBEM_E_PROVIDER_FAILURE;
}
}
else return WBEM_S_NO_ERROR;
}
CUniversalRefresher::CDirect::CRequest::~CRequest()
{
if(m_pProviderObject)
m_pProviderObject->Release();
}
void CUniversalRefresher::CDirect::CRequest::Copy()
{
m_pClientObject->CopyBlobOf(m_pProviderObject);
}
CUniversalRefresher::CDirect::CEnumRequest::CEnumRequest(CClientLoadableHiPerfEnum* pHPEnum,
long lProviderId, CLifeControl* pLifeControl )
: CRequest( NULL, NULL, lProviderId ), m_pHPEnum(pHPEnum)
{
if( m_pHPEnum )
m_pHPEnum->AddRef();
// We'll need an enumerator for the client to retrieve objects
m_pClientEnum = new CReadOnlyHiPerfEnum( pLifeControl );
if ( NULL != m_pClientEnum )
{
// Set the instance template. Without this, there is no point
CWbemInstance* pInst = pHPEnum->GetInstanceTemplate();
if ( NULL != pInst )
{
// Don't hold onto the enumerator unless the template is
// properly set.
if ( SUCCEEDED(m_pClientEnum->SetInstanceTemplate( pInst ) ) )
{
m_pClientEnum->AddRef();
}
else
{
// Cleanup
delete m_pClientEnum;
m_pClientEnum = NULL;
}
// GetInstanceTemplate AddRefs
pInst->Release();
}
else
{
delete m_pClientEnum;
m_pClientEnum = NULL;
}
}
}
CUniversalRefresher::CDirect::CEnumRequest::~CEnumRequest()
{
if(m_pHPEnum)
m_pHPEnum->Release();
if ( NULL != m_pClientEnum )
{
m_pClientEnum->Release();
}
}
void CUniversalRefresher::CDirect::CEnumRequest::Copy()
{
// Tell the refresher enumerator to copy its objects from
// the HiPerf Enumerator
if ( NULL != m_pClientEnum )
{
m_pClientEnum->Copy( m_pHPEnum );
}
}
HRESULT CUniversalRefresher::CDirect::CEnumRequest::GetClientInfo( RELEASE_ME IWbemHiPerfEnum** ppEnum,
long* plId)
{
// We best have enumerators to hook up here
if ( NULL != m_pClientEnum )
{
// Store the client id, then do a QI
if ( NULL != plId )
{
*plId = m_lClientId;
}
return m_pClientEnum->QueryInterface( IID_IWbemHiPerfEnum, (void**) ppEnum );
}
else
{
return WBEM_E_FAILED;
}
}
//*****************************************************************************
//*****************************************************************************
// REMOTE PROVIDER
//*****************************************************************************
//*****************************************************************************
CUniversalRefresher::CRemote::CRemote(IWbemRemoteRefresher* pRemRefresher, COAUTHINFO* pCoAuthInfo, const GUID* pGuid,
LPCWSTR pwszNamespace, LPCWSTR pwszServer, CUniversalRefresher* pObject )
: m_pRemRefresher(pRemRefresher), m_bstrNamespace( NULL ), m_fConnected( TRUE ), m_pObject( pObject ),
m_bstrServer( NULL ), m_lRefCount( 1 ), m_pReconnectedRemote( NULL ), m_pReconnectSrv( NULL ), m_fQuit( FALSE )
{
// Initialize the GUID data members
ZeroMemory( &m_ReconnectGuid, sizeof(GUID));
m_RemoteGuid = *pGuid;
if(m_pRemRefresher)
m_pRemRefresher->AddRef();
m_CoAuthInfo = *pCoAuthInfo;
if ( NULL != pCoAuthInfo->pwszServerPrincName )
{
// This will throw an exception if it fails
m_CoAuthInfo.pwszServerPrincName = new WCHAR[wcslen(pCoAuthInfo->pwszServerPrincName)+1];
wcscpy( m_CoAuthInfo.pwszServerPrincName, pCoAuthInfo->pwszServerPrincName );
}
// Store reconnection data
if ( NULL != pwszNamespace )
{
m_bstrNamespace = SysAllocString( pwszNamespace );
}
if ( NULL != pwszServer )
{
m_bstrServer = SysAllocString( pwszServer );
}
}
CUniversalRefresher::CRemote::~CRemote()
{
ClearRemoteConnections();
if ( NULL != m_CoAuthInfo.pwszServerPrincName )
{
delete [] m_CoAuthInfo.pwszServerPrincName;
}
if ( NULL != m_bstrNamespace )
{
SysFreeString( m_bstrNamespace );
}
if ( NULL != m_bstrServer )
{
SysFreeString( m_bstrServer );
}
}
ULONG STDMETHODCALLTYPE CUniversalRefresher::CRemote::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
ULONG STDMETHODCALLTYPE CUniversalRefresher::CRemote::Release()
{
long lRef = InterlockedDecrement(&m_lRefCount);
if(lRef == 0)
delete this;
return lRef;
}
// Applies appropriate security settings to the proxy
HRESULT CUniversalRefresher::CRemote::ApplySecurity( void )
{
return WbemSetProxyBlanket( m_pRemRefresher, m_CoAuthInfo.dwAuthnSvc, m_CoAuthInfo.dwAuthzSvc,
m_CoAuthInfo.pwszServerPrincName, m_CoAuthInfo.dwAuthnLevel, m_CoAuthInfo.dwImpersonationLevel,
(RPC_AUTH_IDENTITY_HANDLE) m_CoAuthInfo.pAuthIdentityData, m_CoAuthInfo.dwCapabilities );
}
void CUniversalRefresher::CRemote::CheckConnectionError( HRESULT hr, BOOL fStartReconnect )
{
if ( IsConnectionError( hr ) && fStartReconnect )
{
// Release and NULL out the remote refresher pointer. The Remote GUID member
// will tell us if a reconnect got us back to the same stub on the server
// DEVNOTE:TODO - Looks like COM has a problem with these, so let the release happen
// when we try to Rebuild the connection.
// m_pRemRefresher->Release();
// m_pRemRefresher = NULL;
// We should change the m_fConnected data member to indicate that we are no
// longer connected, and we need to spin off a thread to try and put us back
// together again. To keep things running smoothly, we should AddRef() ourselves
// so the thread will release us when it is done.
m_fConnected = FALSE;
// AddRefs us so we can be passed off to the thread
AddRef();
DWORD dwThreadId = NULL;
HANDLE hThread = (HANDLE) _beginthreadex( NULL, 0, CRemote::ThreadProc, (void*) this,
0, (unsigned int *) &dwThreadId );
// If no thread was spawned, then there is no need for us to maintain the AddRef() from
// above.
if ( NULL != hThread )
{
CloseHandle( hThread );
}
else
{
Release();
}
} // If connection error and start reconnect thread
}
HRESULT CUniversalRefresher::CRemote::AddRequest(
CWbemObject* pTemplate, LPCWSTR pwcsRequestName, long lCancelId,
IWbemClassObject** ppRefreshable, long* plId)
{
HRESULT hr = WBEM_S_NO_ERROR;
CRequest* pRequest = NULL;
try
{
pRequest = _new CRequest(pTemplate, lCancelId, pwcsRequestName);
m_apRequests.Add(pRequest);
pRequest->GetClientInfo(ppRefreshable, plId);
}
catch( ... )
{
if ( NULL != pRequest )
{
delete pRequest;
}
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
HRESULT CUniversalRefresher::CRemote::AddEnumRequest(
CWbemObject* pTemplate, LPCWSTR pwcsRequestName, long lCancelId,
IWbemHiPerfEnum** ppEnum, long* plId, CLifeControl* pLifeControl )
{
HRESULT hr = WBEM_S_NO_ERROR;
CEnumRequest* pRequest = NULL;
try
{
// Make sure the request allocates an enumerator internally
pRequest = _new CEnumRequest( pTemplate, lCancelId, pwcsRequestName, pLifeControl );
if ( pRequest->IsOk() )
{
// All we need for the client is the id, so
// dummy up a holder for the refreshable object
// ( which is really the template for the objects
// we will be returning from the enumerator.
IWbemClassObject* pObjTemp = NULL;
m_apRequests.Add((CRequest*) pRequest);
pRequest->GetClientInfo( &pObjTemp, plId );
if ( NULL != pObjTemp )
{
pObjTemp->Release();
}
// Get the enumerator
hr = pRequest->GetEnum( ppEnum );
}
else
{
hr = WBEM_E_FAILED;
}
}
catch( ... )
{
if ( NULL != pRequest )
{
delete pRequest;
}
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
// Rebuilds a remote refresher
HRESULT CUniversalRefresher::CRemote::Rebuild( IWbemServices* pNamespace )
{
HRESULT hr = WBEM_S_NO_ERROR;
// Storage for security settings we will need in order to propagate
// down to our internal interfaces.
COAUTHINFO CoAuthInfo;
// Acquire internal connection to WINMGMT
// ====================================
IWbemRefreshingServices* pRefServ = NULL;
hr = m_pObject->GetRefreshingServices( pNamespace, &pRefServ, &CoAuthInfo );
CReleaseMe rmrs(pRefServ);
if ( FAILED( hr ) )
{
return hr;
}
// This guarantees this will be freed when we drop out of scope. If we store
// it we will need to allocate an internal copy.
CMemFreeMe mfm( CoAuthInfo.pwszServerPrincName );
IWbemRemoteRefresher* pRemRefresher = NULL;
// Make sure a remote refresher exists for "this" refresher
GUID remoteGuid;
DWORD dwRemoteRefrVersion = 0;
hr = pRefServ->GetRemoteRefresher( m_pObject->GetId(), 0L, WBEM_REFRESHER_VERSION,
&pRemRefresher, &remoteGuid, &dwRemoteRefrVersion );
CReleaseMe rm(pRemRefresher);
if ( FAILED( hr ) )
{
return hr;
}
else
{
// Will enter and exit the critical section with scoping
CInCritSec ics( &m_cs );
// Check that we're still not connected
if ( !m_fConnected )
{
// Because the original object mayhave been instantiated in an STA, we will let the Refresh
// call do the dirty work of actually hooking up this bad boy. In order for this
// to work, however,
hr = CoMarshalInterThreadInterfaceInStream( IID_IWbemRemoteRefresher, pRemRefresher, &m_pReconnectedRemote );
if ( SUCCEEDED( hr ) )
{
hr = CoMarshalInterThreadInterfaceInStream( IID_IWbemRefreshingServices, pRefServ, &m_pReconnectSrv );
if ( SUCCEEDED( hr ) )
{
// Store the GUID so the refresh will be able to determine the identity
// of the remote refresher.
m_ReconnectGuid = remoteGuid;
}
else
{
IWbemRemoteRefresher* pTemp = NULL;
// Cleanup the data here
CoGetInterfaceAndReleaseStream( m_pReconnectedRemote, IID_IWbemRemoteRefresher,
(void**) &pTemp );
CReleaseMe rmTemp( pTemp );
// NULL out the old pointer
m_pReconnectedRemote = NULL;
}
}
} // IF !m_fConnected
}
return hr;
}
HRESULT CUniversalRefresher::CRemote::Rebuild( IWbemRefreshingServices* pRefServ,
IWbemRemoteRefresher* pRemRefresher,
const GUID* pReconnectGuid )
{
HRESULT hr = WBEM_S_NO_ERROR;
// Will enter and exit the critical section with scoping
CInCritSec ics( &m_cs );
// Right off, check if we ARE connected, in which case we can assume we had
// a race condition on this function, and the winner got us all hooked back
// up again.
if ( m_fConnected )
{
return hr;
}
// If these two are equal, we can assume that we reconnected without losing our previous connection.
// If they are not equal, we will then need to rebuild the remote refresher, however, by calling
// GetRemoteRefresher() successfully we will have effectively ensured that a remote refresher exists
// for us up on the server.
if ( *pReconnectGuid != m_RemoteGuid )
{
// We will need these memory buffers to hold individual request data
WBEM_RECONNECT_INFO* apReconnectInfo = NULL;
WBEM_RECONNECT_RESULTS* apReconnectResults = NULL;
// Only alloc and fill out arrays if we have requests
if ( m_apRequests.GetSize() > 0 )
{
try
{
apReconnectInfo = new WBEM_RECONNECT_INFO[m_apRequests.GetSize()];
apReconnectResults = new WBEM_RECONNECT_RESULTS[m_apRequests.GetSize()];
}
catch( ... )
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if ( SUCCEEDED( hr ) )
{
// Don't need to reset anything if nothing to reset
if ( m_apRequests.GetSize() > 0 )
{
// Enumerate the requests and fill out the arrays
for ( int i = 0; i < m_apRequests.GetSize(); i++ )
{
CRequest* pRequest = m_apRequests.GetAt( i );
// Setup each info structure
apReconnectInfo[i].m_lType = ( pRequest->IsEnum() ? WBEM_RECONNECT_TYPE_ENUM :
WBEM_RECONNECT_TYPE_OBJECT );
apReconnectInfo[i].m_pwcsPath = pRequest->GetName();
apReconnectResults[i].m_lId = pRequest->GetRemoteId();
apReconnectResults[i].m_hr = 0;
} // FOR enum requests
DWORD dwRemoteRefrVersion = 0;
hr = pRefServ->ReconnectRemoteRefresher( m_pObject->GetId(), 0L, m_apRequests.GetSize(),
WBEM_REFRESHER_VERSION, apReconnectInfo,
apReconnectResults, &dwRemoteRefrVersion );
}
// Rehook up the object and enumids
if ( WBEM_S_NO_ERROR == hr )
{
// Cleanup the old pointer
if ( NULL != m_pRemRefresher )
{
m_pRemRefresher->Release();
m_pRemRefresher = NULL;
}
// Store the new one and setup the security
m_pRemRefresher = pRemRefresher;
hr = ApplySecurity();
if ( SUCCEEDED( hr ) )
{
m_pRemRefresher->AddRef();
// Redo the ones that succeeded. Clear the rest
for( int i = 0; i < m_apRequests.GetSize(); i++ )
{
CRequest* pRequest = m_apRequests.GetAt( i );
if ( SUCCEEDED( apReconnectResults[i].m_hr ) )
{
pRequest->SetRemoteId( apReconnectResults[i].m_lId );
}
else
{
// This means it didn't get hooked up again. So if the
// user tries to remove him, we will just ignore this
// id.
pRequest->SetRemoteId( INVALID_REMOTE_REFRESHER_ID );
}
}
}
else
{
// Setting security failed, so just set the pointer to NULL (we haven't
// AddRef'd it ).
m_pRemRefresher = NULL;
}
} // IF WBEM_S_NO_ERROR == hr
} // IF SUCCEEDED(hr)
// Check that we're good to go
if ( SUCCEEDED( hr ) )
{
// Clear the removed ids array since a new connection was established, hence the
// old ids are a moot point.
m_alRemovedIds.Empty();
m_fConnected = TRUE;
}
// Cleanup the memory buffers
if ( NULL != apReconnectInfo )
{
delete [] apReconnectInfo;
}
if ( NULL != apReconnectResults )
{
delete [] apReconnectResults;
}
} // IF remote refreshers not the same
else
{
// The remote refresher pointers match, so assume that all our old ids are still
// valid.
// The refresher we were handed will be automatically released.
m_fConnected = TRUE;
// Cleanup the old pointer
if ( NULL != m_pRemRefresher )
{
m_pRemRefresher->Release();
m_pRemRefresher = NULL;
}
// Store the new one and setup the security
m_pRemRefresher = pRemRefresher;
hr = ApplySecurity();
if ( SUCCEEDED( hr ) )
{
m_pRemRefresher->AddRef();
}
else
{
// Setting security failed, so just set the pointer to NULL (we haven't
// AddRef'd it ).
m_pRemRefresher = NULL;
}
// Delete cached ids if we have any.
if ( ( SUCCEEDED ( hr ) ) && m_alRemovedIds.Size() > 0 )
{
// We will need these memory buffers to hold individual request data
long* aplIds = NULL;
try
{
aplIds = new long[m_alRemovedIds.Size()];
}
catch( ... )
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( SUCCEEDED( hr ) )
{
// Enumerate the requests and fill out the arrays
for ( int i = 0; i < m_alRemovedIds.Size(); i++ )
{
// DEVNOTE:WIN64:SANJ - The id's are 32-bit, but on 64-bit platforms,
// the flex array will contain 64-bit values, so use PtrToLong
// to get a warning free conversion. On 32-bit platforms,
// PtrToLong will do nothing.
aplIds[i] = PtrToLong(m_alRemovedIds.GetAt( i ));
} // FOR enum requests
// DEVNOTE:TODO:SANJ - Do we care about this return code?
hr = m_pRemRefresher->StopRefreshing( i-1, aplIds, 0 );
// Clear the array
m_alRemovedIds.Empty();
}
if ( NULL != aplIds )
{
delete [] aplIds;
}
} // If RemoveId list is not empty
} // We got the remote refresher
return hr;
}
// This is a temporary helper function which helps us determine if a remote machine
// is actually alive, since COM/RPC seem to have problems with hanging if I constantly
// hammer at CoCreateInstanceEx() when the remote machine is down
HRESULT CUniversalRefresher::CRemote::IsAlive( void )
{
HRESULT hr = RPC_E_DISCONNECTED;
HKEY hRemoteKey = NULL;
long lError = RegConnectRegistryW( m_bstrServer, HKEY_LOCAL_MACHINE, &hRemoteKey );
// If we get a success or an access denied, then we will go ahead
// and assume that the machine is up.
if ( ERROR_SUCCESS == lError || ERROR_ACCESS_DENIED == lError )
{
hr = WBEM_S_NO_ERROR;
}
if ( NULL != hRemoteKey )
{
RegCloseKey( hRemoteKey );
}
return hr;
}
unsigned CUniversalRefresher::CRemote::ReconnectEntry( void )
{
HRESULT hr = RPC_E_DISCONNECTED;
// This guy ALWAYS runs in the MTA
InitializeCom();
// Basically as long as we can't connect, somebody else doesn't connect us, or we are told
// to quit, we will run this thread.
while ( FAILED(hr) && !m_fConnected && !m_fQuit )
{
IWbemLocator* pWbemLocator = NULL;
// Because COM and RPC seem to have this problem with actually being able to themselves
// reconnect, we're performing our own low level "ping" of the remote machine, using RegConnectRegistry
// to verify if the machine is indeed alive. If it is, then and only then will be deign to use
// DCOM to follow through the operation.
hr = IsAlive();
if ( SUCCEEDED( hr ) )
{
// Make sure we have a namespace to connect to
if ( NULL != m_bstrNamespace )
{
hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (void**) &pWbemLocator );
if ( SUCCEEDED( hr ) )
{
IWbemServices* pNamespace = NULL;
// We're gonna default to the system
hr = pWbemLocator->ConnectServer( m_bstrNamespace, // NameSpace Name
NULL, // UserName
NULL, // Password
NULL, // Locale
0L, // Security Flags
NULL, // Authority
NULL, // Wbem Context
&pNamespace // Namespace
);
if ( SUCCEEDED( hr ) )
{
// Apply security settings to the namespace
hr = WbemSetProxyBlanket( pNamespace, m_CoAuthInfo.dwAuthnSvc,
m_CoAuthInfo.dwAuthzSvc, m_CoAuthInfo.pwszServerPrincName,
m_CoAuthInfo.dwAuthnLevel, m_CoAuthInfo.dwImpersonationLevel,
(RPC_AUTH_IDENTITY_HANDLE) m_CoAuthInfo.pAuthIdentityData,
m_CoAuthInfo.dwCapabilities );
if ( SUCCEEDED( hr ) )
{
hr = Rebuild( pNamespace );
}
pNamespace->Release();
} // IF ConnectServer
pWbemLocator->Release();
} // IF Created Locator
} // IF NULL != m_bstrNamespace
} // IF IsAlive()
// Sleep for a second and retry
Sleep( 1000 );
}
// Release the AddRef() on the object from when the thread was created
Release();
CoUninitialize();
return 0;
}
void CUniversalRefresher::CRemote::ClearRemoteConnections( void )
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemRemoteRefresher* pRemRefresher = NULL;
IWbemRefreshingServices* pRefServ = NULL;
// Cleanup the IWbemRefreshingServices stream pointer
if ( NULL != m_pReconnectSrv )
{
hr = CoGetInterfaceAndReleaseStream( m_pReconnectSrv, IID_IWbemRefreshingServices, (void**) &pRefServ );
// This will autorelease
CReleaseMe rmrs( pRefServ );
if ( SUCCEEDED( hr ) )
{
// We need to reset security on the Refreshing services proxy.
hr = WbemSetProxyBlanket( pRefServ, m_CoAuthInfo.dwAuthnSvc,
m_CoAuthInfo.dwAuthzSvc, m_CoAuthInfo.pwszServerPrincName,
m_CoAuthInfo.dwAuthnLevel, m_CoAuthInfo.dwImpersonationLevel,
(RPC_AUTH_IDENTITY_HANDLE) m_CoAuthInfo.pAuthIdentityData,
m_CoAuthInfo.dwCapabilities );
}
m_pReconnectSrv = NULL;
}
// Cleanup the IWbemRemoteRefresher stream pointer
if ( NULL != m_pReconnectedRemote )
{
hr = CoGetInterfaceAndReleaseStream( m_pReconnectedRemote, IID_IWbemRemoteRefresher,
(void**) &pRemRefresher );
CReleaseMe rmrr( pRemRefresher );
if ( SUCCEEDED( hr ) )
{
// We need to reset security on the proxy.
hr = WbemSetProxyBlanket( pRemRefresher, m_CoAuthInfo.dwAuthnSvc,
m_CoAuthInfo.dwAuthzSvc, m_CoAuthInfo.pwszServerPrincName,
m_CoAuthInfo.dwAuthnLevel, m_CoAuthInfo.dwImpersonationLevel,
(RPC_AUTH_IDENTITY_HANDLE) m_CoAuthInfo.pAuthIdentityData,
m_CoAuthInfo.dwCapabilities );
}
// Make sure we release the stream
m_pReconnectedRemote = NULL;
}
// Cleanup the IWbemRemoteRefresher pointer
if ( NULL != m_pRemRefresher )
{
m_pRemRefresher->Release();
m_pRemRefresher = NULL;
}
}
HRESULT CUniversalRefresher::CRemote::Reconnect( void )
{
HRESULT hr = RPC_E_DISCONNECTED;
IWbemRemoteRefresher* pRemRefresher = NULL;
IWbemRefreshingServices* pRefServ = NULL;
CInCritSec ics( &m_cs );
// We will need to unmarshale both the RefreshingServices and the RemoteRefresher pointers,
// so make sure that the streams we will need to unmarshal these from already exist.
if ( NULL != m_pReconnectSrv && NULL != m_pReconnectedRemote )
{
hr = CoGetInterfaceAndReleaseStream( m_pReconnectSrv, IID_IWbemRefreshingServices, (void**) &pRefServ );
CReleaseMe rmrs( pRefServ );
if ( SUCCEEDED( hr ) )
{
// We need to reset security on the Refreshing services proxy.
hr = WbemSetProxyBlanket( pRefServ, m_CoAuthInfo.dwAuthnSvc,
m_CoAuthInfo.dwAuthzSvc, m_CoAuthInfo.pwszServerPrincName,
m_CoAuthInfo.dwAuthnLevel, m_CoAuthInfo.dwImpersonationLevel,
(RPC_AUTH_IDENTITY_HANDLE) m_CoAuthInfo.pAuthIdentityData,
m_CoAuthInfo.dwCapabilities );
if ( SUCCEEDED( hr ) )
{
hr = CoGetInterfaceAndReleaseStream( m_pReconnectedRemote, IID_IWbemRemoteRefresher,
(void**) &pRemRefresher );
CReleaseMe rmrr( pRemRefresher );
if ( SUCCEEDED( hr ) )
{
// Remote refresher and refreshing services
hr = Rebuild( pRefServ, pRemRefresher, &m_ReconnectGuid );
}
else
{
// Make sure we release the stream
m_pReconnectedRemote->Release();
}
}
else
{
// Make sure we release the stream
m_pReconnectedRemote->Release();
}
} // IF unmarshaled refreshing services pointer
else
{
m_pReconnectSrv->Release();
m_pReconnectedRemote->Release();
}
// NULL out both stream pointers
m_pReconnectSrv = NULL;
m_pReconnectedRemote = NULL;
}
return hr;
}
HRESULT CUniversalRefresher::CRemote::Refresh(long lFlags)
{
if(m_pRemRefresher == NULL && IsConnected())
return WBEM_E_CRITICAL_ERROR;
WBEM_REFRESHED_OBJECT* aRefreshed = NULL;
long lNumObjects = 0;
HRESULT hresRefresh = WBEM_S_NO_ERROR;
// Make sure we're connected. If not, and we haven't been told not to, try to reconnect
if ( !IsConnected() )
{
if ( ! (lFlags & WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT ) )
{
hresRefresh = Reconnect();
if ( FAILED( hresRefresh ) )
{
return hresRefresh;
}
}
else
{
return RPC_E_DISCONNECTED;
}
}
hresRefresh = m_pRemRefresher->RemoteRefresh(0, &lNumObjects, &aRefreshed);
// If RemoteRefresh returns a connection type error, Set oiur state to "NOT" connected
if(FAILED(hresRefresh))
{
// This will kick off a thread to reconnect if the error return was
// a connection error, and the appropriate "Don't do this" flag is not set
CheckConnectionError( hresRefresh, !(lFlags & WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT ) );
return hresRefresh;
}
int nSize = m_apRequests.GetSize();
HRESULT hresFinal = WBEM_S_NO_ERROR;
// DEVNOTE:TODO:SANJ - We could make this much faster if we did some sorting on the
// server end
for(int i = 0; i < lNumObjects; i++)
{
long lObjectId = aRefreshed[i].m_lRequestId;
for(int j = 0; j < nSize; j++)
{
CRequest* pRequest = m_apRequests[j];
if(pRequest->GetRemoteId() == lObjectId)
{
// The request will refresh itself
HRESULT hres = pRequest->Refresh( &aRefreshed[i] );
// Only copy this value if the refresh failed and we haven't already
// gotten the value
if(FAILED(hres) && SUCCEEDED(hresFinal))
{
hresFinal = hres;
}
break;
}
}
CoTaskMemFree(aRefreshed[i].m_pbBlob);
}
// Free the wrapping BLOB
CoTaskMemFree( aRefreshed );
// The final return code should give precedence to the actual remote refresh call if it
// doesn't contain a NO_ERROR, and hresFinal is NOT an error
if ( SUCCEEDED( hresFinal ) )
{
if ( WBEM_S_NO_ERROR != hresRefresh )
{
hresFinal = hresRefresh;
}
}
return hresFinal;
}
HRESULT CUniversalRefresher::CRemote::Remove(long lId,
long lFlags,
CUniversalRefresher* pContainer)
{
HRESULT hr = WBEM_S_FALSE;
int nSize = m_apRequests.GetSize();
for(int i = 0; i < nSize; i++)
{
CRequest* pRequest = m_apRequests[i];
if(pRequest->GetClientId() == lId)
{
if ( IsConnected() )
{
// Check that the remote id doesn't indicate an item that
// failed to be reconstructed.
if ( pRequest->GetRemoteId() == INVALID_REMOTE_REFRESHER_ID )
{
hr = WBEM_S_NO_ERROR;
}
else
{
hr = pRequest->Cancel(this);
}
if ( FAILED(hr) && IsConnectionError(hr) )
{
// This will kick off a reconnect thread unless we were told not to
CheckConnectionError( hr, !(lFlags & WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT ) );
// We will remove the request from here, but
// queue up the id for later deletion
hr = WBEM_S_NO_ERROR;
}
}
// DEVNOTE:TODO:SANJ - What about other errors? For now, we'll lose the local
// connection.
if ( SUCCEEDED( hr ) )
{
// Retrieves the remote id from the request
long lRemoteId = pRequest->GetRemoteId();
m_apRequests.RemoveAt(i);
// If we couldn't remove the id remotely, just queue it up in the
// removed id array so we can clean it up properly if we get
// reconnected. We will, of course, not need to do anything if the
// remote id indicates a failed readd during reconnection
if ( lRemoteId != INVALID_REMOTE_REFRESHER_ID && !IsConnected() )
{
CInCritSec ics(&m_cs);
// Note that we may have gotten connected on the critical section and
// if that is the case, for now, we'll have one extra resource on the
// server, but the likelihood of running into contention problems here
// is too high. Plus, if it reconnected via a new remote refresher, if
// we retry a remove here, we could remove the "wrong" id. To protect
// against this, we will check that we are still not connected and if
// that is not the case, we will just "forget" about the object id.
if (!IsConnected())
{
try
{
// BUBBUG:WIN64:SANJ - By casting to __int64 and back to void*, in 32-bit,
// this truncates the __int64, and in 64-bit, keeps away warningss.
m_alRemovedIds.Add( (void*) (__int64) lRemoteId );
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
} // IF Still not connected
} // IF Not connected
} // IF remote remove ok
break;
} // IF found matching client id
} // FOR enum requests
return hr;
}
CUniversalRefresher::CRemote::CRequest::CRequest(CWbemObject* pTemplate,
long lRequestId,
LPCWSTR pwcsRequestName )
: CClientRequest(pTemplate), m_lRemoteId(lRequestId), m_wstrRequestName( pwcsRequestName )
{
}
HRESULT CUniversalRefresher::CRemote::CRequest::Refresh( WBEM_REFRESHED_OBJECT* pRefrObj )
{
CWbemInstance* pInst = (CWbemInstance*) GetClientObject();
return pInst->CopyTransferBlob(
pRefrObj->m_lBlobType,
pRefrObj->m_lBlobLength,
pRefrObj->m_pbBlob);
}
HRESULT CUniversalRefresher::CRemote::CRequest::Cancel(
CUniversalRefresher::CRemote* pRemote)
{
if(pRemote->GetRemoteRefresher())
return pRemote->GetRemoteRefresher()->StopRefreshing( 1, &m_lRemoteId, 0 );
else
return WBEM_S_NO_ERROR;
}
CUniversalRefresher::CRemote::CEnumRequest::CEnumRequest(CWbemObject* pTemplate,
long lRequestId,
LPCWSTR pwcsRequestName,
CLifeControl* pLifeControl )
: CRequest(pTemplate, lRequestId, pwcsRequestName), m_pClientEnum(NULL)
{
m_pClientEnum = new CReadOnlyHiPerfEnum( pLifeControl );
// AddRef the new enumerator
if ( NULL != m_pClientEnum )
{
// Don't hold onto this guy if we can't set the template
if ( SUCCEEDED( m_pClientEnum->SetInstanceTemplate( (CWbemInstance*) pTemplate ) ) )
{
m_pClientEnum->AddRef();
}
else
{
// Cleanup
delete m_pClientEnum;
m_pClientEnum = NULL;
}
}
}
CUniversalRefresher::CRemote::CEnumRequest::~CEnumRequest( void )
{
if ( NULL != m_pClientEnum )
{
m_pClientEnum->Release();
}
}
HRESULT CUniversalRefresher::CRemote::CEnumRequest::Refresh( WBEM_REFRESHED_OBJECT* pRefrObj )
{
return m_pClientEnum->Copy( pRefrObj->m_lBlobType,
pRefrObj->m_lBlobLength,
pRefrObj->m_pbBlob );
}
HRESULT CUniversalRefresher::CRemote::CEnumRequest::GetEnum( IWbemHiPerfEnum** ppEnum )
{
return ( NULL != m_pClientEnum ?
m_pClientEnum->QueryInterface( IID_IWbemHiPerfEnum, (void**) ppEnum ) :
WBEM_E_FAILED );
}
//*****************************************************************************
//*****************************************************************************
// NESTED REFRESHERS
//*****************************************************************************
//*****************************************************************************
CUniversalRefresher::CNestedRefresher::CNestedRefresher( IWbemRefresher* pRefresher )
: m_pRefresher(pRefresher)
{
if ( m_pRefresher )
m_pRefresher->AddRef();
// Assign a unique id
m_lClientId = CUniversalRefresher::GetNewId();
}
CUniversalRefresher::CNestedRefresher::~CNestedRefresher()
{
if ( m_pRefresher )
m_pRefresher->Release();
}
HRESULT CUniversalRefresher::CNestedRefresher::Refresh( long lFlags )
{
// Make sure we have an internal refresher pointer
return ( NULL != m_pRefresher ? m_pRefresher->Refresh( lFlags ) : WBEM_E_FAILED );
}
//*****************************************************************************
//*****************************************************************************
// PROVIDER CACHE
//*****************************************************************************
//*****************************************************************************
CHiPerfProviderRecord::CHiPerfProviderRecord(REFCLSID rclsid,
LPCWSTR wszNamespace, IWbemHiPerfProvider* pProvider)
: m_clsid(rclsid), m_wsNamespace(wszNamespace), m_pProvider(pProvider),
m_lRef( 0 )
{
if(m_pProvider)
m_pProvider->AddRef();
}
CHiPerfProviderRecord::~CHiPerfProviderRecord()
{
if(m_pProvider)
m_pProvider->Release();
}
long CHiPerfProviderRecord::Release()
{
long lRef = InterlockedDecrement( &m_lRef );
// Removing us from the cache will delete us
if ( 0 == lRef )
{
CUniversalRefresher::GetProviderCache()->RemoveRecord( this );
}
return lRef;
}
HRESULT CClientLoadableProviderCache::FindProvider(REFCLSID rclsid,
LPCWSTR wszNamespace, IUnknown* pNamespace,
CHiPerfProviderRecord** ppProvider)
{
CLock lock( &m_Lock );
// Check that we've got something to look into
if ( NULL == m_papRecords )
{
return WBEM_E_FAILED;
}
*ppProvider = NULL;
HRESULT hres;
for(int i = 0; i < m_papRecords->GetSize(); i++)
{
CHiPerfProviderRecord* pRecord = m_papRecords->GetAt( i );
if(pRecord->m_clsid == rclsid &&
pRecord->m_wsNamespace.EqualNoCase(wszNamespace))
{
*ppProvider = pRecord;
(*ppProvider)->AddRef();
return WBEM_S_NO_ERROR;
}
}
// Prepare an namespace pointer
// ============================
IWbemServices* pServices = NULL;
hres = pNamespace->QueryInterface(IID_IWbemServices, (void**)&pServices);
if(FAILED(hres))
return hres;
CReleaseMe rm1(pServices);
// Create
// ======
IUnknown* pUnk = NULL;
hres = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void**)&pUnk);
CReleaseMe rm2(pUnk);
if(FAILED(hres))
return hres;
// Initialize
// ==========
IWbemProviderInit* pInit = NULL;
hres = pUnk->QueryInterface(IID_IWbemProviderInit, (void**)&pInit);
if(FAILED(hres))
return hres;
CReleaseMe rm3(pInit);
CProviderInitSink* pSink = new CProviderInitSink;
pSink->AddRef();
CReleaseMe rm4(pSink);
try
{
hres = pInit->Initialize(NULL, 0, (LPWSTR)wszNamespace, NULL, pServices,
NULL, pSink);
}
catch(...)
{
hres = WBEM_E_PROVIDER_FAILURE;
}
if(FAILED(hres))
return hres;
hres = pSink->WaitForCompletion();
if(FAILED(hres))
return hres;
// Ask for the right interface
// ===========================
IWbemHiPerfProvider* pProvider = NULL;
hres = pUnk->QueryInterface(IID_IWbemHiPerfProvider, (void**)&pProvider);
if(FAILED(hres))
return hres;
CReleaseMe rm5(pProvider);
// Create a record
// ===============
CHiPerfProviderRecord* pRecord = _new CHiPerfProviderRecord(rclsid, wszNamespace, pProvider);
m_papRecords->Add(pRecord);
// AddRef the record
pRecord->AddRef();
*ppProvider = pRecord;
return WBEM_S_NO_ERROR;
}
HRESULT CClientLoadableProviderCache::FindProvider(REFCLSID rclsid,
IWbemHiPerfProvider* pProvider, LPCWSTR wszNamespace,
CHiPerfProviderRecord** ppProvider)
{
CLock lock( &m_Lock );
// Check that we've got something to look into
if ( NULL == m_papRecords )
{
return WBEM_E_FAILED;
}
*ppProvider = NULL;
for(int i = 0; i < m_papRecords->GetSize(); i++)
{
CHiPerfProviderRecord* pRecord = m_papRecords->GetAt( i );
if(pRecord->m_clsid == rclsid &&
pRecord->m_wsNamespace.EqualNoCase(wszNamespace))
{
*ppProvider = pRecord;
(*ppProvider)->AddRef();
return WBEM_S_NO_ERROR;
}
}
// We already have provider pointer so we can just create a record
// ===============
CHiPerfProviderRecord* pRecord = _new CHiPerfProviderRecord(rclsid, wszNamespace, pProvider);
m_papRecords->Add(pRecord);
// AddRef the record
pRecord->AddRef();
*ppProvider = pRecord;
return WBEM_S_NO_ERROR;
}
void CClientLoadableProviderCache::RemoveRecord( CHiPerfProviderRecord* pRecord )
{
CLock lock( &m_Lock );
// Make sure the record didn't get accessed on another thread.
// If not, go ahead and look for our record, and remove it
// from the array. When we remove it, the record will be
// deleted.
if ( pRecord->IsReleased() )
{
for(int i = 0; i < m_papRecords->GetSize(); i++)
{
if ( pRecord == m_papRecords->GetAt( i ) )
{
// This will delete the record
m_papRecords->RemoveAt( i );
break;
}
} // FOR search records
} // IF record is released
}
void CClientLoadableProviderCache::Flush()
{
CLock lock( &m_Lock );
if ( NULL != m_papRecords )
{
m_papRecords->RemoveAll();
}
}
CClientLoadableProviderCache::~CClientLoadableProviderCache( void )
{
// This is a static list, so if we're going away and something
// fails here because people didn't release pointers properly,
// chances are something will fail, so since we're being dropped
// from memory, if the provider list is not empty, don't clean
// it up. This is really a bad client-created leak anyways.
if ( NULL != m_papRecords )
{
if ( m_papRecords->GetSize() == 0 )
{
delete m_papRecords;
}
}
}
CClientLoadableProviderCache::CClientLoadableProviderCache( void )
: m_papRecords( NULL )
{
m_Lock.SetData( &m_LockData );
// We need one of these
m_papRecords = new CUniquePointerArray<CHiPerfProviderRecord>;
}