704 lines
17 KiB
C++
704 lines
17 KiB
C++
//***************************************************************************
|
|
//
|
|
// 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);
|
|
}
|
|
|