windows-nt/Source/XPSP1/NT/admin/wmi/wbem/sdk/framedyn/provider.cpp
2020-09-26 16:20:57 +08:00

1043 lines
30 KiB
C++

//***************************************************************************
//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
// Provider.CPP
//
// Purpose: Implementation of Provider class
//
//***************************************************************************
#include "precomp.h"
#include <assertbreak.h>
#include <objpath.h>
#include <cominit.h>
#include <brodcast.h>
#include <createmutexasprocess.h>
#include <stopwatch.h>
#include <SmartPtr.h>
#include <frqueryex.h>
#include "FWStrings.h"
#include "MultiPlat.h"
// Must instantiate static members
CHString Provider::s_strComputerName;
////////////////////////////////////////////////////////////////////////
//
// Function: Provider ctor
//
//
//
// Inputs: name of this provider
//
// Outputs:
//
// Return:
//
// Comments: suggest that derived classes implement their provider's ctor thusly:
//
// MyProvider::MyProvider(const CHString& setName) :
// Provider(setName)
//
// that way, a *further* derived class can specify its own name
//
//
////////////////////////////////////////////////////////////////////////
Provider::Provider( LPCWSTR a_setName, LPCWSTR a_pszNameSpace /*=NULL*/ )
: CThreadBase(),
m_pIMosProvider( NULL ),
m_piClassObject( NULL ),
m_name( a_setName ),
m_strNameSpace( a_pszNameSpace )
{
// Initialize the computer name, then register with the framework.
InitComputerName();
CWbemProviderGlue::FrameworkLogin( a_setName, this, a_pszNameSpace );
}
////////////////////////////////////////////////////////////////////////
//
// Function: Provider dtor
//
//
//
// Inputs: none.
//
// Outputs:
//
// Return:
//
// Comments: cleans up our pointer to the IMosProvider
//
////////////////////////////////////////////////////////////////////////
Provider::~Provider( void )
{
// get out of the framework's hair
CWbemProviderGlue::FrameworkLogoff( (LPCWSTR)m_name, (LPCWSTR)m_strNameSpace );
// we can't release the interfaces here because CIMOM has a habit
// of shutting down when it still has interface pointers open.
/********************
// Release the pointer returned to us by GetNamespaceConnection(), which
// will return us an AddRefed pointer.
if ( NULL != m_pIMosProvider )
{
m_pIMosProvider->Release();
}
// The class object is returned to us by IMOSProvider::GetObject, so
// we should try to release it here when we're done with it.
if ( NULL != m_piClassObject )
{
m_piClassObject->Release();
}
******************************/
}
////////////////////////////////////////////////////////////////////////
//
// Function: Provider::InitComputerName
//
// Initializes our static computer name variable.
//
// Inputs: None.
//
// Outputs: None.
//
// Return: None.
//
// Comments: Because the idea behind creating providers is that
// a single static instance is instantiated, this function
// will most likely be called as part of DLL loading, we'll
// introduce some thread safety here using a named mutex
// but won't worry too much about it other than that.
//
////////////////////////////////////////////////////////////////////////
void Provider::InitComputerName( void )
{
// For performance, check if the value is empty. Only if it
// is, should we then bother with going through a thread-safe
// static initialization. Because we are using a named mutex,
// multiple threads will get the same kernel object, and will
// be stop-gapped by the OS as they each acquire the mutex
// in turn.
if ( s_strComputerName.IsEmpty() )
{
CreateMutexAsProcess createMutexAsProcess(WBEMPROVIDERSTATICMUTEX);
// Double check in case there was a conflict and somebody else
// got here first.
if ( s_strComputerName.IsEmpty() )
{
DWORD dwBuffSize = MAX_COMPUTERNAME_LENGTH + 1;
// Make sure the string buffer will be big enough to handle the
// value.
LPWSTR pszBuffer = s_strComputerName.GetBuffer( dwBuffSize );
if ( NULL != pszBuffer )
{
// Now grab the computer name and release the buffer, forcing
// it to reallocate itself to the new length.
if (!FRGetComputerName( pszBuffer, &dwBuffSize )) {
wcscpy(pszBuffer, L"DEFAULT");
}
s_strComputerName.ReleaseBuffer();
} // IF NULL != pszBuffer
} // IF strComputerName.IsEmpty()
} // IF strComputerName.IsEmpty()
}
////////////////////////////////////////////////////////////////////////
//
// Function: Flush
//
// flushes out all unnecessary memory usage
// inlcuding the (unimplemented) cache
// and the class object we clone from
//
// Inputs: nope
//
// Outputs:
//
// Return: the eternal void
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
void Provider::Flush()
{
// TODO: implement cache flush
BeginWrite();
try
{
if (m_piClassObject)
{
m_piClassObject->Release();
m_piClassObject = NULL;
}
if ( NULL != m_pIMosProvider )
{
m_pIMosProvider->Release();
m_pIMosProvider = NULL;
}
}
catch ( ... )
{
EndWrite();
throw;
}
EndWrite();
}
////////////////////////////////////////////////////////////////////////
//
// Function: ValidateIMOSPointer
//
// Verifies in a threadsafe manner, that our IWBEMServices pointer
// is okay.
//
// Inputs: None.
//
// Outputs:
//
// Return: TRUE/FALSE success/failure
//
// Comments: Requires that our NameSpace be valid.
//
////////////////////////////////////////////////////////////////////////
BOOL Provider::ValidateIMOSPointer( )
{
// if we don't have a Namespace connection, get one. Be aware that for
// speed's sake we are testing the value outside of a critical section, but
// because two threads may enter this block of code simultaneously, this
// block is testing one more time inside the critical sections.
// if ( NULL == m_pIMosProvider )
// {
// BeginWrite();
//
// try
// {
//
// // See above (it's a redundant test), but keeps us from leaking and
// // overwriting the value twice.
//
// if ( NULL == m_pIMosProvider )
// {
// m_pIMosProvider = CWbemProviderGlue::GetNamespaceConnection( m_strNameSpace, pwszIID );
// }
// }
// catch ( ... )
// {
// EndWrite();
// throw;
// }
//
// EndWrite();
// }
//
// if (m_pIMosProvider == NULL)
// {
// throw CFramework_Exception(L"ValidateIMOSPointer failed");
// }
//
// return ( NULL != m_pIMosProvider );
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Function: CreateNewInstance
//
//
//
// Inputs: MethodContext* - context that this instance belongs to
//
// Outputs:
//
// Return: CInstance*
//
// Comments: caller is responsible for memory
//
////////////////////////////////////////////////////////////////////////
CInstance* Provider::CreateNewInstance( MethodContext* pMethodContext )
{
HRESULT hr = WBEM_S_NO_ERROR;
CInstance* pNewInstance = NULL;
IWbemClassObjectPtr pClassObject (GetClassObjectInterface(pMethodContext), false);
IWbemClassObjectPtr piClone;
hr = pClassObject->SpawnInstance(0, &piClone);
if (SUCCEEDED(hr))
{
// The Instance is responsible for its own AddRef/Releasing
pNewInstance = new CInstance(piClone, pMethodContext);
if (pNewInstance == NULL)
{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
}
else
{
throw CFramework_Exception(L"SpawnInstance failed", hr);
}
return pNewInstance;
}
////////////////////////////////////////////////////////////////////////
//
// Function: Commit
//
// sends instance to CIMOM
//
// Inputs: CInstance* pInstance - the instance to pass off to cimom,
// bool bCache - should we cache this puppy? (unimplemented)
//
// Outputs:
//
// Return:
//
// Comments: do not reference pointer once committed, it may not exist any more!
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::Commit(CInstance* pInstance, bool bCache /* = false*/)
{
HRESULT hRes = WBEM_S_NO_ERROR;
// allow derived classes to fill out extra info.
// GetExtendedProperties(pInstance);
hRes = pInstance->Commit();
// TODO: Implement cache
// if !bCache...
// We're done with pInstance, so...
pInstance->Release();
return hRes;
}
////////////////////////////////////////////////////////////////////////
//
// Function: ExecuteQuery
//
//
//
// Inputs: IWbemContext __RPC_FAR * pCtx,
//
// Outputs:
//
// Return: HRESULT
//
// Comments: Calls a provider's ExecQuery function, or returns
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::ExecuteQuery( MethodContext* pContext, CFrameworkQuery& pQuery, long lFlags /*= 0L*/ )
{
HRESULT hr = ValidateQueryFlags(lFlags);
// Make sure we've got Managed Object Services avaliable, as we will need
// it to get WBEMClassObjects for constructing Instances.
if ( SUCCEEDED(hr) && ValidateIMOSPointer( ) )
{
// Check to see if this is an extended query
CFrameworkQueryEx *pQuery2 = static_cast <CFrameworkQueryEx*>(&pQuery);
if (pQuery2->IsExtended())
{
// It is an extended query. Does the provider support them?
if (FAILED(ValidateQueryFlags(WBEM_FLAG_FORWARD_ONLY)))
{
// We have an extended query, but the provider doesn't support it
hr = WBEM_E_INVALID_QUERY;
}
}
if (SUCCEEDED(hr))
{
// Tell cimom he's got work to do on the instances when we send
// them back.
pContext->QueryPostProcess();
// If the client hasn't overridden the class, we get back
// WBEM_E_PROVIDER_NOT_CAPABLE. In that case, call the enumerate, and let
// CIMOM do the work
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::ProviderTimer);
hr = ExecQuery(pContext, pQuery, lFlags);
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::FrameworkTimer);
if (hr == WBEM_E_PROVIDER_NOT_CAPABLE)
{
// Get the instances
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::ProviderTimer);
hr = CreateInstanceEnum(pContext, lFlags);
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::FrameworkTimer);
}
}
else
{
hr = WBEM_E_INVALID_QUERY;
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////
//
// Function: CreateInstanceEnum
//
//
//
// Inputs: IWbemContext __RPC_FAR * pCtx,
// IWbemObjectSink __RPC_FAR * pResponseHandler
// Outputs:
//
// Return:
//
// Comments: enumerate all instances of this class
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::CreateInstanceEnum( MethodContext* pContext, long lFlags /*= 0L*/ )
{
HRESULT sc = ValidateEnumerationFlags(lFlags);
// Make sure we've got Managed Object Services avaliable, as we will need
// it to get WBEMClassObjects for constructing Instances.
if ( SUCCEEDED(sc) && ValidateIMOSPointer( ) )
{
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::ProviderTimer);
sc = EnumerateInstances( pContext, lFlags );
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::FrameworkTimer);
}
return sc;
}
////////////////////////////////////////////////////////////////////////
//
// Function: PutInstance
//
// CIMOM wants us to put this instance.
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::PutInstance(const CInstance& newInstance, long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
////////////////////////////////////////////////////////////////////////
//
// Function: PutInstance
//
// CIMOM wants us to put this instance.
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::PutInstance( IWbemClassObject __RPC_FAR *pInst,
long lFlags,
MethodContext* pContext )
{
HRESULT scode = ValidatePutInstanceFlags(lFlags);
// No need to AddRef()/Release() pInst here, since we're just
// passing it into the CInstance object, which should take
// care of that for us internally.
if (SUCCEEDED(scode))
{
CInstancePtr pInstance (new CInstance( pInst, pContext ), false);
if ( NULL != pInstance )
{
scode = PutInstance(*pInstance, lFlags);
}
else
{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
}
return scode;
}
////////////////////////////////////////////////////////////////////////
//
// Function: DeleteInstance
//
// CIMOM wants us to delete this instance.
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::DeleteInstance(const CInstance& newInstance, long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
////////////////////////////////////////////////////////////////////////
//
// Function: DeleteInstance
//
// CIMOM wants us to put this instance.
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::DeleteInstance( ParsedObjectPath* pParsedObjectPath,
long lFlags,
MethodContext* pContext )
{
HRESULT sc = ValidateDeletionFlags(lFlags);
// Make sure we've got Managed Object Services avaliable, as we will
// need it in order to create a brand new instance.
if ( SUCCEEDED(sc) && ValidateIMOSPointer( ) )
{
CInstancePtr pInstance (CreateNewInstance( pContext ), false);
// Load up the instance keys
if ( SetKeyFromParsedObjectPath( pInstance, pParsedObjectPath ) )
{
sc = DeleteInstance(*pInstance, lFlags);
}
else
{
sc = WBEM_E_INVALID_OBJECT_PATH;
}
}
return sc;
}
////////////////////////////////////////////////////////////////////////
//
// Function: ExecMethod
//
// CIMOM wants us to execute this method on this instance
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::ExecMethod(const CInstance& pInstance,
BSTR bstrMethodName,
CInstance *pInParams,
CInstance *pOutParams,
long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
////////////////////////////////////////////////////////////////////////
//
// Function: ExecMethod
//
// CIMOM wants us to Execute this method on this instance
//
// Inputs:
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::ExecMethod( ParsedObjectPath *pParsedObjectPath,
BSTR bstrMethodName,
long lFlags,
CInstance *pInParams,
CInstance *pOutParams,
MethodContext *pContext )
{
HRESULT sc = ValidateMethodFlags(lFlags);
// Make sure we've got Managed Object Services avaliable, as we will
// need it in order to create a brand new instance.
if ( SUCCEEDED(sc) && ValidateIMOSPointer( ) )
{
CInstancePtr pInstance(CreateNewInstance( pContext ), false);
if ( SetKeyFromParsedObjectPath( pInstance, pParsedObjectPath ) )
{
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::ProviderTimer);
sc = ExecMethod(*pInstance, bstrMethodName, pInParams, pOutParams, lFlags);
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::FrameworkTimer);
}
else
{
sc = WBEM_E_INVALID_OBJECT_PATH;
}
}
return sc;
}
////////////////////////////////////////////////////////////////////////
//
// Function: GetObject
//
// called by the framework in response to a GetObject from CIMOM
//
// Inputs: ParsedObjectPath* pParsedObjectPath - All the news
// thats fit to print.
// IWbemContext __RPC_FAR* pCtx
// IWbemObjectSink __RPC_FAR*pResponseHandler
//
//
// Outputs:
//
// Return:
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
HRESULT Provider::GetObject( ParsedObjectPath *pParsedObjectPath,
MethodContext *pContext,
long lFlags /*= 0L*/ )
{
HRESULT hr = ValidateGetObjFlags(lFlags);
// Make sure we've got Managed Object Services avaliable, as we will
// need it in order to create a brand new instance.
if ( SUCCEEDED(hr) && ValidateIMOSPointer( ) )
{
CInstancePtr pInstance (CreateNewInstance( pContext ), false);
// Load up the instance keys
if ( SetKeyFromParsedObjectPath( pInstance, pParsedObjectPath ) )
{
// Look for per-property gets
IWbemContextPtr pWbemContext (pContext->GetIWBEMContext(), false);
CFrameworkQueryEx CQuery;
hr = CQuery.Init(pParsedObjectPath, pWbemContext, GetProviderName(), m_strNameSpace);
// Note that 'SUCCEEDED' DOESN'T mean that we have per-property gets. It
// just means that the query object was successfully initialized.
if (SUCCEEDED(hr))
{
// Fill in key properties on query object
IWbemClassObjectPtr pWbemClassObject(pInstance->GetClassObjectInterface(), false);
CQuery.Init2(pWbemClassObject);
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::ProviderTimer);
hr = GetObject(pInstance, lFlags, CQuery);
PROVIDER_INSTRUMENTATION_START(pContext, StopWatch::FrameworkTimer);
}
}
else
{
hr = WBEM_E_INVALID_OBJECT_PATH;
}
if (SUCCEEDED(hr))
{
// Account for the possibility that we have a SUCCESS code back from GetObject.
HRESULT hRes = pInstance->Commit();
hr = __max((ULONG)hRes, (ULONG)hr);
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////
//
// Function: Provider::GetInstancePath
//
// Attempts to build an instance path for the supplied CInstance pointer.
//
// Inputs: const CInstance* pInstance - Instance to build path for.
//
// Outputs: CHString& strPath - Path from instance.
//
// Return: BOOL Success/Failure.
//
// Comments: This function was created to help support the internal
// short circuit we performed for obtaining local WBEM
// Provider objects. In this instance, we will use our
// computer system name, namespace and instance relative
// path to munge together a full WBEM Object Path. This
// is because only CIMOM objects will have this value set
// and when we perform our short circuit, we cut CIMOM
// out of the loop, so our instances don't have full
// object paths. This mostly helps out our association
// logic, although a weakness of this solution is that
// if the path that gets stored by CIMOM changes, we
// will then need to change this function.
//
////////////////////////////////////////////////////////////////////////
bool Provider::GetLocalInstancePath( const CInstance *pInstance,
CHString& strPath )
{
bool fReturn = false;
CHString strRelativePath;
if (pInstance && pInstance->GetCHString( L"__RELPATH", strRelativePath ) )
{
// We may want to use the OBJPath classes to piece this
// together for us at a later time.
strPath = MakeLocalPath(strRelativePath);
fReturn = true;
}
return fReturn;
}
////////////////////////////////////////////////////////////////////////
//
// Function: Provider::MakeLocalPath
//
// Builds a full instance path from a relative path
//
// Inputs: const CHString &strRelPath - Relative path
//
// Outputs:
//
// Return: CHString& strPath - Path
//
// Comments: Consider using GetLocalInstance path before using
// this function.
//
////////////////////////////////////////////////////////////////////////
CHString Provider::MakeLocalPath( const CHString &strRelPath )
{
ASSERT_BREAK( (strRelPath.Find(L':') == -1) || ((strRelPath.Find(L'=') != -1) && (strRelPath.Find(L':') >= strRelPath.Find(L'=')) ));
CHString sBase;
sBase.Format(L"\\\\%s\\%s:%s",
(LPCWSTR)s_strComputerName,
m_strNameSpace.IsEmpty() ? DEFAULT_NAMESPACE: (LPCWSTR) m_strNameSpace,
(LPCWSTR)strRelPath);
return sBase;
}
////////////////////////////////////////////////////////////////////////
//
// Function: SetKeyFromParsedObjectPath
//
// called by the DeleteInstance and GetObject in order to load a
// CInstance* with the key values in an object path.
//
// Inputs: CInstance* pInstance - Instance to store
// key values in.
// ParsedObjectPath* pParsedObjectPath - All the news
// thats fit to print.
//
//
// Outputs:
//
// Return: BOOL Success/Failure
//
// Comments:
//
////////////////////////////////////////////////////////////////////////
BOOL Provider::SetKeyFromParsedObjectPath( CInstance *pInstance,
ParsedObjectPath *pParsedPath )
{
BOOL fReturn = TRUE;
SAFEARRAY *pNames = NULL;
long lLBound, lUBound;
// populate instance - This exact same routine is in wbemglue.cpp. Changes here should be
// reflected there (or someone should move these two somewhere else. instance.cpp?).
for (DWORD i = 0; fReturn && i < (pParsedPath->m_dwNumKeys); i++)
{
if (pParsedPath->m_paKeys[i])
{
// If a name was specified in the form class.keyname=value
if (pParsedPath->m_paKeys[i]->m_pName != NULL)
{
fReturn = pInstance->SetVariant(pParsedPath->m_paKeys[i]->m_pName, pParsedPath->m_paKeys[i]->m_vValue);
}
else
{
// There is a special case that you can say class=value
fReturn = FALSE;
// only one key allowed in the format. Check the names on the path
if (pParsedPath->m_dwNumKeys == 1)
{
// Get the names from the object
if (m_piClassObject->GetNames(NULL, WBEM_FLAG_KEYS_ONLY, NULL, &pNames) == WBEM_S_NO_ERROR)
{
BSTR t_bstrName = NULL ;
try
{
SafeArrayGetLBound(pNames, 1, &lLBound);
SafeArrayGetUBound(pNames, 1, &lUBound);
// Only one key?
if ((lUBound - lLBound) == 0)
{
// Get the name of the key field and set it
SafeArrayGetElement(pNames, &lUBound, &t_bstrName );
fReturn = pInstance->SetVariant( t_bstrName, pParsedPath->m_paKeys[i]->m_vValue);
}
}
catch ( ... )
{
if( NULL != t_bstrName )
{
SysFreeString( t_bstrName ) ;
}
SafeArrayDestroy(pNames);
throw;
}
SafeArrayDestroy(pNames);
}
}
ASSERT_BREAK(fReturn); // somebody lied about the number of keys or the datatype was wrong
}
}
else
{
ASSERT_BREAK(0); // somebody lied about the number of keys!
fReturn = FALSE;
}
}
return fReturn;
}
// sets the CreationClassName to the name of this provider
bool Provider::SetCreationClassName(CInstance* pInstance)
{
if (pInstance)
{
return pInstance->SetCHString(IDS_CreationClassName, m_name);
}
else
{
return false;
}
}
// flag validation - returns WBEM_E_UNSUPPORTED parameter if
// lFlags contains any flags not found in lAcceptableFlags
HRESULT Provider::ValidateFlags(long lFlags, FlagDefs lAcceptableFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
// invert the acceptable flags, which then are the UNacceptable flags
if (lFlags & ~((long)lAcceptableFlags))
hr = WBEM_E_UNSUPPORTED_PARAMETER;
else
hr = WBEM_S_NO_ERROR;
return hr;
}
// base level validation routines
// you can override these in order to support a flag
// that is unknown to the base class
HRESULT Provider::ValidateEnumerationFlags(long lFlags)
{
return ValidateFlags(lFlags, EnumerationFlags);
}
HRESULT Provider::ValidateGetObjFlags(long lFlags)
{
return ValidateFlags(lFlags, GetObjFlags);
}
HRESULT Provider::ValidateMethodFlags(long lFlags)
{
return ValidateFlags(lFlags, MethodFlags);
}
HRESULT Provider::ValidateQueryFlags(long lFlags)
{
return ValidateFlags(lFlags, QueryFlags);
}
HRESULT Provider::ValidateDeletionFlags(long lFlags)
{
return ValidateFlags(lFlags, DeletionFlags);
}
HRESULT Provider::ValidatePutInstanceFlags(long lFlags)
{
return ValidateFlags(lFlags, PutInstanceFlags);
}
IWbemClassObject* Provider::GetClassObjectInterface(MethodContext *pMethodContext)
{
IWbemClassObject *pObject = NULL;
if (ValidateIMOSPointer())
{
BOOL bWriting = TRUE;
BeginWrite();
try
{
if ( NULL == m_piClassObject )
{
bWriting = FALSE;
//calling back into winmgmt - no critsec!
EndWrite();
IWbemContextPtr pWbemContext;
if ( NULL != pMethodContext )
{
pWbemContext.Attach(pMethodContext->GetIWBEMContext());
}
IWbemServicesPtr pServices(CWbemProviderGlue::GetNamespaceConnection( m_strNameSpace, pMethodContext ), false);
HRESULT hr = pServices->GetObject( bstr_t( m_name ), 0L, pWbemContext, &pObject, NULL);
BeginWrite();
bWriting = TRUE;
if (SUCCEEDED(hr))
{
if (m_piClassObject == NULL)
{
m_piClassObject = pObject;
pObject->AddRef();
}
}
else
{
// belt & suspenders check. Won't hurt.
m_piClassObject = NULL;
throw CFramework_Exception(L"SpawnInstance failed", hr);
}
}
else
{
pObject = m_piClassObject;
pObject->AddRef();
}
}
catch ( ... )
{
if (bWriting)
{
EndWrite();
}
if (pObject)
{
pObject->Release();
pObject = NULL;
}
throw;
}
EndWrite();
}
return pObject;
}
// If a provider wants to process queries, they should override this
HRESULT Provider::ExecQuery(MethodContext *pMethodContext, CFrameworkQuery& pQuery, long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
// find and create all instances of your class
HRESULT Provider::EnumerateInstances(MethodContext* pMethodContext, long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
// you will be given an object with the key properties filled in.
// you need to fill in all of the rest of the properties
HRESULT Provider::GetObject(CInstance* pInstance, long lFlags /*= 0L*/)
{
return WBEM_E_PROVIDER_NOT_CAPABLE;
}
// You will be given an object with the key properties filled in.
// You can either fill in all the properties, or check the Query object
// to see what properties are required.
HRESULT Provider::GetObject(CInstance *pInstance, long lFlags, CFrameworkQuery &Query)
{
// If we are here, the provider didn't override this method. Fall back to the older
// call.
return GetObject(pInstance, lFlags);
}