//*************************************************************************** // // 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 #include #include #include #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); }