|
|
//***************************************************************************
//
// Copyright � Microsoft Corporation. All rights reserved.
//
// WBEMGLUE.CPP
//
// Purpose: Implementation of CWbemProviderGlue class
//
//***************************************************************************
#include "precomp.h"
#include <assertbreak.h>
#include <eventProvider.h>
#include <FRQueryEx.h>
#include <cnvmacros.h>
#include <BrodCast.h>
#include <cominit.h>
#include <StopWatch.h>
#include <comdef.h>
#include <SmartPtr.h>
#include <lmcons.h>
#define SECURITY_WIN32
#include <sspi.h>
#include <Secext.h>
#include "FWStrings.h"
#include "MultiPlat.h"
#include <AutoImpRevert.h>
#include <lockwrap.h>
#include <winbasep.h>
#include <helper.h>
typedef FrameDynOnDelete < CRITICAL_SECTION *, VOID ( * ) ( LPCRITICAL_SECTION ), LeaveCriticalSection > LeaveCriticalSectionScope; typedef WaitException < CRITICAL_SECTION *, VOID ( * ) ( LPCRITICAL_SECTION ), EnterCriticalSection, 1000 > EnterCriticalSectionWait;
class CWbemGlueImpersonation { CWbemGlueImpersonation ( const CWbemGlueImpersonation& ) {}
HRESULT m_hr;
public:
CWbemGlueImpersonation () : m_hr ( E_FAIL ) { m_hr = CWbemProviderGlue::CheckImpersonationLevel (); }
~CWbemGlueImpersonation () { if SUCCEEDED ( m_hr ) { WbemCoRevertToSelf (); } }
HRESULT IsImpersonated () const { return m_hr; } };
#define GLUETIMEOUT WBEM_INFINITE //(3 * 60 * 1000)
// Used in ASSERT_BREAK to give meaningful messages
#define DEPRECATED 1
#define MEMORY_EXHAUSTED 0
#define FRAMEWORK_EXCEPTION 0
#define UNSPECIFIED_EXCEPTION 0
#define STRUCTURED_EXCEPTION 0
#define DUPLICATE_RELEASE 0
#define IMPERSONATION_REVERTED 0
#define UNNECESSARY_CWBEMPROVIDERGLUE_INSTANCE 0
// Initialize Statics
STRING2LPVOID CWbemProviderGlue::s_providersmap; CCritSec CWbemProviderGlue::s_csFactoryMap; PTR2PLONG CWbemProviderGlue::s_factorymap; CCritSec CWbemProviderGlue::s_csProviderMap; CCritSec CWbemProviderGlue::m_csStatusObject; IWbemClassObject *CWbemProviderGlue::m_pStatusObject = NULL; BOOL CWbemProviderGlue::s_bInitted = FALSE; DWORD CWbemProviderGlue::s_dwPlatform = 0; DWORD CWbemProviderGlue::s_dwMajorVersion = 0; WCHAR CWbemProviderGlue::s_wstrCSDVersion[_MAX_PATH] = {0};
long CWbemProviderGlue::s_lObjects = 0;
// Static Provider we use to initialize, uninitialize our static
// data. We should be able to assume at Construct/Destruct time that
// we (the DLL) are being loaded/unloaded.
// later on -- we should, but we can't. Current model is that we
// uninitialize when the last DLL that we service has called DLLLogoff,
// which had better be in response to "DllCanUnloadNow"
CWbemProviderGlue g_wbemprovider;
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::CWbemProviderGlue
//
// Class CTor. Uses static initialization functon to get static data
// ready if this is the first instance of our object.
//
// Inputs: None
//
// Outputs: None.
//
// Returns: None.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
CWbemProviderGlue::CWbemProviderGlue() : m_strNamespace(), m_lRefCount(0), m_pCount(NULL), m_pServices(NULL) { Init(); }
CWbemProviderGlue::CWbemProviderGlue(PLONG pCount) : m_strNamespace(), m_lRefCount(0), m_pCount(pCount), m_pServices(NULL) { CWbemProviderGlue::IncrementMapCount(pCount); }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::~CWbemProviderGlue
//
// Class DTor.
//
// Inputs: None
//
// Outputs: None.
//
// Returns: None.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
CWbemProviderGlue::~CWbemProviderGlue() { // Note that the item we are destructing here was not added in
// the constructor, but in Initialize().
if (m_pServices) { m_pServices->Release(); }
if (m_pCount != NULL) // Indicates the static instance
{ if (DecrementMapCount(m_pCount) == 0) { FlushAll(); } } else { UnInit(); } }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::Init
//
// Static initialization function for initializing critical sections
// and such for making our static data thread-safe.
//
// Inputs: None.
//
// Outputs: None.
//
// Returns: None.
//
// Comments: Because we are protecting static data, we are using
// a named mutex. Construction and Destruction of object
// instances should call these functions.
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::Init( void ) { LogMessage(IDS_GLUEINIT);
if (!s_bInitted) { // Note that we *have* to use the ansi version at this point,
// since this is where we decide whether to use the ansi functions
// or the unicode ones.
OSVERSIONINFOA OsVersionInfoA;
OsVersionInfoA.dwOSVersionInfoSize = sizeof (OSVERSIONINFOA) ; GetVersionExA(&OsVersionInfoA);
s_dwPlatform = OsVersionInfoA.dwPlatformId; s_dwMajorVersion = OsVersionInfoA.dwMajorVersion;
if (OsVersionInfoA.szCSDVersion == NULL) { s_wstrCSDVersion[0] = L'\0'; } else { bool t_ConversionFailure = false ; WCHAR *wcsBuffer = NULL ; ANSISTRINGTOWCS(OsVersionInfoA.szCSDVersion, wcsBuffer, t_ConversionFailure ); if ( ! t_ConversionFailure ) { if ( wcsBuffer ) { StringCchCopyW(s_wstrCSDVersion, _MAX_PATH, wcsBuffer); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } else { // Should do something here since we know version is not initialised.
} }
s_bInitted = TRUE; } else { ASSERT_BREAK(UNNECESSARY_CWBEMPROVIDERGLUE_INSTANCE); } }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::UnInit
//
// Static cleanup function for cleaning up critical sections
// and such for making our static data thread-safe.
//
// Inputs: None.
//
// Outputs: None.
//
// Returns: None.
//
// Comments: Because we are protecting static data, we are using
// a named mutex. Construction and Destruction of object
// instances should call these functions.
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::UnInit( void ) { try { LogMessage(IDS_GLUEUNINIT); } catch ( ... ) { } }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetStaticMutex
//
// Creates and returns an instance of the named mutex used to
// protect our static initialization functions.
//
// Inputs: None.
//
// Outputs: None.
//
// Returns: None.
//
// Comments: The mutex, although it is named, makes the process
// id part of the name, guaranteeing that it is still
// unique across processes.
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::QueryInterface
//
// COM function called to ask us if we support a particular
// face type. If so, we addref ourselves and return the
// ourselves as an LPVOID.
//
// Inputs: REFIID riid - Interface being queried for.
//
// Outputs: LPVOID FAR* ppvObj - Interface pointer.
//
// Returns: None.
//
// Comments: The only interfaces we support are IID_IUnknown and
// IID_IWbemServices.
//
/////////////////////////////////////////////////////////////////////
STDMETHODIMP CWbemProviderGlue::QueryInterface( REFIID riid, LPVOID FAR *ppvObj ) { LogMessage(L"CWbemProviderGlue::QueryInterface");
if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IWbemServices *) this; } else if (IsEqualIID(riid, IID_IWbemServices)) { *ppvObj = (IWbemServices *) this; } else if (IsEqualIID(riid, IID_IWbemProviderInit)) { *ppvObj = (IWbemProviderInit *) this; } else { try { *ppvObj = NULL ; if (IsVerboseLoggingEnabled()) { WCHAR wcID[128]; StringFromGUID2(riid, wcID, 128);
LogMessage2(L"CWbemProviderGlue::QueryInterface - unsupported interface (%s)", wcID); } } catch ( ... ) { }
return ResultFromScode(E_NOINTERFACE) ; }
AddRef() ;
return NOERROR ; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::AddRef
//
// Increments the reference count on this object.
//
// Inputs: None.
//
// Outputs: None.
//
// Returns: ULONG - Our Reference Count.
//
// Comments: Requires that a correponding call to Release be
// performed.
//
/////////////////////////////////////////////////////////////////////
ULONG CWbemProviderGlue::AddRef( void ) { CSetStructuredExceptionHandler t_ExceptionHandler;
try { if (IsVerboseLoggingEnabled()) { // this will be an approximation because another thread could come through...
LogMessage2(L"CWbemProviderGlue::AddRef, count is (approx) %d", m_lRefCount +1); }; } catch ( ... ) { }
// InterlockedIncrement does not necessarily return the
// correct value, only whether the value is <, =, > 0.
// However it is guaranteed threadsafe.
return InterlockedIncrement( &m_lRefCount ); }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::Intialize
//
// Inputs: Many.
//
// Outputs: None.
//
// Returns:
//
// Comments: any global initializations, esp those that call CIMOM should go here.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::Initialize( /* [in] */ LPWSTR pszUser, /* [in] */ LONG lFlags, /* [in] */ LPWSTR pszNamespace, /* [in] */ LPWSTR pszLocale, /* [in] */ IWbemServices __RPC_FAR *pNamespace, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink) { CSetStructuredExceptionHandler t_ExceptionHandler; HRESULT hr = WBEM_S_NO_ERROR;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s(%s)", IDS_GLUEINITINTERFACE, pszNamespace); } } catch ( ... ) { }
if ( (NULL != pszNamespace) && (NULL != pNamespace) ) { try { // this may come back to bite me
// CIMOM promises that this will only be called on one thread, once per object
// and that no queries will be issued until after initialize is called.
// therefore - I don't need a critical section, here -
m_strNamespace = pszNamespace; m_strNamespace.MakeUpper();
pNamespace->AddRef(); m_pServices = pNamespace; } catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } } else { hr = WBEM_E_FAILED; }
if (pInitSink) { pInitSink->SetStatus(hr, 0); hr = WBEM_S_NO_ERROR; }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::Release
//
// Decrements the reference count on this object.
//
// Inputs: None.
//
// Outputs: None.
//
// Returns: ULONG - Our Reference Count.
//
// Comments: When the ref count hits zero, the object is deleted.
//
/////////////////////////////////////////////////////////////////////
ULONG CWbemProviderGlue::Release() { // InterlockedDecrement does not necessarily return the
// correct value, only whether the value is <, =, > 0.
// However it is guaranteed threadsafe.
// We want to hold the value locally in case two threads
// Release at the same time and one gets a final release,
// and deletes, leaving a potential window in which a thread
// deletes the object before the other returns and tries to
// reference the value from within the deleted object.
CSetStructuredExceptionHandler t_ExceptionHandler; ULONG nRet = InterlockedDecrement( &m_lRefCount );
try { if (IsVerboseLoggingEnabled()) { LogMessage2(L"CWbemProviderGlue::Release, count is (approx) %d", m_lRefCount); } } catch ( ... ) { }
if( 0 == nRet ) { try { LogMessage(IDS_GLUEREFCOUNTZERO); } catch ( ... ) { } delete this; } else if (nRet > 0x80000000) { ASSERT_BREAK(DUPLICATE_RELEASE); }
return nRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FlushAll
//
// Inputs: voidness
//
// Outputs: more voidness
//
// Returns: see above
//
// Comments: flushes caches, calls all of the provider's flushes.
// no need to flush event providers map, flush will be
// called on the provider pointer
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::FlushAll(void) { PROVIDERPTRS::iterator setIter;
// We DEFINITELY want to protect the Map while this is running!
EnterCriticalSectionWait ecs ( &s_csProviderMap ); LeaveCriticalSectionScope lcs ( &s_csProviderMap );
try { // pProvider doesn't get addref'ed, so doesn't need to be released
Provider *pProvider = NULL;
EnterCriticalSectionWait ecs1 ( &m_csFlushPtrs ); LeaveCriticalSectionScope lcs1 ( &m_csFlushPtrs );
for (setIter = m_FlushPtrs.begin(); setIter != m_FlushPtrs.end(); setIter++) { pProvider = (Provider*) *setIter; if ( pProvider != NULL ) { // If one provider poops out, try the others.
try { pProvider->Flush(); } catch ( ... ) { } } }
m_FlushPtrs.clear(); } catch ( ... ) { // we should not be here
// do not re-throw (called from destructor)
}
lcs.Exec ();
if (m_pStatusObject) { EnterCriticalSectionWait ecs1 ( &m_csStatusObject ); LeaveCriticalSectionScope lcs1 ( &m_csStatusObject );
if (m_pStatusObject) { m_pStatusObject->Release(); m_pStatusObject = NULL; } } }
// SetStatusObject
// sets the properties in the extended status object so that it can be returned when
// the glue layer calls SetStatus at the end of the method invocation.
// will return false if the status object has already been filled.
// (first one in wins)
bool CWbemProviderGlue::SetStatusObject(
MethodContext *pContext, LPCWSTR pNamespace, LPCWSTR pDescription, HRESULT hr, const SAFEARRAY *pPrivilegesNotHeld,/* = NULL */ const SAFEARRAY *pPrivilegesRequired/* = NULL */ ) { bool bRet = false;
ASSERT_BREAK(pContext != NULL); if (pContext) { IWbemClassObjectPtr pObj ( GetStatusObject(pContext, pNamespace), false );
if (pObj != NULL) { // Variant_t handles the VariantInit/VariantClear
variant_t v;
pContext->SetStatusObject(pObj);
// set hresult ("StatusCode")
v.vt = VT_I4; v.lVal = (long)hr; pObj->Put(IDS_STATUSCODE, 0, &v, NULL); v.Clear();
// set description
if (pDescription) { v = pDescription;
if (v.bstrVal != NULL) { bRet = SUCCEEDED(pObj->Put(IDS_DESCRIPTION, 0, &v, NULL)); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
v.Clear(); }
// privileges properties
if (pPrivilegesNotHeld) { SAFEARRAY *pSafeArray = NULL; // blithy casting away the const...
if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)pPrivilegesNotHeld, &pSafeArray ) ) ) { v.vt = VT_BSTR | VT_ARRAY; v.parray = pSafeArray; pObj->Put(IDS_PRIVILEGESNOTHELD, 0, &v, NULL); v.Clear(); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } }
if (pPrivilegesRequired) { SAFEARRAY *pSafeArray = NULL; // blithy casting away the const...
if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)pPrivilegesRequired, &pSafeArray ) ) ) { v.vt = VT_BSTR | VT_ARRAY; v.parray = pSafeArray; pObj->Put(IDS_PRIVILEGESREQUIRED, 0, &v, NULL); v.Clear(); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } } }
return bRet; }
IWbemClassObject *CWbemProviderGlue::GetStatusObject(
MethodContext *pContext, LPCWSTR pNamespace ) { ASSERT_BREAK(pContext != NULL); IWbemClassObject *pStatusObj = NULL;
if (pContext != NULL) { // first time in, we cache the class object
if (!m_pStatusObject) { m_csStatusObject.Enter();
// check again - someone might have snuck in!
if (!m_pStatusObject) { IWbemServicesPtr pSrvc; IWbemContextPtr pWbemContext (pContext->GetIWBEMContext(), false);
pSrvc.Attach ( GetNamespaceConnection( pNamespace, pContext ) ) ; if ( pSrvc ) { // not checking return code, error object should be NULL on error
pSrvc->GetObject( bstr_t( IDS_WIN32PRIVILEGESSTATUS ), 0, pWbemContext, &m_pStatusObject, NULL ); }
} m_csStatusObject.Leave(); }
if (m_pStatusObject) m_pStatusObject->SpawnInstance(0, &pStatusObj); } else { LogErrorMessage(L"NULL parameter to GetStatusObject"); }
return pStatusObj; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::ExecQueryAsync
//
// Place holder for the ExecQuery function.
//
// Inputs: const BSTR QueryFormat - Query Format String
// const BSTR Query - The actual query
// long lFlags - Additional flags.
// IWbemContext __RPC_FAR *pCtx - Context we were called in.
// IWbemObjectSink FAR *pResponseHandler - Response Handler
//
// Outputs: None.
//
// Returns: ULONG - Our Reference Count.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::ExecQueryAsync(
const BSTR QueryFormat, const BSTR Query, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemObjectSink FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
#ifdef PROVIDER_INSTRUMENTATION
StopWatch stopWatch(CHString(IDS_EXECQUERY) + CHString(Query)); stopWatch.Start(StopWatch::FrameworkTimer); #endif
HRESULT hr = WBEM_S_NO_ERROR; IWbemClassObjectPtr pStatusObject;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_EXECQUERY, Query); }
// Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
#ifdef PROVIDER_INSTRUMENTATION
pContext->pStopWatch = &stopWatch; #endif
if (pContext != NULL) { CFrameworkQueryEx CQuery; // hr = CQuery.InitEx(QueryFormat, Query, lFlags, m_strNamespace);
hr = CQuery.Init(QueryFormat, Query, lFlags, m_strNamespace); if (SUCCEEDED(hr)) { // Find the class name for the query
bstr_t bstrClass (CQuery.GetQueryClassName(), false); if ((WCHAR *)bstrClass != NULL) { // Search for the class name in our map of providers, we know which
// namespace we are when we get constructed.
// pProvider doesn't get addref'ed, so doesn't need to be released.
Provider *pProvider = SearchMapForProvider( bstrClass, m_strNamespace ); if ( NULL != pProvider ) {
// Initialize the CQuery.m_keysonly variable. Note that we CAN'T do this as part
// of Init, because we need the pProvider pointer. And we can do the init
// down here, because we need the bstrClass that we get from Init. And we can't
// do this as part of CQuery.KeysOnly because you can't get the IWbemClassObject
// from there.
IWbemClassObjectPtr IClass(pProvider->GetClassObjectInterface(pContext), false); if (IClass != NULL) { CQuery.Init2(IClass);
// Impersonate connected user
CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
// Everything is in place, run the query
hr = pProvider->ExecuteQuery( pContext, CQuery, lFlags );
dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s", wszName2, wszName, Query); } } } else { // we don't know WHY we couldn't get the interface,
// generic error it is...
hr = WBEM_E_FAILED; }
} else { LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, (LPCWSTR)bstrClass); hr = WBEM_E_INVALID_CLASS; } } else { LogErrorMessage(IDS_INVALIDCLASSNAME); hr = WBEM_E_INVALID_CLASS; } }
pStatusObject.Attach(pContext->GetStatusObject()); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage3(L"%s%s - Succeeded", IDS_EXECQUERY, Query); else LogMessage4(L"%s%s - FAILED (%x)", IDS_EXECQUERY, Query, hr); } } catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
// We must call SetStatus so CIMOM doesn't lose any threads.
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER)) { #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
hr = WBEM_S_NO_ERROR; }
Release();
#ifdef PROVIDER_INSTRUMENTATION
stopWatch.Stop(); stopWatch.LogResults(); #endif
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::CreateInstanceEnumAsync
//
// Locates the provider for the specified class name and
// calls its CreateInstanceEnum function.
//
// Inputs: const BSTR Class - Name of provider
// long lFlags - Enumeration flags.
// IWbemContext __RPC_FAR *pCtxt - Context pointer
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
// handler.
//
// Outputs: None.
//
// Returns: SCCODE - COM Status.
//
// Comments: None.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::CreateInstanceEnumAsync(
const BSTR a_bstrClass, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemObjectSink __RPC_FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
#ifdef PROVIDER_INSTRUMENTATION
StopWatch stopWatch(CHString(IDS_CREATEINSTANCEENUM) + CHString(Class)); stopWatch.Start(StopWatch::FrameworkTimer); #endif
HRESULT hr = WBEM_E_INVALID_CLASS; IWbemClassObjectPtr pStatusObject; bool bSendStatus = true;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_CREATEINSTANCEENUM, a_bstrClass); }
// Check for per-property gets
CFrameworkQueryEx CQuery; hr = CQuery.Init(NULL, pCtx, a_bstrClass, m_strNamespace);
// Note that we AREN'T calling Init2, which means if they specified "__RELPATH"
// as their property, we won't expand that out to the key names. However, since
// we are going to call ExecQuery, and it reprocesses the query and DOES call
// Init2, this isn't an issue.
// CQuery.Init2(pWbemClassObject);
// If they are doing per-property gets, then turn this into a query.
if (SUCCEEDED(hr)) { if (CQuery.AllPropertiesAreRequired()) { // Search for the class name in our map of providers, we know which
// namespace we are when we get constructed.
// pProvider doesn't get addref'ed, so no release necessary
Provider *pProvider = SearchMapForProvider( a_bstrClass, m_strNamespace );
if ( NULL != pProvider ) { // Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
if ( NULL != pContext ) { CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
#ifdef PROVIDER_INSTRUMENTATION
pContext->pStopWatch = &stopWatch; #endif
hr = pProvider->CreateInstanceEnum( pContext, lFlags );
dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s", wszName2, wszName, a_bstrClass); } } pStatusObject.Attach(pContext->GetStatusObject()); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } else { LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, a_bstrClass); hr = WBEM_E_INVALID_CLASS; bSendStatus = false; } } else { bstr_t bstrtQuery = CQuery.GetQuery();
hr = ExecQueryAsync( L"WQL", bstrtQuery, lFlags, pCtx, pResponseHandler);
// Since execquery sent whatever status is necessary
bSendStatus = false; }
}
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage3(L"%s%s - Succeeded", IDS_CREATEINSTANCEENUM, a_bstrClass); else LogMessage4(L"%s%s - FAILED (%x)", IDS_CREATEINSTANCEENUM, a_bstrClass, hr); } }
catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && bSendStatus) {
#ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject );
#ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
hr = WBEM_S_NO_ERROR; }
Release(); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Stop(); stopWatch.LogResults(); #endif
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetObjectAsync
//
// Parses the supplied object path and hands the request off
// to the appropriate provider.
//
// Inputs: const BSTR ObjPath - Object Path containing
// keys to required object.
// long lFlags - Get Object flags.
// IWbemContext __RPC_FAR *pCtxt - Context pointer
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
// handler.
//
// Outputs: None.
//
// Returns: SCCODE - COM Status.
//
// Comments: None.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::GetObjectAsync(
const BSTR ObjectPath, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemObjectSink __RPC_FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
#ifdef PROVIDER_INSTRUMENTATION
StopWatch stopWatch(CHString(IDS_GETOBJECTASYNC) + CHString(ObjectPath)); stopWatch.Start(StopWatch::FrameworkTimer); #endif
HRESULT hr = WBEM_E_FAILED; bool bLocalError = false; IWbemClassObjectPtr pStatusObject; ParsedObjectPath *pParsedPath = NULL; CObjectPathParser objpathParser;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_GETOBJECTASYNC, ObjectPath); }
// Parse the object path passed to us by CIMOM
// ==========================================
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
if ( 0 == nStatus ) {
// Now try to find the provider based on the class name
// pProvider doesn't get addref'ed, so no release necessary
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
// If we got a provider, let it handle itself like a grown-up provider
// should.
if ( NULL != pProvider ) { // Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
if ( NULL != pContext ) { #ifdef PROVIDER_INSTRUMENTATION
pContext->pStopWatch = &stopWatch; #endif
CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
hr = pProvider->GetObject( pParsedPath, pContext, lFlags ); dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s", wszName2, wszName, ObjectPath); } }
pStatusObject.Attach(pContext->GetStatusObject()); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
} else { LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, pParsedPath->m_pClass); hr = WBEM_E_INVALID_CLASS; bLocalError = true; }
}
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage3(L"%s%s - Succeeded", IDS_GETOBJECTASYNC, ObjectPath); else LogMessage4(L"%s%s - FAILED (%x)", IDS_GETOBJECTASYNC, ObjectPath, hr); }
} catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError) { #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject ); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
hr = WBEM_S_NO_ERROR; }
// Clean up the Parsed Path
if (pParsedPath) { objpathParser.Free( pParsedPath ); }
Release(); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Stop(); stopWatch.LogResults(); #endif
return hr;
}
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::PutInstanceAsync
//
// Locates the provider for the specified class name and
// calls its CreateInstanceEnum function.
//
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
// values to use.
// long lFlags - PutInstance flags.
// IWbemContext __RPC_FAR *pCtxt - Context pointer
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
// handler.
//
// Outputs: None.
//
// Returns: SCCODE - COM Status.
//
// Comments: None.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::PutInstanceAsync(
IWbemClassObject __RPC_FAR *pInst, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemObjectSink __RPC_FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
HRESULT hr = WBEM_E_INVALID_CLASS; variant_t vClass; bool bLocalError = false; IWbemClassObjectPtr pStatusObject;
try { // Set up to get the class name of the instance being passed to us
// ask the framework if it has this class registered for support
// ===============================================================
// Get the class name
pInst->Get( IDS_CLASS, 0, &vClass, NULL, NULL );
if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_PUTINSTANCEASYNC, vClass.bstrVal); }
// pProvider doesn't get addref'ed, so no release necessary
Provider *pProvider = SearchMapForProvider( vClass.bstrVal, m_strNamespace );
// If we got a provider, let it handle itself like a grown-up provider
// should.
if ( NULL != pProvider ) { // Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
if ( NULL != pContext ) { IWbemClassObjectPtr pInstPostProcess; if (SUCCEEDED(hr = PreProcessPutInstanceParms(pInst, &pInstPostProcess, pCtx))) { CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
hr = pProvider->PutInstance( pInstPostProcess, lFlags, pContext );
dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s", wszName2, wszName, vClass.bstrVal); } } } pStatusObject.Attach(pContext->GetStatusObject()); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } else { LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, vClass.bstrVal); hr = WBEM_E_INVALID_CLASS; bLocalError = true; }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage3(L"%s%s - Succeeded", IDS_PUTINSTANCEASYNC, vClass.bstrVal); else LogMessage4(L"%s%s - FAILED (%x)", IDS_PUTINSTANCEASYNC, vClass.bstrVal, hr); } }
catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError) { pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject ); hr = WBEM_S_NO_ERROR; }
Release(); return hr;
}
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::PreProcessPutInstanceParms()
//
// IF __PUT_EXT_PROPERTIES is specified, will parse out the intended properties
// and set to NULL those props that are not explicitly being put.
//
// Inputs: [IN] IWbemClassObject __RPC_FAR *pInstIn - Instance whose values to use.
// [OUT] IWbemClassObject __RPC_FAR **pInstOut - processed instance
// IWbemContext __RPC_FAR *pCtxt - Context pointer
//
// Outputs: None.
//
// Returns: WBEM_S_NO_ERROR if the only extension specified is __PUT_EXT_PROPERTIES
// or if no extensions are specified
// WBEM_E_UNSUPPORTED_PUT_EXTENSION if any other flag is set.
// WBEM_E_SEVERE_SCREWUP if some other darn thing happened.
//
// Comments: You may get a different IWbemObject out than you put in
// it's your responsibility to release it.
// On error - pInstOut is undefined.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::PreProcessPutInstanceParms(
IWbemClassObject __RPC_FAR *pInstIn, IWbemClassObject __RPC_FAR **pInstOut, IWbemContext __RPC_FAR *pCtx ) {
HRESULT hr = WBEM_S_NO_ERROR; // Variant_t handles the VariantInit/VariantClear
variant_t vValue;
if ( pCtx != NULL && SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXTENSIONS", 0, &vValue)) && V_VT(&vValue) == VT_BOOL && V_BOOL(&vValue) == VARIANT_TRUE ) { // easy checks first, are there unsupported parms?
vValue.Clear(); if (SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_STRICT_NULLS", 0, &vValue)) && (V_VT(&vValue) == VT_BOOL) && (V_BOOL(&vValue) == VARIANT_TRUE)) hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION; else { vValue.Clear(); if (SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_ATOMIC", 0, &vValue)) && (V_VT(&vValue) == VT_BOOL) && (V_BOOL(&vValue) == VARIANT_TRUE)) hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION; }
vValue.Clear(); if ((SUCCEEDED(hr) || (hr != WBEM_E_UNSUPPORTED_PUT_EXTENSION)) && SUCCEEDED(hr = pCtx->GetValue( L"__PUT_EXT_PROPERTIES", 0, &vValue))) { if (V_VT(&vValue) == (VT_BSTR|VT_ARRAY)) hr = NullOutUnsetProperties(pInstIn, pInstOut, vValue); else hr = WBEM_E_INVALID_PARAMETER; } else if (hr == WBEM_E_NOT_FOUND) { // well, if we've never heard of it, it MUST be wrong...
hr = WBEM_E_UNSUPPORTED_PUT_EXTENSION; } } else if (hr == WBEM_E_NOT_FOUND) { // no extensions - no problems.
// out interface is same as in interface
hr = WBEM_S_NO_ERROR; *pInstOut = pInstIn; (*pInstOut)->AddRef(); }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::NullOutUnsetProperties
//
// returns a copy of the input class, any properties whose names are listed
// in the variant are set to NULL in the output class
//
//
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
// values to NULL
// VARIANT contains names to not NULL out.
//
// Outputs: None.
//
// Returns: the ubiquitous HRESULT
//
// Comments: Assumes you've done your homework and the Variant
// is a BSTR Array containing property names.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::NullOutUnsetProperties(
IWbemClassObject __RPC_FAR *pInstIn, IWbemClassObject __RPC_FAR **pInstOut, const VARIANT& vValue ) { HRESULT hRes = WBEM_S_NO_ERROR;
// get ourselves a copy to work with
CInstancePtr pInstance;
// Variant_t handles the VariantInit/VariantClear
variant_t vName; variant_t vNameSpace;
hRes = pInstIn->Get(IDS_CLASS, 0, &vName, NULL, NULL);
if (SUCCEEDED(hRes)) { hRes = pInstIn->Get(L"__NAMESPACE", 0, &vNameSpace, NULL, NULL); }
if (SUCCEEDED(hRes) && SUCCEEDED( hRes = GetEmptyInstance(vName.bstrVal, &pInstance, vNameSpace.bstrVal))) { // and off we go...
SAFEARRAY *pNames = vValue.parray; long nBiggestName; if (SUCCEEDED(hRes = SafeArrayGetUBound(pNames, 1, &nBiggestName))) { BSTR t_bstrName = NULL ; *pInstOut = pInstance->GetClassObjectInterface();
variant_t value;
// wander through the names, for every one we find
// copy the property value to the out pointer
for (long i = 0; i <= nBiggestName; i++) { if (SUCCEEDED(SafeArrayGetElement( pNames, &i, &t_bstrName ))) { OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartt_bstrName(t_bstrName);
pInstIn->Get( t_bstrName, 0, &value, NULL, NULL); (*pInstOut)->Put( t_bstrName, 0, &value, 0); } }
// and, oh what the heck - let's copy the keys, too...
SAFEARRAY *pKeyNames = NULL; if (SUCCEEDED(hRes = pInstIn->GetNames(NULL, WBEM_FLAG_KEYS_ONLY, NULL, &pKeyNames))) { OnDelete<SAFEARRAY *,HRESULT(*)(SAFEARRAY *),SafeArrayDestroy> smartpKeyNames(pKeyNames);
SafeArrayGetUBound(pKeyNames, 1, &nBiggestName); for (i = 0; i <= nBiggestName; i++) { if (SUCCEEDED(SafeArrayGetElement( pKeyNames, &i, &t_bstrName ))) { OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartt_bstrName(t_bstrName);
pInstIn->Get( t_bstrName, 0, &value, NULL, NULL ); (*pInstOut)->Put( t_bstrName, 0, &value, 0 ); } } } } else { // failed to get array upper bound!
hRes = WBEM_E_FAILED; } }
return hRes; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::DeleteInstanceAsync
//
// Locates the provider for the specified class name and
// calls its DeleteInstance function.
//
// Inputs: IWbemClassObject __RPC_FAR *pInst - Instance whose
// values to use.
// long lFlags - PutInstance flags.
// IWbemContext __RPC_FAR *pCtxt - Context pointer
// IWbemObjectSink __RPC_FAR *pResponseHandler - Response
// handler.
//
// Outputs: None.
//
// Returns: SCCODE - COM Status.
//
// Comments: None.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::DeleteInstanceAsync(
const BSTR ObjectPath, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemObjectSink __RPC_FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
HRESULT hr = WBEM_E_FAILED; bool bLocalError = false; IWbemClassObjectPtr pStatusObject;
ParsedObjectPath *pParsedPath = NULL; CObjectPathParser objpathParser;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_DELETEINSTANCEASYNC, ObjectPath); }
// Parse the object path passed to us by CIMOM
// ==========================================
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
if ( 0 == nStatus ) { // Now try to find the provider based on the class name
// pProvider doesn't get addref'ed, so no release necessary
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
// If we got a provider, let it handle itself like a grown-up provider
// should.
if ( NULL != pProvider ) { // Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false);
if ( NULL != pContext ) { CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
hr = pProvider->DeleteInstance( pParsedPath, lFlags, pContext );
dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage4(L"Warning! User name at exit (%s) != user name at entry (%s) for %s", wszName2, wszName, ObjectPath); } } pStatusObject.Attach(pContext->GetStatusObject()); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
} else { hr = WBEM_E_INVALID_CLASS; LogErrorMessage4(L"%s (%s:%s)", IDS_PROVIDERNOTFOUND, (LPCWSTR)m_strNamespace, pParsedPath->m_pClass); bLocalError = true; }
} else { LogErrorMessage3(L"%s (%s)", IDS_COULDNOTPARSE, ObjectPath); bLocalError = true; }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage3(L"%s%s - Succeeded", IDS_DELETEINSTANCEASYNC, ObjectPath); else LogMessage4(L"%s%s - FAILED (%x)", IDS_DELETEINSTANCEASYNC, ObjectPath, hr); } }
catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError) { pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject); hr = WBEM_S_NO_ERROR; }
// Clean up the Parsed Path
if (pParsedPath) { objpathParser.Free( pParsedPath ); }
Release(); return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::ExecMethodAsync
//
// Locates the provider for the specified class name and
// calls its ExecMethod function.
//
// Inputs:
// const BSTR ObjectPath, - Object path on which to execute the method
// const BSTR MethodName, - Name of the method to execute
// long lFlags, - Any flags
// IWbemContext __RPC_FAR *pCtx,
// IWbemClassObject __RPC_FAR *pInParams, - Pointer to IWbemClassObject
// that contains parms
// IWbemObjectSink __RPC_FAR *pResponseHandler)
//
// Outputs: None.
//
// Returns: SCCODE - COM Status.
//
// Comments: None.
//
/////////////////////////////////////////////////////////////////////
HRESULT CWbemProviderGlue::ExecMethodAsync(
const BSTR ObjectPath, const BSTR MethodName, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemClassObject __RPC_FAR *pInParams, IWbemObjectSink __RPC_FAR *pResponseHandler ) { // make sure we don't disappear while running
AddRef();
CSetStructuredExceptionHandler t_ExceptionHandler;
#ifdef PROVIDER_INSTRUMENTATION
StopWatch stopWatch(CHString(IDS_EXECMETHODASYNC) + CHString(ObjectPath) + CHString(MethodName)); stopWatch.Start(StopWatch::FrameworkTimer); #endif
HRESULT hr = WBEM_E_FAILED; bool bLocalError = false; IWbemClassObjectPtr pStatusObject;
ParsedObjectPath *pParsedPath = NULL; CObjectPathParser objpathParser;
try { if (IsVerboseLoggingEnabled()) { LogMessage4(L"%s%s.%s", IDS_EXECMETHODASYNC, ObjectPath, MethodName); }
// Parse the object path passed to us by CIMOM
// ==========================================
int nStatus = objpathParser.Parse( ObjectPath, &pParsedPath );
if ( 0 == nStatus ) { // Now try to find the provider based on the class name
// pProvider doesn't get addref'ed, so no release necessary
Provider *pProvider = SearchMapForProvider( pParsedPath->m_pClass, m_strNamespace );
// If we got a provider, let it handle itself like a grown-up provider
// should.
if ( NULL != pProvider ) { IWbemClassObjectPtr pOutClass; IWbemClassObjectPtr pOutParams; CInstancePtr COutParam; CInstancePtr CInParam; hr = WBEM_S_NO_ERROR;
// Now create an External Method Context object and go to town
ExternalMethodContextPtr pContext (new ExternalMethodContext( pResponseHandler, pCtx, this ), false); #ifdef PROVIDER_INSTRUMENTATION
pContext->pStopWatch = &stopWatch; #endif
// Check for out of memory
if (NULL == pContext) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
// add check to ensure that we do not call a static method
// on an instance of a class.
if (SUCCEEDED(hr) && pParsedPath->IsInstance()) { IWbemClassObjectPtr pObj(pProvider->GetClassObjectInterface(pContext), false); if (pObj) { IWbemQualifierSetPtr pSet; #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
if (SUCCEEDED(pObj->GetMethodQualifierSet(MethodName, &pSet))) { // disallow an instance to invoke a static method
#ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
if (SUCCEEDED(pSet->Get( IDS_Static, 0, NULL, NULL))) hr = WBEM_E_INVALID_METHOD; #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
} } }
// If there are in params, convert them to a cinstance.
if (SUCCEEDED(hr) && (NULL != pInParams) ) { CInParam.Attach(new CInstance(pInParams, pContext));
if (NULL == CInParam) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } }
// Get the output class for the method
if (SUCCEEDED(hr)) { IWbemClassObjectPtr pObj(pProvider->GetClassObjectInterface(pContext), false); if (pObj != NULL) { #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
hr = pObj->GetMethod(MethodName, 0, NULL, &pOutClass); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
} else { hr = WBEM_E_FAILED; } }
// If there is no output class, pOutClass is null (by design). So, if there was no error
// and we got an pOutClass, get an instance and wrap it in a CInstance
if (SUCCEEDED(hr) && (pOutClass != NULL)) { #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
hr = pOutClass->SpawnInstance(0, &pOutParams); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
if (SUCCEEDED(hr)) { COutParam.Attach(new CInstance(pOutParams, pContext));
// Out of memory
if (NULL == COutParam) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } }
if ( SUCCEEDED(hr) ) { CWbemGlueImpersonation impersonate; if SUCCEEDED ( hr = impersonate.IsImpersonated () ) { // Set up to call FlushAll
AddFlushPtr(pProvider);
WCHAR wszName[UNLEN + DNLEN + 1 + 1] = {0}; WCHAR wszName2[UNLEN + DNLEN + 1 + 1] = {0}; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName, &dwLen);
hr = pProvider->ExecMethod( pParsedPath, MethodName, lFlags, CInParam, COutParam, pContext );
dwLen = UNLEN + DNLEN + 1 + 1;
GetUserNameEx(NameSamCompatible, wszName2, &dwLen);
if (wcscmp(wszName, wszName2) != 0) { ASSERT_BREAK(IMPERSONATION_REVERTED); LogErrorMessage5(L"Warning! User name at exit (%s) != user name at entry (%s) for %s.%s", wszName2, wszName, ObjectPath, MethodName); } } }
// If there is an output object
if (COutParam != NULL) {
// Only send back an output object if the method succeeded
if (SUCCEEDED(hr)) {
// Send the object back
IWbemClassObjectPtr pObj(COutParam->GetClassObjectInterface(), false); IWbemClassObject *pObj2 = (IWbemClassObject *)pObj; #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
pResponseHandler->Indicate( 1, &pObj2); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
} }
pStatusObject.Attach(pContext->GetStatusObject());
} else { LogErrorMessage3(L"%s (%s)", IDS_PROVIDERNOTFOUND, pParsedPath->m_pClass); hr = WBEM_E_INVALID_CLASS; bLocalError = true; }
} else { LogErrorMessage3(L"%s (%s)", IDS_COULDNOTPARSE, ObjectPath); bLocalError = true; }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) LogMessage4(L"%s%s.%s - Succeeded", IDS_EXECMETHODASYNC, ObjectPath, MethodName); else LogMessage5(L"%s%s.%s - FAILED (%x)", IDS_EXECMETHODASYNC, ObjectPath, MethodName, hr); } }
catch ( CFramework_Exception e_FR ) { ASSERT_BREAK(FRAMEWORK_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( CHeap_Exception e_HE ) { ASSERT_BREAK(MEMORY_EXHAUSTED); hr = WBEM_E_OUT_OF_MEMORY; } catch(CStructured_Exception e_SE) { ASSERT_BREAK(STRUCTURED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; } catch ( ... ) { ASSERT_BREAK(UNSPECIFIED_EXCEPTION); hr = WBEM_E_PROVIDER_FAILURE; }
if ((hr != WBEM_E_INVALID_CLASS) && (hr != WBEM_E_UNSUPPORTED_PARAMETER) && !bLocalError) { #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::WinMgmtTimer); #endif
pResponseHandler->SetStatus( 0, hr, NULL, pStatusObject ); #ifdef PROVIDER_INSTRUMENTATION
stopWatch.Start(StopWatch::FrameworkTimer); #endif
hr = WBEM_S_NO_ERROR; }
// Clean up the Parsed Path
if (pParsedPath) { objpathParser.Free( pParsedPath ); }
Release();
#ifdef PROVIDER_INSTRUMENTATION
stopWatch.Stop(); stopWatch.LogResults(); #endif
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetNamespaceConnection
//
// Establishes a connection to the supplied namespace by first
// assigning a default if needed, then searching our map, and if
// that fails, then actually connecting.
//
// Inputs: const BSTR NameSpace - NameSpace of provider
//
// Outputs: None.
//
// Returns: IWbemServices *pointer to IWbemServices corresponding
// to the connected namespace.
//
// Comments: Default Namespace is Root\\Default
//
//
/////////////////////////////////////////////////////////////////////
IWbemServices *CWbemProviderGlue::GetNamespaceConnection(
LPCWSTR pwszNameSpace ) { ASSERT_BREAK(DEPRECATED);
bstr_t bstrNamespace(pwszNameSpace);
// Root\CimV2 is the default name space
if ( NULL == pwszNameSpace || L'\0' == *pwszNameSpace ) { bstrNamespace = DEFAULT_NAMESPACE; }
if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_GETNAMESPACECONNECTION, (LPCWSTR)bstrNamespace); }
IWbemLocatorPtr pIWbemLocator; IWbemServices *pWbemServices = NULL;
HRESULT hRes = CoCreateInstance (
CLSID_WbemLocator, //CLSID_WbemAdministrativeLocator,
NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown, ( void ** ) &pIWbemLocator ) ;
if (SUCCEEDED(hRes)) { hRes = pIWbemLocator->ConnectServer(bstrNamespace, // Namespace
NULL, // Userid
NULL, // PW
NULL, // Locale
0, // flags
NULL, // Authority
NULL, // Context
&pWbemServices );
if (SUCCEEDED(hRes)) { } else { LogErrorMessage3(L"Failed to Connectserver to namespace %s (%x)", (LPCWSTR)bstrNamespace, hRes); } } else { LogErrorMessage2(L"Failed to get locator (%x)", hRes); }
return pWbemServices; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FrameworkLogin
//
// Static entry point for providers to login to the framework,
// providing us with info for our map, and allowing us to return
// an IWbemServices pointer for the base provider class to
// manipulate to its heart's content.
//
// Inputs: LPCWSTR& strName - Name of object for map.
// Provider *pProvider - Pointer Name Maps to.
// LPCWSTR pszNameSpace - NameSpace of provider
//
// Outputs: None.
//
// Returns: None.
//
// Comments: None.
//
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::FrameworkLogin(
LPCWSTR a_szName, Provider *a_pProvider, LPCWSTR a_pszNameSpace ) { if (IsVerboseLoggingEnabled()) { if (a_pszNameSpace != NULL) { LogMessage4(L"%s%s:%s", IDS_FRAMEWORKLOGIN, a_pszNameSpace, a_szName); } else { LogMessage4(L"%s%s:%s", IDS_FRAMEWORKLOGIN, DEFAULT_NAMESPACE, a_szName); } }
// AddProviderToMap, searches the Map for a match first.
// If one is found, it does not perform the actual add.
// Check that the pointers are the same. If they're
// different, this is what happened.
// pProvider doesn't get addref'ed, so no release necessary
Provider *t_pTestProvider = AddProviderToMap( a_szName, a_pszNameSpace, a_pProvider );
if ( t_pTestProvider != a_pProvider ) { // this should never happen
// a provider should login only once at construction and out at destruction
// this should coincide with DLLs being loaded and unloaded.
LogErrorMessage4(L"%s (%s:%s)", IDS_LOGINDISALLOWED, a_pszNameSpace, a_szName); ASSERT_BREAK( FALSE ); }
}
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FrameworkLogoff
//
// Static entry point for providers to log out of the framework,
// this should be called from the provider's dtor so that we release
// all of our pointers so they don't dangle.
//
// Inputs: LPCWSTR& strName - Name of object for map.
// LPCWSTR pszNameSpace - NameSpace of provider
//
// Outputs: None.
//
// Returns: usually.
//
// Comments: We don't bother removing entries from the namespace map.
//
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::FrameworkLogoff(
LPCWSTR a_pszName, LPCWSTR a_pszNamespace ) { STRING2LPVOID::iterator mapIter;
try { if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_FRAMEWORKLOGOFF, a_pszName); }
BOOL bDone = FALSE; CHString strQualifiedName;
do { try { strQualifiedName = a_pszName; bDone = TRUE; } catch ( CHeap_Exception e_HE ) { // resources could be eventually back
::Sleep ( 1000 ); } } while ( !bDone ); bDone = FALSE;
// If our NameSpace is non-NULL (we use DEFAULT_NAMESPACE then), AND it
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
// so we can differentiate providers across namespaces.
if ( (a_pszNamespace != NULL) && (a_pszNamespace[0] != L'\0') && 0 != _wcsicmp(a_pszNamespace, DEFAULT_NAMESPACE ) ) { do { try { strQualifiedName += a_pszNamespace; bDone = TRUE; } catch ( CHeap_Exception e_HE ) { // resources could be eventually back
::Sleep ( 1000 ); } } while ( !bDone ); bDone = FALSE; }
// Convert characters to upper case before searching for
// them in the map. Since we convert to upper case when
// we store the map associations, this effectively makes
// us case-insensitive.
strQualifiedName.MakeUpper();
EnterCriticalSectionWait ecs ( &s_csProviderMap ); LeaveCriticalSectionScope lcs ( &s_csProviderMap );
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() ) s_providersmap.erase(mapIter); else ASSERT_BREAK(0 /* did not find provider to log off!*/); } catch ( ... ) { // we should not be here
// do not re-throw (called from destructor)
} }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetAllInstances
//
// Static entry point for providers to obtain instance lists from
// other providers.
//
// Inputs: LPCWSTR pszProviderName - Name of provider to
// get list for.
// TRefPointerCollection<CInstance> *pList - List to fill.
// LPCWSTR pszNamespace - Namespace of provider.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetAllInstances(
LPCWSTR pszClassName, TRefPointerCollection<CInstance> *pList, LPCWSTR pszNamespace, /* = NULL*/ MethodContext *pMethodContext /* = NULL*/ ) { HRESULT hr = WBEM_S_NO_ERROR;
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
if (pszClassName) { CHString sQuery;
sQuery.Format(L"SELECT * FROM %s where __CLASS = \"%s\"", pszClassName, pszClassName); hr = GetInstancesByQuery( sQuery, pList, pMethodContext, pszNamespace); } else { hr = WBEM_E_INVALID_PARAMETER; }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetAllInstancesAsynch
//
// Static entry point for providers to obtain instances from
// other providers. Note that this is not, strictly speaking,
// an asynchronous implementation - it does HELP the asynch calls
// in that it does not build a big list and that the callback allows
// the provider to respond asynchronously
//
// Inputs: LPCWSTR pszProviderName - Name of provider to
// get instances from.
//
// Provider * this is the "this" pointer for the requester
// LPProviderInstanceCallback callback function to eat the instances provided
// LPCWSTR pszNamespace - Namespace of provider.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
// this puppy shares a lot of code with GetAllInstances, but I
// can't find a clean way to combine them.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetAllInstancesAsynch(
LPCWSTR pszClassName, Provider *pRequester, LPProviderInstanceCallback pCallback, LPCWSTR pszNamespace, MethodContext *pMethodContext, void *pUserData ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
HRESULT hr = WBEM_S_NO_ERROR;
if (pszClassName) { CHString sQuery; sQuery.Format(L"SELECT * FROM %s where __CLASS = \"%s\"", pszClassName, pszClassName); hr = GetInstancesByQueryAsynch( sQuery, pRequester, pCallback, pszNamespace, pMethodContext, pUserData);
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer); } else { hr = WBEM_E_INVALID_PARAMETER; }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetAllDerivedInstances
//
// Static entry point for providers to obtain instance lists from
// other providers. This one will return all instances derived from
// the base class passed in.
//
// Inputs: LPCWSTR pszBaseClassName - Name of base class
// to get list for.
// TRefPointerCollection<CInstance> *pList - List to fill.
// LPCWSTR pszNamespace - Namespace of provider.
// MethodContext *pMethodContext, // must not be NULL
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetAllDerivedInstances(
LPCWSTR pszBaseClassName, TRefPointerCollection<CInstance> *pList, MethodContext *pMethodContext, LPCWSTR pszNamespace ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
HRESULT hr = WBEM_S_NO_ERROR;
if (pszBaseClassName) { CHString sQuery; sQuery.Format(L"SELECT * FROM %s", pszBaseClassName); hr = GetInstancesByQuery( sQuery, pList, pMethodContext, pszNamespace); } else { hr = WBEM_E_INVALID_PARAMETER; }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetAllDerivedInstancesAsynch
//
// Static entry point for providers to obtain instances from
// other providers. Note that this is not, strictly speaking,
// an asynchronous implementation - it does HELP the asynch calls
// in that it does not build a big list and that the callback allows
// the provider to respond asynchronously
//
// Inputs: LPCWSTR pszProviderName - Name of provider to
// get instances from.
//
// Provider* this is the "this" pointer for the requester
// LPProviderInstanceCallback callback function to eat the instances provided
// LPCWSTR pszNamespace - Namespace of provider.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
// this puppy shares a lot of code with GetAllInstances, but I
// can't find a clean way to combine them.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetAllDerivedInstancesAsynch(
LPCWSTR pszProviderName, Provider *pRequester, LPProviderInstanceCallback pCallback, LPCWSTR pszNamespace, MethodContext *pMethodContext, void *pUserData ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
HRESULT hr = WBEM_S_NO_ERROR;
if (pszProviderName) { CHString sQuery; sQuery.Format(L"SELECT * FROM %s", pszProviderName); hr = GetInstancesByQueryAsynch( sQuery, pRequester, pCallback, pszNamespace, pMethodContext, pUserData); } else { hr = WBEM_E_INVALID_PARAMETER; }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstancesByQuery
//
// Static entry point for providers to obtain instance lists from
// other providers. This one will return all instances matching a query.
//
// Inputs: LPCWSTR Query to execute "Select * from win32_foo where bar = "baz""
// TRefPointerCollection<CInstance> *pList - List to fill.
// MethodContext *pMethodContext, // must not be NULL
// LPCWSTR pointer to namespace - may be NULL (means default -- root\cimv2)
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstancesByQuery( LPCWSTR query, TRefPointerCollection<CInstance> *pList, MethodContext *pMethodContext, LPCWSTR pszNamespace /* = NULL*/) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s (%s)", IDS_GETINSTANCESBYQUERY, query); }
HRESULT hr = WBEM_E_FAILED;
if ( (query != NULL) && (pList != NULL) && (pMethodContext != NULL) ) { IEnumWbemClassObjectPtr pEnum;
IWbemContextPtr pWbemContext; if (pMethodContext) { pWbemContext.Attach(pMethodContext->GetIWBEMContext()); }
IWbemServicesPtr piService;
// get a service interface
if (pszNamespace == NULL || pszNamespace[0] == L'\0') { piService.Attach(GetNamespaceConnection(NULL, pMethodContext)); } else { piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext)); }
if ( piService != NULL) { { // Assures that impersonation goes
// back to the way it was before the
// call to CIMOM.
CAutoImpRevert air; DWORD dwImpErr = air.LastError(); if(dwImpErr == ERROR_SUCCESS) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); hr = piService->ExecQuery(bstr_t(IDS_WQL), bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, pWbemContext, &pEnum); PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); } else { LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr); hr = WBEM_E_FAILED; } }
if ( SUCCEEDED( hr ) ) { IWbemClassObjectPtr pObj; ULONG nReturned;
// author's apology:
// we loop through, using Next() to get each instance
// we bail when we get WBEM_S_FALSE because that's the end of the enumeration
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); for (hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned); (SUCCEEDED(hr) && (hr != WBEM_S_FALSE) && (hr != WBEM_S_TIMEDOUT) ) ; hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned)) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); if (pObj != NULL && nReturned) { CInstancePtr pInstance(new CInstance(pObj, pMethodContext), false);
if (pInstance != NULL) { // Check to see if adding to the list succeeds
if (!pList->Add(pInstance)) { hr = WBEM_E_OUT_OF_MEMORY; } } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
} }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
// the Next will return WBEM_S_FALSE when it is done. However, that
// means that THIS function had no error.
if (hr == WBEM_S_FALSE) { hr = WBEM_S_NO_ERROR; } // fencepost check - the last error might have been access denied
// but it's okay if we got any instances at all
else if (hr == WBEM_E_ACCESS_DENIED) if (pList->GetSize() > 0) hr = WBEM_S_NO_ERROR;
} // IF SUCCEEDED
} else LogErrorMessage(IDS_FAILED); } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to GetInstancesByQuery"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) { LogMessage3(L"%s (%s) - Succeeded", IDS_GETINSTANCESBYQUERY, query); } else { LogMessage4(L"%s (%s) - FAILED (%x)", IDS_GETINSTANCESBYQUERY, query, hr); } }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::IsDerivedFrom
//
// Static entry point for providers to obtain derivation information
//
// Inputs: LPCWSTR pszBaseClassName - Name of base class
// LPCWSTR pszDerivedClassName - Name of class we're testing
// MethodContext *pMethodContext
//
// Outputs: None.
//
// Returns: true iff pszDerivedClassName is derived from pszBaseClassName
//
// Comments: This function cannot short circuit, because a derived class may be external
//
/////////////////////////////////////////////////////////////////////
bool CWbemProviderGlue::IsDerivedFrom(
LPCWSTR pszBaseClassName, LPCWSTR pszDerivedClassName, MethodContext *pMethodContext, LPCWSTR pszNamespace /* = NULL*/ ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
bool bRet = false;
if ( (pszBaseClassName != NULL) && (pszDerivedClassName != NULL) && (pMethodContext != NULL) ) { IWbemServicesPtr piService;
// get a service interface
piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext ));
// find the derived class object
if (piService != NULL) { IWbemClassObjectPtr pObj; IWbemContextPtr pWbemContext; if (pMethodContext) { pWbemContext.Attach(pMethodContext->GetIWBEMContext()); }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); HRESULT hr = piService->GetObject( bstr_t( pszDerivedClassName ), 0, pWbemContext, &pObj, NULL); PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
if (SUCCEEDED(hr) && (pObj != NULL)) { // Variant_t handles the VariantInit/VariantClear
variant_t v;
if (SUCCEEDED(pObj->Get((unsigned short *)IDS_DERIVATION, 0, &v, NULL, NULL))) { BSTR bstrTemp = NULL; SAFEARRAY *psa = V_ARRAY(&v); LONG uBound; SafeArrayGetUBound(psa, 1, &uBound);
// if base class is in the list in the derivation, we're true!
for (LONG i = 0; !bRet && (i <= uBound); i++) { if (SUCCEEDED(SafeArrayGetElement( psa, &i, &bstrTemp ))) { OnDeleteIf<BSTR,VOID(*)(BSTR),SysFreeString> smartbstrTemp(bstrTemp); bRet = (_wcsicmp(pszBaseClassName, bstrTemp) == 0); } } } } } } else { LogErrorMessage(L"NULL parameter to IsDerivedFrom"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return bRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetEmptyInstance
//
// Static entry point for providers to obtain a single empty instance
// of a provider object.
//
// Inputs: LPCWSTR pszProviderName - Name of provider to
// get list for.
// LPCWSTR pszNamespace - Namespace of provider.
//
// Outputs: CInstance **ppInstance - Pointer to store new
// pInstance in. Must be Released by
// caller.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
//
/////////////////////////////////////////////////////////////////////
// DEPRECATED
HRESULT WINAPI CWbemProviderGlue::GetEmptyInstance(
LPCWSTR pszClassName, CInstance **ppInstance, LPCWSTR pszNamespace ) { ASSERT_BREAK(DEPRECATED);
HRESULT hr = WBEM_E_INVALID_CLASS;
if ( (pszClassName != NULL) && (ppInstance != NULL) ) { // Search for the class name in our map of providers, we know which
// namespace we are when we get constructed.
// pProvider doesn't get addref'ed, so no release is necessary
Provider *pProvider = SearchMapForProvider( pszClassName, pszNamespace );
if ( NULL != pProvider ) { // Now create an Internal Method Context object, since this function
// only gets called internal to our DLL. Using a NULL for the
// list pointer, essentially creates a dummy context so we can
// do our commit dance as painlessly as possible.
InternalMethodContextPtr pContext (new InternalMethodContext( NULL, NULL, NULL ), false);
if ( NULL != pContext ) { // Assume things will go wrong like a good liitle paranoiac
hr = WBEM_E_FAILED;
// Before asking for a new instance, we MUST verify that the
// provider has a valid IMOS pointer. If it does'nt, CreateNewInstance
// may GPF (this is a safety check we must do because of our
// little short circuit.
// We don't do short circuits anymore.
// if ( pProvider->ValidateIMOSPointer() )
{ // Set the error code appropriately depending on whether or
// not the Instance gets created correctly.
// The instance returned will have been AddRefed, so it will
// be up to the caller to Release() it.
if ( ( *ppInstance = pProvider->CreateNewInstance( pContext ) ) != NULL ) { hr = WBEM_S_NO_ERROR; } } } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } else { hr = WBEM_E_INVALID_CLASS; } } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to GetEmptyInstance"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetEmptyInstance
//
// Static entry point for providers to obtain a single empty instance
// of a provider object. This alternate form makes a call back
// into WINMGMT.
//
// Inputs: MethodContext *Context object for this call
// LPCWSTR pszProviderName - Name of provider to
// get instance of.
// LPCWSTR pszNamespace - Namespace of class.
//
// Outputs: CInstance **ppInstance - Pointer to store new
// pInstance in. Must be Released by
// caller.
//
// Returns: HRESULT hr - Status code.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetEmptyInstance(
MethodContext *pMethodContext, LPCWSTR pszProviderName, CInstance **ppOutInstance, LPCWSTR a_pszNamespace ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
HRESULT hr = WBEM_E_FAILED;
if ( (pMethodContext != NULL) && (pszProviderName != NULL) && (ppOutInstance != NULL) ) {
CInstancePtr pClassInstance;
hr = GetInstanceFromCIMOM(pszProviderName, a_pszNamespace, pMethodContext, &pClassInstance);
if (SUCCEEDED(hr)) { IWbemClassObjectPtr pClassObject(pClassInstance->GetClassObjectInterface(), false); if (pClassObject != NULL) { IWbemClassObjectPtr pObj; hr = pClassObject->SpawnInstance(0, &pObj);
if (SUCCEEDED(hr)) { *ppOutInstance = new CInstance(pObj, pMethodContext); if (*ppOutInstance == NULL) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } } else { hr = WBEM_E_FAILED; } } } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to GetEmptyInstance"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FillInstance
//
// Static entry point for providers to pass us an instance with
// key data filled out, which we will use to locate the correct
// provider and ask it to fill out completely.
//
// Inputs: CInstance *pInstance - Instance to fill out.
// LPCWSTR pszNamespace - Namespace for provider.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
//
/////////////////////////////////////////////////////////////////////
// DEPRECATED!
HRESULT WINAPI CWbemProviderGlue::FillInstance(
CInstance *pInstance, LPCWSTR pszNamespace /*= NULL*/ ) { ASSERT_BREAK(DEPRECATED);
HRESULT hr = WBEM_E_FAILED;
if (pInstance != NULL) { // Check that we have an instance pointer, then pull out the
// class name and name space. From there we can find the
// appropriate provider and ask it to get the object.
if ( NULL != pInstance ) { CHString strProviderName; pInstance->GetCHString( IDS_CLASS, strProviderName );
// Search for the class name in our map of providers, we know which
// namespace we are when we get constructed.
// pProvider is not addref'ed, so no release is necessary
Provider *pProvider = SearchMapForProvider( strProviderName, pszNamespace );
if ( NULL != pProvider ) { // Pass the pInstance off to the provider and let it take care
// of obtaining the correct values.
hr = pProvider->GetObject( pInstance ); } else { hr = WBEM_E_INVALID_CLASS; } } } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to FillInstance"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FillInstance
//
// Static entry point for providers to pass us an instance with
// key data filled out, use to make a call back into winmgmt.
//
// Inputs: MethodContext *Context object for this call
// CInstance *pInstance - Instance to fill out.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::FillInstance(
MethodContext *pMethodContext, CInstance *pInstance ) { ASSERT_BREAK(DEPRECATED);
HRESULT hr = WBEM_E_FAILED;
if ( (pMethodContext != NULL) && (pInstance != NULL) ) { // Check that we have an instance pointer, then pull out the path
// and send it to cimom.
CHString strPathName;
pInstance->GetCHString( L"__RELPATH", strPathName ); hr = GetInstanceByPath(strPathName, &pInstance, pMethodContext); } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to FillInstance"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstanceKeysByPath
//
// Static entry point for providers to pass us an instance path
// to retrieve. This class uses per-property gets to request
// only the keys on the object we are retrieving.
//
// Inputs: pszInstancePath Object path to retrieve
// CInstance *pInstance - Instance to fill out.
// MethodContext *Context object for this call
//
// Outputs: None
//
// Returns: HRESULT hr - Status code.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstanceKeysByPath(
LPCWSTR pszInstancePath, CInstance **ppInstance, MethodContext *pMethodContext ) { HRESULT hr = WBEM_S_NO_ERROR;
if ( (pMethodContext != NULL) && (pszInstancePath != NULL) && (ppInstance != NULL) ) {
IWbemContextPtr pWbemContext(pMethodContext->GetIWBEMContext(), false);
// We need to have a real context object, not an internal method context
if (pWbemContext != NULL) { VARIANT vValue; V_VT(&vValue) = VT_BOOL; V_BOOL(&vValue) = VARIANT_TRUE;
// Set the appropriate properties on the context object
if ( (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue))) && (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_KEYS_ONLY", 0L, &vValue))) && (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_CLIENT_REQUEST", 0L, &vValue)))) { LogMessage2(L"GetInstanceKeysByPath: %s", pszInstancePath); hr = GetInstanceByPath(pszInstancePath, ppInstance, pMethodContext);
V_BOOL(&vValue) = VARIANT_FALSE; pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue); } } else { ASSERT_BREAK(FALSE); LogErrorMessage(L"Can't use InternalMethodContext to GetInstanceKeysByPath"); hr = WBEM_E_INVALID_PARAMETER; } } else { hr = WBEM_E_INVALID_PARAMETER; }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstancePropertiesByPath
//
// Static entry point for providers to pass us an instance path
// to retrieve. This class uses per-property gets to request
// only the properties specified in the array.
//
// Inputs: pszInstancePath Object path to retrieve
// CInstance *pInstance - Instance to fill out.
// MethodContext *Context object for this call
// csaProperties Properties to request
//
// Outputs: None
//
// Returns: HRESULT hr - Status code.
//
// Comments:
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstancePropertiesByPath(
LPCWSTR pszInstancePath, CInstance **ppInstance, MethodContext *pMethodContext, CHStringArray &csaProperties ) { HRESULT hr = WBEM_S_NO_ERROR;
if ( (pMethodContext != NULL) && (pszInstancePath != NULL) && (ppInstance != NULL) ) {
IWbemContextPtr pWbemContext(pMethodContext->GetIWBEMContext(), false);
// We need to have a real context object, not an internal method context
if (pWbemContext != NULL) { variant_t vValue; V_VT(&vValue) = VT_BOOL; V_BOOL(&vValue) = VARIANT_TRUE;
// First set the value that says we are using Get extensions
if ((SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue))) && (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_CLIENT_REQUEST", 0L, &vValue))) ) { // Delete any unneeded properties
pWbemContext->DeleteValue(L"__GET_EXT_KEYS_ONLY", 0L);
// Now build the array of properties
SAFEARRAYBOUND rgsabound [ 1 ] ;
rgsabound[0].cElements = csaProperties.GetSize() ; rgsabound[0].lLbound = 0 ; V_ARRAY(&vValue) = SafeArrayCreate ( VT_BSTR, 1, rgsabound ) ; if ( V_ARRAY(&vValue) ) { V_VT(&vValue) = VT_BSTR | VT_ARRAY;
for (long x=0; x < csaProperties.GetSize(); x++) { bstr_t bstrProp = csaProperties[x];
SafeArrayPutElement( V_ARRAY(&vValue), &x, (LPVOID) (BSTR) bstrProp); }
// Put the array into the context object
if (SUCCEEDED(hr = pWbemContext->SetValue(L"__GET_EXT_PROPERTIES", 0L, &vValue))) { LogMessage2(L"GetInstancePropertiesByPath: %s", pszInstancePath); // Make the call
hr = GetInstanceByPath(pszInstancePath, ppInstance, pMethodContext);
vValue.Clear(); V_VT(&vValue) = VT_BOOL; V_BOOL(&vValue) = VARIANT_FALSE; pWbemContext->SetValue(L"__GET_EXTENSIONS", 0L, &vValue); } } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } } else { ASSERT_BREAK(FALSE); LogErrorMessage(L"Can't use InternalMethodContext to GetInstanceKeysByPath"); hr = WBEM_E_INVALID_PARAMETER; } } else { hr = WBEM_E_INVALID_PARAMETER; }
return hr; } /////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstanceByPath
//
// Static entry point for providers to obtain a single empty instance
// of a provider object.
//
// Inputs: LPCWSTR pszInstancePath - Path to Object. This
// MUST be a full path,
// MethodContext *pMethodContext - Method Context containing
// (hopefully) the WbemContext we need
// to propogate.
//
// Outputs: CInstance** ppInstance - Pointer to store new
// pInstance in. Must be Released by
// caller.
//
// Returns: HRESULT hr - Status code.
//
// Comments: This is an internal entry point, allowing providers
// to short circuit having to go through WBEM to access
// data from other providers.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstanceByPath(
LPCWSTR pszInstancePath, CInstance **ppInstance, MethodContext *pMethodContext /* = NULL */ ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
HRESULT hr = WBEM_E_FAILED;
if ( (pszInstancePath != NULL) && (ppInstance != NULL) ) { CHString strComputerName; GetComputerName( strComputerName );
DWORD dwError = ::GetLastError (); if ( ERROR_SUCCESS != dwError ) { // For this revision, we DO NOT support getting paths that are not local.
// This is because if the machine name is anything other than the local
// one, we run the risk of freezing while CIMOM goes out and tries to find
// the machine (up to around 5 minutes according to his Levness.
ParsedObjectPath *pParsedPath = NULL; CObjectPathParser objpathParser;
// Parse the object path passed to us by CIMOM
// ==========================================
int nStatus = objpathParser.Parse( pszInstancePath, &pParsedPath );
if ( 0 == nStatus ) { //
// smart free for pParsedPath
//
OnDeleteObjIf < ParsedObjectPath*, CObjectPathParser, void ( CObjectPathParser:: * ) ( ParsedObjectPath* ) , &CObjectPathParser::Free > SmartFree ( &objpathParser, pParsedPath ) ;
// Machine names MUST match. Null indicates no machine name specified.
if (( pParsedPath->m_pServer == NULL) || ( strComputerName.CompareNoCase( pParsedPath->m_pServer ) == 0 ) || ( wcscmp(pParsedPath->m_pServer, L".") == 0 ) ) { // Now try to find the provider based on the class name
CHString strNamespace;
// Pull out the name space parts, and concatenate them using a '\\'
// character. e.g. root\default.
for ( DWORD dwCtr = 0; dwCtr < pParsedPath->m_dwNumNamespaces; dwCtr++ ) { if ( dwCtr != 0 ) { strNamespace += L"\\"; }
strNamespace += pParsedPath->m_paNamespaces[dwCtr]; }
// We need to propogate the Wbem Context if we are going out
// to CIMOM!
IWbemContextPtr pWbemContext; CWbemProviderGlue *pGlue = NULL;
if ( NULL != pMethodContext ) { pWbemContext.Attach(pMethodContext->GetIWBEMContext()); pGlue = pMethodContext->GetProviderGlue(); } else { ASSERT_BREAK(DEPRECATED); }
InternalMethodContextPtr pInternalContext ( new InternalMethodContext( NULL, pWbemContext, pGlue), false);
if ( NULL != pInternalContext ) { hr = GetInstanceFromCIMOM( pszInstancePath, strNamespace, pInternalContext, ppInstance ); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
} // IF Machine Names MATCH
else { hr = WBEM_E_INVALID_PARAMETER; // INVALID MACHINE NAME
}
} // IF nStatus == 0
else { hr = WBEM_E_INVALID_OBJECT_PATH; } } else { // this could be access denied from GetComputeName
if ( ERROR_ACCESS_DENIED == dwError ) { hr = WBEM_E_ACCESS_DENIED; } else { // it is WBEM_E_FAILED
} } } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to GetInstanceByPath"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr;
}
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstanceFromCIMOM
//
// Static entry point for providers to obtain a single instance
// of a WBEM Object. obtaining said object from CIMOM.
//
// Inputs: LPCWSTR pszInstancePath - Path to Object. This
// MUST be a full path,
// LPCWSTR pszNameSpace - NameSpace of Object.
// MethodContext *pMethodContext - Method Context
//
// Outputs: CInstance **ppInstance - Pointer to store new
// pInstance in. Must be Released by
// caller.
//
// Returns: HRESULT hr - Status code.
// will return WBEM_E_INVALID_NAMESPACE if it's not a namespace we support
// (might otherwise be valid, but not so far as WE are concerned).
//
// Comments: This is an internal entry point, allowing providers
// that failed the short circuit to be propogated
// by calling into CIMOM.
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstanceFromCIMOM(
LPCWSTR pszInstancePath, LPCWSTR pszNamespace, MethodContext *pMethodContext, CInstance **ppInstance ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); HRESULT hr = WBEM_E_FAILED;
if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s (%s)", IDS_INSTANCEFROMCIMOM, pszInstancePath); }
// We need to propogate the Wbem Context (if any) that was passed to
// us by CIMOM.
IWbemContextPtr pWbemContext;
if ( NULL != pMethodContext ) { pWbemContext.Attach(pMethodContext->GetIWBEMContext()); } else { ASSERT_BREAK(DEPRECATED); }
// If we failed to find the provider, try using CIMOM to do our
// dirty work for us.
IWbemServicesPtr piService; IWbemClassObjectPtr piObject;
// get a service interface
if ( (pszNamespace == NULL) || (pszNamespace[0] == L'\0' )) { piService.Attach(GetNamespaceConnection(NULL, pMethodContext)); } else { piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext )); }
if ( NULL != piService ) {
// No go out to CIMOM to get the object, if this succeeds, new an
// instance and store everything internally.
{ // Assures that impersonation goes
// back to the way it was before the
// call to CIMOM.
CAutoImpRevert air; DWORD dwImpErr = air.LastError();
if(dwImpErr == ERROR_SUCCESS) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); hr = piService->GetObject( bstr_t(pszInstancePath), 0, pWbemContext, &piObject, NULL ); PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); } else { LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr); hr = WBEM_E_FAILED; } }
if ( SUCCEEDED(hr) ) { *ppInstance = new CInstance( piObject, pMethodContext ); if (*ppInstance == NULL) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
} } else { LogErrorMessage(IDS_FAILED); hr = WBEM_E_INVALID_NAMESPACE; }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) { LogMessage3(L"%s (%s) - Succeeded", IDS_INSTANCEFROMCIMOM, pszInstancePath); } else { LogMessage4(L"%s (%s) - FAILED (%x)", IDS_INSTANCEFROMCIMOM, pszInstancePath, hr); } }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::SearchMapForProvider
//
// Searches our Provider map for a match against the supplied
// provider name/NameSpace combination
//
// Inputs: const LPCWSTR& strName - Provider Name to find.
// const LPCWSTR& strNamespace - Provider's Namespace
//
// Outputs: None.
//
// Returns: Provider *pointer to a provider that was given to
// us by a call to FrameworkLogin.
//
// Comments: None.
//
//
/////////////////////////////////////////////////////////////////////
Provider *CWbemProviderGlue::SearchMapForProvider(
LPCWSTR a_pszProviderName, LPCWSTR a_pszNamespace ) { Provider *pProvider = NULL; STRING2LPVOID::iterator mapIter;
// If our NameSpace is non-NULL (we use DEFAULT_NAMEPSACE then), AND it
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
// so we can differentiate providers across namespaces.
CHString strQualifiedName( a_pszProviderName ); CHString strLocNamespace( a_pszNamespace );
if ( !strLocNamespace.IsEmpty() && 0 != strLocNamespace.CompareNoCase( DEFAULT_NAMESPACE ) ) {
// Convert the / characters to \ for comparison
WCHAR *pszBuff; pszBuff = strLocNamespace.GetBuffer(0); while ((pszBuff = wcschr(pszBuff, '/')) != NULL) { *pszBuff = '\\'; } strLocNamespace.ReleaseBuffer();
strQualifiedName += strLocNamespace; }
// Convert characters to upper case before searching for
// them in the map. Since we convert to upper case when
// we store the map associations, this effectively makes
// us case-insensitive.
strQualifiedName.MakeUpper();
// Protect the map while we're inside this
LockProviderMap(); OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockProviderMap> SmartUnlockProviderMap ;
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() ) { pProvider = (Provider*) (*mapIter).second; }
return pProvider;
}
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::AddProviderToMap
//
// Adds a provider to our map. Searches the map first, and if it's
// not in it, adds it to the map.
//
// Inputs: const LPCWSTR strName - Provider Name to Add.
// const LPCWSTR strNamespace - Namespace for provider.
// Provider *pProvider - Provider to add to map.
//
// Outputs: None.
//
// Returns: Provider *pointer to a provider in the map (may
// be different from the supplied one)
//
// Comments: None.
//
//
/////////////////////////////////////////////////////////////////////
Provider *CWbemProviderGlue::AddProviderToMap(
LPCWSTR a_szProviderName, LPCWSTR a_pszNamespace, Provider *a_pProvider ) { STRING2LPVOID::iterator mapIter;
// If our NameSpace is non-NULL (we use DEFAULT_NAMEPSACE then), AND it
// is not DEFAULT_NAMESPACE, concat the namespace to the provider name
// so we can differentiate providers across namespaces.
CHString strQualifiedName( a_szProviderName );
if ( ( a_pszNamespace != NULL) && (a_pszNamespace[0] != L'\0') && (0 != _wcsicmp(a_pszNamespace, DEFAULT_NAMESPACE )) ) { strQualifiedName += a_pszNamespace; }
// Convert characters to upper case before searching for
// them in the map. Since we convert to upper case when
// we store the map associations, this effectively makes
// us case-insensitive.
strQualifiedName.MakeUpper();
// Protect the map while we're inside this
Provider *pReturnProvider = NULL; LockProviderMap(); OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockProviderMap> SmartUnlockProviderMap ;
// First check if we've already got a provider.
if( ( mapIter = s_providersmap.find( strQualifiedName ) ) != s_providersmap.end() ) { pReturnProvider = (Provider*) (*mapIter).second; //delete it, we're gonna update it shortly
s_providersmap.erase(mapIter); }
if ( NULL == pReturnProvider ) { pReturnProvider = a_pProvider; }
//add in the newly logged in provider
s_providersmap[strQualifiedName] = (LPVOID) a_pProvider;
return pReturnProvider;
}
void CWbemProviderGlue::GetComputerName( CHString& strComputerName ) { // Fill the supplied CHString with the local machine name
DWORD dwBufferLength = MAX_COMPUTERNAME_LENGTH + 1;
FRGetComputerName(strComputerName.GetBuffer( dwBufferLength ), &dwBufferLength); strComputerName.ReleaseBuffer();
if (strComputerName.IsEmpty()) { strComputerName = L"DEFAULT"; } }
BOOL CWbemProviderGlue::FrameworkLoginDLL(LPCWSTR a_pszName) { return CWbemProviderGlue::FrameworkLoginDLL(a_pszName, NULL); }
BOOL CWbemProviderGlue::FrameworkLogoffDLL(LPCWSTR a_pszNname) { return CWbemProviderGlue::FrameworkLogoffDLL(a_pszNname, NULL); }
void CWbemProviderGlue::IncrementObjectCount(void) { InterlockedIncrement(&s_lObjects); if (IsVerboseLoggingEnabled()) { LogMessage2(L"CWbemProviderGlue::IncrementObjectCount. Count is (approx) %d", s_lObjects); } }
LONG CWbemProviderGlue::DecrementObjectCount(void) { LONG lRet = InterlockedDecrement(&s_lObjects); if (IsVerboseLoggingEnabled()) { LogMessage2(L"CWbemProviderGlue::DecrementObjectCount. Count is (approx) %d", s_lObjects); }
return lRet; }
// checks impersonation level
// impersonates client if allowed
HRESULT WINAPI CWbemProviderGlue::CheckImpersonationLevel() { HRESULT hr = WBEM_E_ACCESS_DENIED;
if (CWbemProviderGlue::GetPlatform() == VER_PLATFORM_WIN32_NT) { HRESULT hRes = WbemCoImpersonateClient(); if (SUCCEEDED(hRes)) // From cominit.cpp - needed for nt3.51
{ // Now, let's check the impersonation level. First, get the thread token
HANDLE hThreadTok; DWORD dwImp, dwBytesReturned;
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hThreadTok )) { DWORD dwLastError = GetLastError();
if (dwLastError == ERROR_NO_TOKEN) { // If the CoImpersonate works, but the OpenThreadToken fails due to ERROR_NO_TOKEN, we
// are running under the process token (either local system, or if we are running
// with /exe, the rights of the logged in user). In either case, impersonation rights
// don't apply. We have the full rights of that user.
hr = WBEM_S_NO_ERROR; } else { // If we failed to get the thread token for any other reason, log an error.
LogErrorMessage2(L"Impersonation failure - OpenThreadToken failed (0x%x)", dwLastError); hr = WBEM_E_ACCESS_DENIED; } } else { // We really do have a thread token, so let's retrieve its level
if (GetTokenInformation( hThreadTok, TokenImpersonationLevel, &dwImp, sizeof(DWORD), &dwBytesReturned )) { // Is the impersonation level Impersonate?
if ((dwImp == SecurityImpersonation) || (dwImp == SecurityDelegation)) { hr = WBEM_S_NO_ERROR; } else { hr = WBEM_E_ACCESS_DENIED; LogErrorMessage3(L"%s Level(%d)", IDS_ImpersonationFailed, dwImp); } } else { hr = WBEM_E_FAILED; LogErrorMessage3(L"%s Token(%d)", IDS_ImpersonationFailed, GetLastError()); }
// Done with this handle
CloseHandle(hThreadTok); }
if (FAILED(hr)) { WbemCoRevertToSelf(); } } else if (hRes == E_NOTIMPL) { // On 3.51 or vanilla 95, this call is not implemented, we should work anyway
hr = WBEM_S_NO_ERROR; } else { LogErrorMessage3(L"%s CoImpersonate(%d)", IDS_ImpersonationFailed, hRes); } } else { // let win9X in...
hr = WBEM_S_NO_ERROR; }
if (IsVerboseLoggingEnabled()) { WCHAR wszName[UNLEN + DNLEN + 1 + 1]; // domain + \ + name + null
DWORD dwLen = UNLEN + DNLEN + 1 + 1;
if (GetUserNameEx(NameSamCompatible, wszName, &dwLen)) { LogMessage2(L"Impersonation running as: %s", wszName); } }
return hr; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetInstancesByQueryAsynch
//
// Static entry point for providers to obtain instances from
// other providers. Note that this is not, strictly speaking,
// an asynchronous implementation - it does HELP the asynch calls
// in that it does not build a big list and that the callback allows
// the provider to respond asynchronously
//
// Inputs: LPCWSTR Query to execute "Select * from win32_foo where bar = "baz""
// Provider * this is the "this" pointer for the requester
// LPProviderInstanceCallback callback function to eat the instances provided
// LPCWSTR pszNamespace - Namespace of provider.
//
// Outputs: None.
//
// Returns: HRESULT hr - Status code.
//
//
/////////////////////////////////////////////////////////////////////
HRESULT WINAPI CWbemProviderGlue::GetInstancesByQueryAsynch(
LPCWSTR query, Provider *pRequester, LPProviderInstanceCallback pCallback, LPCWSTR pszNamespace, MethodContext *pMethodContext, void *pUserData ) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); if (IsVerboseLoggingEnabled()) { LogMessage2(L"GetInstancesByQueryAsynch (%s)", query); }
HRESULT hr = WBEM_E_FAILED;
if ( (query != NULL) && (pRequester != NULL) && (pCallback != NULL) && (pMethodContext != NULL) ) {
// We need to propogate the WBEM context...ESPECIALLY...if we are going out
// to CIMOM.
IWbemContextPtr pWbemContext; if (pMethodContext) { pWbemContext.Attach(pMethodContext->GetIWBEMContext()); } else { ASSERT_BREAK(DEPRECATED); }
// Now create an Internal Method Context object, since this function
// only gets called internal to our DLLs
InternalMethodContextAsynchPtr pInternalContext (new InternalMethodContextAsynch(pRequester, pCallback, pWbemContext, pMethodContext, pUserData), false);
if ( NULL != pInternalContext ) { // using CIMOM to do our dirty work for us.
IWbemServicesPtr piService;
// get a service interface
if (pszNamespace == NULL || pszNamespace[0] == L'\0') { piService.Attach(GetNamespaceConnection(NULL, pMethodContext)); } else { piService.Attach(GetNamespaceConnection( pszNamespace, pMethodContext )); }
if ( NULL != piService ) { IEnumWbemClassObjectPtr pEnum; { // Assures that impersonation goes
// back to the way it was before the
// call to CIMOM.
CAutoImpRevert air; DWORD dwImpErr = air.LastError();
if(dwImpErr == ERROR_SUCCESS) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); hr = piService->ExecQuery(bstr_t(IDS_WQL), bstr_t(query), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, pWbemContext, &pEnum); PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); } else { LogErrorMessage2(L"Failed to open current thread token for checking impersonation, with error %d", dwImpErr); hr = WBEM_E_FAILED; } }
if ( SUCCEEDED( hr ) ) { IWbemClassObjectPtr pObj; ULONG nReturned;
// we retrieve all instances of this class and it's children. Note that
// the next returns WBEM_S_FALSE at the end which PASSES the SUCCEEDED()
// test, but fails the pObj test.
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::WinMgmtTimer); while (SUCCEEDED(hr) && SUCCEEDED(hr = pEnum->Next(GLUETIMEOUT, 1, &pObj, &nReturned)) && (pObj != NULL)) { PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer); CInstancePtr pInstance(new CInstance(pObj, pMethodContext), false); if (pInstance != NULL) { // For reasons quite beyond me, InternalContext::Commit doesn't
// release, but external does. Note that the smartptr is doing
// the release here.
hr = pInternalContext->Commit(pInstance); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::FrameworkTimer);
// the Next will return WBEM_S_FALSE when it is done. However, that
// means that THIS function had no error.
if (hr == WBEM_S_FALSE) { hr = WBEM_S_NO_ERROR; }
} // IF SUCCEEDED
} else { LogErrorMessage(IDS_FAILED); } } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } else { hr = WBEM_E_INVALID_PARAMETER; LogErrorMessage(L"NULL parameter to GetInstancesByQueryAsynch"); ASSERT_BREAK(WBEM_E_INVALID_PARAMETER); }
if (IsVerboseLoggingEnabled()) { if (SUCCEEDED(hr)) { LogMessage2(L"GetInstancesByQueryAsynch (%s) - Succeeded", query); } else { LogMessage3(L"GetInstancesByQueryAsynch (%s) - FAILED (%x)", query, hr); } }
PROVIDER_INSTRUMENTATION_START(pMethodContext, StopWatch::ProviderTimer);
return hr; }
IWbemServices *CWbemProviderGlue::InternalGetNamespaceConnection(
LPCWSTR pwszNameSpace ) { IWbemServices *pWbemServices = NULL;
bstr_t bstrNamespace;
// Root\CimV2 is the default name space
if ( NULL != pwszNameSpace && L'\0' != *pwszNameSpace ) { bstrNamespace = pwszNameSpace; } else { ASSERT_BREAK(DEPRECATED); bstrNamespace = DEFAULT_NAMESPACE; }
if (IsVerboseLoggingEnabled()) { LogMessage3(L"%s%s", IDS_GETNAMESPACECONNECTION, (LPCWSTR)bstrNamespace); }
_wcsupr(bstrNamespace);
// If we are looking for the namespace our class is in, we already
// got an IWbemServices pointer for this from Initialize
if (m_strNamespace.Compare(bstrNamespace) == 0) { pWbemServices = m_pServices; pWbemServices->AddRef(); } else { IWbemLocatorPtr pIWbemLocator;
HRESULT hRes = CoCreateInstance (
CLSID_WbemLocator, //CLSID_WbemAdministrativeLocator,
NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown, ( void ** ) &pIWbemLocator ) ;
if (SUCCEEDED(hRes)) { hRes = pIWbemLocator->ConnectServer(bstrNamespace, // Namespace
NULL, // Userid
NULL, // PW
NULL, // Locale
0, // flags
NULL, // Authority
NULL, // Context
&pWbemServices );
if (FAILED(hRes)) { LogErrorMessage3(L"Failed to Connectserver to namespace %s (%x)", (LPCWSTR)bstrNamespace, hRes); } } else { LogErrorMessage2(L"Failed to get locator (%x)", hRes); } }
return pWbemServices; }
IWbemServices *WINAPI CWbemProviderGlue::GetNamespaceConnection( LPCWSTR wszNameSpace, MethodContext *pMethodContext ) { IWbemServices *pServices = NULL; CWbemProviderGlue *pGlue = NULL;
if ( pMethodContext && (pGlue = pMethodContext->GetProviderGlue()) ) { pServices = pGlue->InternalGetNamespaceConnection(wszNameSpace); } else { pServices = GetNamespaceConnection(wszNameSpace); }
return pServices; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FrameworkLoginDLL
//
// Static entry point for providers to register their DLL with
// the framework. This PLONG must be the same one used in
// FrameworkLogoffDll and as the parameter to the CWbemGlueFactory
// constructor.
//
/////////////////////////////////////////////////////////////////////
BOOL CWbemProviderGlue::FrameworkLoginDLL(LPCWSTR pszName, PLONG plRefCount) { BOOL bRet = TRUE; LogMessage3(L"%s%s", IDS_DLLLOGGED, pszName);
// If this *is* null, that means we are using the backword compatibility
// version of FrameworkLoginDLL, which uses CWbemProviderGlue::s_lObjects
// which has already been initialized.
if (plRefCount != NULL) { *plRefCount = 0; }
return bRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::FrameworkLogoffDLL
//
// Static entry point for providers to determine whether they
// should return TRUE to DllCanUnloadNow. This PLONG must be the
// same one used in FrameworkLoginDLL and as the parameter to the
// CWbemGlueFactory constructor.
//
/////////////////////////////////////////////////////////////////////
BOOL CWbemProviderGlue::FrameworkLogoffDLL(LPCWSTR pszName, PLONG plRefCount) { BOOL bRet = TRUE;
LogMessage3(L"%s%s", IDS_DLLUNLOGGED, pszName);
// If this *is* null, that means we are using the backword compatibility
// version of FrameworkLoginDLL
if (plRefCount != NULL) { bRet = *plRefCount == 0; } else { bRet = CWbemProviderGlue::s_lObjects == 0; }
return bRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::AddToFactoryMap
//
// Adds a new CWbemGlueFactory to the s_factorymap map.
//
/////////////////////////////////////////////////////////////////////
VOID CWbemProviderGlue::AddToFactoryMap(const CWbemGlueFactory *pGlue, PLONG plRefCount) { LockFactoryMap(); OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
// If this *is* null, that means we are using the backword compatibility
// version of FrameworkLoginDLL
if (plRefCount != NULL) { CWbemProviderGlue::s_factorymap[pGlue] = plRefCount; } else { CWbemProviderGlue::s_factorymap[pGlue] = &CWbemProviderGlue::s_lObjects; } }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::RemoveFromFactoryMap
//
// Removes a CWbemGlueFactory from the s_factorymap map.
//
/////////////////////////////////////////////////////////////////////
VOID CWbemProviderGlue::RemoveFromFactoryMap(const CWbemGlueFactory *pGlue) { EnterCriticalSectionWait ecs ( &s_csFactoryMap ); LeaveCriticalSectionScope lcs ( &s_csFactoryMap );
try { bool bFound = false; PTR2PLONG::iterator mapIter;
mapIter = s_factorymap.find(pGlue);
if ( mapIter != s_factorymap.end() ) { s_factorymap.erase(mapIter); } else { LogErrorMessage2(L"Can't find factory in map: %p", pGlue); } } catch( ... ) { // we should not be here
// do not re-throw (called from destructor)
} }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::IncrementMapCount
//
// Increments the refcount on a DLL
//
/////////////////////////////////////////////////////////////////////
LONG CWbemProviderGlue::IncrementMapCount(const CWbemGlueFactory *pGlue) { LONG lRet = -1; LockFactoryMap(); OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
PTR2PLONG::iterator mapIter; mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
if (mapIter != CWbemProviderGlue::s_factorymap.end()) { lRet = InterlockedIncrement((*mapIter).second); } else { // This is very bad. This should have been created
// at CWbemGlueFactory constructor time.
LogErrorMessage2(L"Can't find factory in map: %p", pGlue); }
return lRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::IncrementMapCount
//
// Increments the refcount on a DLL
//
/////////////////////////////////////////////////////////////////////
LONG CWbemProviderGlue::IncrementMapCount(PLONG pCount) { return InterlockedIncrement(pCount); }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::DecrementMapCount
//
// Decrements the refcount on a DLL
//
/////////////////////////////////////////////////////////////////////
LONG CWbemProviderGlue::DecrementMapCount(const CWbemGlueFactory *pGlue) { LONG lRet = -1;
EnterCriticalSectionWait ecs ( &s_csFactoryMap ); LeaveCriticalSectionScope lcs ( &s_csFactoryMap );
try { // Find the matching CWbemGlueFactory in the CWbemGlueFactory<->refcount map
PTR2PLONG::iterator mapIter; mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
if (mapIter != CWbemProviderGlue::s_factorymap.end()) { lRet = InterlockedDecrement((*mapIter).second);
if (lRet < 0) { LogErrorMessage2(L"RefCount < 0 for glue %p", pGlue); ASSERT_BREAK(DUPLICATE_RELEASE); } } else { LogErrorMessage2(L"Can't find factory in map: %p", pGlue); } } catch ( ... ) { // we should not be here
// do not re-throw (called from destructor)
}
return lRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::DecrementMapCount
//
// Decrements the refcount on a DLL
//
/////////////////////////////////////////////////////////////////////
LONG CWbemProviderGlue::DecrementMapCount(PLONG pCount) { LONG lRet = InterlockedDecrement(pCount);
try { if (lRet < 0) { LogErrorMessage2(L"RefCount < 0 for %p", pCount); ASSERT_BREAK(DUPLICATE_RELEASE); } } catch ( ... ) { // we should not be here
// do not re-throw (called from destructor)
}
return lRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::GetMapCountPtr
//
// Returns the pointer to the plong for this glue factory
//
/////////////////////////////////////////////////////////////////////
PLONG CWbemProviderGlue::GetMapCountPtr(const CWbemGlueFactory *pGlue) { PLONG pRet = NULL; LockFactoryMap(); OnDelete0 < void (__stdcall *)(void), CWbemProviderGlue::UnlockFactoryMap> SmartUnlockFactoryMap ;
// Find the matching CWbemGlueFactory in the CWbemGlueFactory<->refcount map
PTR2PLONG::iterator mapIter; mapIter = CWbemProviderGlue::s_factorymap.find( pGlue );
if (mapIter != CWbemProviderGlue::s_factorymap.end()) { pRet = mapIter->second; } else { LogErrorMessage2(L"Can't find factory in map: %p", pGlue); }
return pRet; }
/////////////////////////////////////////////////////////////////////
//
// Function: CWbemProviderGlue::AddFlushPtr
//
// Add the this pointer to a provider to the list of providers
// that need to be flushed.
//
/////////////////////////////////////////////////////////////////////
void CWbemProviderGlue::AddFlushPtr(LPVOID pVoid) { CLockWrapper lockwrap(m_csFlushPtrs);
m_FlushPtrs.insert(pVoid); }
|