|
|
//***************************************************************************
//
// CLASSPRO.CPP
//
// Module: CDM Provider
//
// Purpose: Defines the CClassPro class. An object of this class is
// created by the class factory for each connection.
//
// Copyright (c) 2000 Microsoft Corporation
//
//***************************************************************************
#include <objbase.h>
#include <wbemprov.h>
#include <process.h>
#include <unknwn.h>
#include "debug.h"
#include "wbemmisc.h"
#include "useful.h"
#include "testinfo.h"
#include "sample.h"
// CONSIDER: Does this really need to stay a global ???
//
// This is the global list of all of the CIM classes and their
// corresponsing WDM classes that are managed by the provider.
//
// It is maintained as a global since WinMgmt is aggressive in
// releasing the CClassProv, but we really want to maintain the result
// objects and do not want to be unloaded unless all result objects are
// cleared.
//
CWdmClass *WdmClassHead;
void CleanupAllClasses( ) { CWdmClass *WdmClass; CWdmClass *WdmClassNext;
//
// Loop over all classes that were supported by the provider and
// clean them up
//
WdmClass = WdmClassHead; while (WdmClass != NULL) { WdmClassNext = WdmClass->GetNext(); delete WdmClass; } }
//***************************************************************************
//
// CClassPro::CClassPro
// CClassPro::~CClassPro
//
//***************************************************************************
CClassPro::CClassPro( BSTR ObjectPath, BSTR User, BSTR Password, IWbemContext * pCtx ) { m_pCimServices = NULL; m_cRef=0; InterlockedIncrement(&g_cObj); return; }
CClassPro::~CClassPro(void) { if(m_pCimServices) { m_pCimServices->Release(); } InterlockedDecrement(&g_cObj); return; }
//***************************************************************************
//
// CClassPro::QueryInterface
// CClassPro::AddRef
// CClassPro::Release
//
// Purpose: IUnknown members for CClassPro object.
//***************************************************************************
STDMETHODIMP CClassPro::QueryInterface(REFIID riid, PPVOID ppv) { HRESULT hr; *ppv=NULL;
// Since we have dual inheritance, it is necessary to cast the return type
if(riid== IID_IWbemServices) { *ppv=(IWbemServices*)this; }
if(IID_IUnknown==riid || riid== IID_IWbemProviderInit) { *ppv=(IWbemProviderInit*)this; }
if (NULL!=*ppv) { AddRef(); hr = NOERROR; } else { hr = E_NOINTERFACE; } return(hr); }
STDMETHODIMP_(ULONG) CClassPro::AddRef(void) { return(++m_cRef); }
STDMETHODIMP_(ULONG) CClassPro::Release(void) { ULONG nNewCount = InterlockedDecrement((long *)&m_cRef); if (0L == nNewCount) { delete this; } return(nNewCount); }
/***********************************************************************
* * * CClassPro::Initialize * * * * Purpose: This is the implementation of IWbemProviderInit. The method * * is need to initialize with CIMOM. * * * ***********************************************************************/
STDMETHODIMP CClassPro::Initialize(LPWSTR pszUser, LONG lFlags, LPWSTR pszNamespace, LPWSTR pszLocale, IWbemServices *pNamespace, IWbemContext *pCtx, IWbemProviderInitSink *pInitSink) { if (pNamespace) { pNamespace->AddRef(); } m_pCimServices = pNamespace;
//
// Let CIMOM know you are initialized
//
pInitSink->SetStatus(WBEM_S_INITIALIZED, 0); return(WBEM_S_NO_ERROR); }
//***************************************************************************
//
// CClassPro::CreateClassEnumAsync
//
// Purpose: Asynchronously enumerates the classes this provider supports.
// Note that this sample only supports one.
//
//***************************************************************************
SCODE CClassPro::CreateClassEnumAsync( const BSTR Superclass, long lFlags, IWbemContext *pCtx, IWbemObjectSink *pHandler ) { return(WBEM_E_NOT_SUPPORTED); }
//***************************************************************************
//
// CClassPro::CreateInstanceEnumAsync
//
// Purpose: Asynchronously enumerates the instances.
//
//***************************************************************************
SCODE CClassPro::CreateInstanceEnumAsync( const BSTR ClassName, long lFlags, IWbemContext *pCtx, IWbemObjectSink FAR* pHandler ) { HRESULT hr; ULONG i, Count; IWbemClassObject *pCimInstance; CWdmClass *WdmClass; WmipDebugPrint(("CDMPROV: Enumerate instances of class %ws\n", ClassName)); //
// Do a check of arguments and make sure we have pointer to Namespace
//
if (pHandler == NULL || m_pCimServices == NULL) { return WBEM_E_INVALID_PARAMETER; }
//
// Obtain a wdm class object that represents this class
//
hr = LookupWdmClass(pCtx, ClassName, &WdmClass);
if (hr == WBEM_S_NO_ERROR) { if (WdmClass->IsInstancesAvailable()) { Count = WdmClass->GetInstanceCount(); for (i = 0; i < Count; i++) { pCimInstance = WdmClass->GetCimInstance(i); //
// Send the object to the caller
//
hr = pHandler->Indicate(1, &pCimInstance); } } }
//
// TODO: Create extended error object with more info about the
// error that occured. The object is created by
// CreateInst("__ExtendedStatus")
//
pHandler->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
return(hr); }
//***************************************************************************
//
// CClassPro::GetObjectByPathAsync
//
// Purpose: Returns either an instance or a class.
//
//***************************************************************************
SCODE CClassPro::GetObjectAsync( const BSTR ObjectPath, long lFlags, IWbemContext *pCtx, IWbemObjectSink FAR* pHandler ) {
HRESULT hr; IWbemClassObject FAR* Instance;
// Do a check of arguments and make sure we have pointer to Namespace
if (ObjectPath == NULL || pHandler == NULL || m_pCimServices == NULL) { return WBEM_E_INVALID_PARAMETER; } hr = GetByPath(pCtx, ObjectPath, &Instance); if (hr == WBEM_S_NO_ERROR) { WmipDebugPrint(("CDMProv: Found instance %p for relpath %ws\n", Instance, ObjectPath)); hr = pHandler->Indicate(1, &Instance); } else { WmipDebugPrint(("CDMProv: Did not find instance for relpath %ws\n", ObjectPath)); hr = WBEM_E_NOT_FOUND; }
// Set Status
pHandler->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
return(hr); } //***************************************************************************
//
// CClassPro::GetByPath
//
// Purpose: Creates an instance given a particular Path value.
//
// All objects returned are assumed to be AddRefed
//
//***************************************************************************
HRESULT CClassPro::GetByPath( IWbemContext *pCtx, BSTR ObjectPath, IWbemClassObject **Instance ) { HRESULT hr = WBEM_S_NO_ERROR; WCHAR ClassName[MAX_PATH+1]; WCHAR *p; int iNumQuotes = 0; int i, Count; CWdmClass *WdmClass; BSTR s;
//
// This is where we are queried for a class based upon its relpath.
// We need to parse the relpath to get the class name and then look
// at the relpath to determine which instance of the class we are
// interested in and then build up the instance and return it
//
//
//
// Obtain the class name by copying up to the .
//
for (p = ObjectPath, i = 0; (*p != 0) && (*p != L'.') && (i < MAX_PATH); p++, i++) { ClassName[i] = *p; }
if (*p != L'.') { //
// If we did end our loop with a . then we failed to parse
// properly
//
WmipDebugPrint(("CDMPROV: Unable to parse relpath %ws at %ws, i = %d\n", ObjectPath, p, i)); } ClassName[i] = 0;
WmipDebugPrint(("CDMPROV: Class %ws looking for relpath %ws\n", ClassName, ObjectPath)); //
// Obtain a Wdm class that represents this classname
//
hr = LookupWdmClass(pCtx, ClassName, &WdmClass);
if (hr == WBEM_S_NO_ERROR) { if (WdmClass->IsInstancesAvailable()) { //
// Assume that we will not find the object instance
//
hr = WBEM_E_NOT_FOUND;
Count = WdmClass->GetInstanceCount(); for (i = 0; i < Count; i++) { if (_wcsicmp(ObjectPath, WdmClass->GetCimRelPath(i)) == 0) { *Instance = WdmClass->GetCimInstance(i); hr = WBEM_S_NO_ERROR; break; } } } else { hr = WBEM_E_FAILED; } }
return(hr); }
/************************************************************************
* * *CMethodPro::ExecMethodAsync * * * *Purpose: This is the Async function implementation. * * The only method supported in this sample is named Echo. It * * takes an input string, copies it to the output and returns the* * length. * * * * * ************************************************************************/
STDMETHODIMP CClassPro::ExecMethodAsync( const BSTR ObjectPath, const BSTR MethodName, long lFlags, IWbemContext* pCtx, IWbemClassObject* pInParams, IWbemObjectSink* pResultSink ) { HRESULT hr, hrDontCare; IWbemClassObject * pMethodClass = NULL; IWbemClassObject * pOutClass = NULL; IWbemClassObject* pOutParams = NULL; WCHAR ClassName[MAX_PATH]; WCHAR *p; VARIANT v, vRetVal; int RelPathIndex; CWdmClass *WdmClass; BSTR WdmObjectPath;
VariantInit(&v); VariantInit(&vRetVal); //
// Extract this class name from the object path
//
wcscpy(ClassName, ObjectPath); p = ClassName; while ((*p != 0) && (*p != L'.')) { p++; } *p = 0;
WmipDebugPrint(("CDMPROV: Exec method %ws for instanec %ws\n", MethodName, ObjectPath));
//
// Obtain a Wdm class that represents this ClassName
//
hr = LookupWdmClass(pCtx, ClassName, &WdmClass); if (hr == WBEM_S_NO_ERROR) { if (WdmClass->IsInstancesAvailable()) { hr = WdmClass->GetIndexByCimRelPath(ObjectPath, &RelPathIndex); if (hr == WBEM_S_NO_ERROR) { WdmObjectPath = WdmClass->GetWdmRelPath(RelPathIndex);
//
// CONSIDER: Do we need to do any processing on the input
// or output parameter objects ??
//
hr = WdmClass->GetWdmServices()->ExecMethod(WdmObjectPath, MethodName, lFlags, pCtx, pInParams, &pOutParams, NULL);
if ((hr == WBEM_S_NO_ERROR) && (pOutParams != NULL)) { pResultSink->Indicate(1, &pOutParams); pOutParams->Release(); } } } }
pResultSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL,NULL); return(hr); }
//
// TODO: Implement setting and deletion
//
SCODE CClassPro::PutClassAsync( /* [in] */ IWbemClassObject __RPC_FAR *pObject, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { return(WBEM_E_NOT_SUPPORTED); } SCODE CClassPro::DeleteClassAsync( /* [in] */ const BSTR Class, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { return(WBEM_E_NOT_SUPPORTED); } SCODE CClassPro::PutInstanceAsync( /* [in] */ IWbemClassObject __RPC_FAR *pInst, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResultsSink) { HRESULT hr; CWdmClass *WdmClass; VARIANT Values[2]; PWCHAR Names[2]; CIMTYPE Types[2]; int RelPathIndex; if (pInst == NULL || pResultsSink == NULL ) { return WBEM_E_INVALID_PARAMETER; }
//
// Get the class name
//
Names[0] = L"__CLASS"; Types[0] = CIM_STRING; Names[1] = L"__RELPATH"; Types[1] = CIM_REFERENCE; hr = WmiGetPropertyList(pInst, 2, Names, Types, Values);
if (hr == WBEM_S_NO_ERROR) { hr = LookupWdmClass(pCtx, Values[0].bstrVal, &WdmClass); if (hr == WBEM_S_NO_ERROR) { //
// We need to pull out the properties from the instance
// passed to us, do any mapping to WDM properties and then
// set them in the WDM instance
//
hr = WdmClass->GetIndexByCimRelPath(Values[1].bstrVal, &RelPathIndex); if (hr == WBEM_S_NO_ERROR) { hr = WdmClass->PutInstance(pCtx, RelPathIndex, pInst); } } VariantClear(&Values[0]); VariantClear(&Values[1]); } pResultsSink->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL,NULL); return(hr); } SCODE CClassPro::DeleteInstanceAsync( /* [in] */ const BSTR ObjectPath, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pResponseHandler) { return(WBEM_E_NOT_SUPPORTED); }
CWdmClass *CClassPro::FindExistingWdmClass( PWCHAR CimClassName ) { CWdmClass *WdmClass;
//
// This routine assumes any sync mechanism has been done outside of
// this routine
//
WdmClass = WdmClassHead; while (WdmClass != NULL) { if (WdmClass->ClaimCimClassName(CimClassName)) { //
// We found an existing test services for this class.
//
return(WdmClass); } WdmClass = WdmClass->GetNext(); } return(NULL); }
HRESULT CClassPro::LookupWdmClass( IWbemContext *pCtx, const BSTR CimClassName, CWdmClass **WdmClassPtr ) { HRESULT hr; CWdmClass *WdmClass, *OtherWdmClass; WmipAssert(CimClassName != NULL); WmipAssert(WdmClassPtr != NULL); //
// Look up the class name and find the Wdm Test Services
// class that represents it.
//
EnterCritSection(); WdmClass = FindExistingWdmClass(CimClassName); LeaveCritSection(); if (WdmClass != NULL) { //
// CONSIDER: Refresh instances from WDM back into CIM
//
*WdmClassPtr = WdmClass; return(WBEM_S_NO_ERROR); } //
// If the WDM test services has not yet been initialized for this
// CDM diagnostic classes then go ahead and do so
//
WdmClass = new CWdmClass();
hr = WdmClass->InitializeSelf(pCtx, CimClassName);
if (hr == WBEM_S_NO_ERROR) {
//
// Now check to see if another thread created and inserted the
// test services for the class while we were trying to
// initialize it. Since we want only one test services we throw
// ours away and use the other
//
EnterCritSection(); OtherWdmClass = FindExistingWdmClass(CimClassName);
if (OtherWdmClass == NULL) { //
// Horray, we win do insert our own test into list
//
WdmClass->InsertSelf(&WdmClassHead); LeaveCritSection(); hr = WdmClass->RemapToCimClass(pCtx);
//
// Decrement the counter to indicate that instances are
// available. This refcount was assigned in the constructor
//
WdmClass->DecrementMappingInProgress(); if (hr != WBEM_S_NO_ERROR) { WmipDebugPrint(("CDMPROV: Inited failed %x for %p for %ws\n", hr, WdmClass, CimClassName)); } } else { //
// We lost, so use existing test services
//
WmipDebugPrint(("CDMPROV: WdmClass %p lost insertion race to %p\n", WdmClass, OtherWdmClass)); LeaveCritSection(); delete WdmClass; WdmClass = OtherWdmClass; }
*WdmClassPtr = WdmClass;
} return(hr); }
|