windows-nt/Source/XPSP1/NT/base/wmi/cimmap/classprov.cpp
2020-09-26 16:20:57 +08:00

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);
}