/*++ Copyright (C) 1997-2001 Microsoft Corporation Module Name: Abstract: History: --*/ //*************************************************************************** // // NTPERF.CPP // // Mapped NT5 Perf Counter Provider // // raymcc 02-Dec-97 Created. // raymcc 20-Feb-98 Updated to use new initializer. // //*************************************************************************** #include "precomp.h" #include #include #include #include "flexarry.h" #include "ntperf.h" #include "oahelp.inl" #include "perfhelp.h" #include "refreshr.h" //*************************************************************************** // // CNt5PerfProvider constructor // //*************************************************************************** // ok CNt5PerfProvider::CNt5PerfProvider() { m_lRef = 0; } //*************************************************************************** // // CNt5PerfProvider destructor // //*************************************************************************** // ok CNt5PerfProvider::~CNt5PerfProvider() { for (int i = 0; i < m_aCache.Size(); i++) delete (CClassMapInfo *) m_aCache[i]; RegCloseKey(HKEY_PERFORMANCE_DATA); } //*************************************************************************** // // CNt5Refresher::AddRef // // Standard COM AddRef(). // //*************************************************************************** // ok ULONG CNt5PerfProvider::AddRef() { return InterlockedIncrement(&m_lRef); } //*************************************************************************** // // CNt5Refresher::Release // // Standard COM Release(). // //*************************************************************************** // ok ULONG CNt5PerfProvider::Release() { long lRef = InterlockedDecrement(&m_lRef); if(lRef == 0) delete this; return lRef; } //*************************************************************************** // // CNt5Refresher::QueryInterface // // Standard COM QueryInterface(). We have to support two interfaces, // the IWbemHiPerfProvider interface itself to provide the objects and // the IWbemProviderInit interface to initialize the provider. // //*************************************************************************** // ok HRESULT CNt5PerfProvider::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown || riid == IID_IWbemHiPerfProvider) { *ppv = (IWbemHiPerfProvider*) this; AddRef(); return S_OK; } else if (riid == IID_IWbemProviderInit) { *ppv = (IWbemProviderInit *) this; AddRef(); return S_OK; } else return E_NOINTERFACE; } //*************************************************************************** // // CNt5Refresher::Initialize // // Called once during startup. Indicates to the provider which // namespace it is being invoked for and which User. It also supplies // a back pointer to WINMGMT so that class definitions can be retrieved. // // We perform any one-time initialization in this routine. The // final call to Release() is for any cleanup. // // The current user. // Reserved. // The namespace for which we are being activated. // The locale under which we are to be running. // An active pointer back into the current namespace // from which we can retrieve schema objects. // The user's context object. We simply reuse this // during any reentrant operations into WINMGMT. // The sink to which we indicate our readiness. // //*************************************************************************** // ok HRESULT CNt5PerfProvider::Initialize( /* [unique][in] */ LPWSTR wszUser, /* [in] */ LONG lFlags, /* [in] */ LPWSTR wszNamespace, /* [unique][in] */ LPWSTR wszLocale, /* [in] */ IWbemServices __RPC_FAR *pNamespace, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink ) { pInitSink->SetStatus(0, WBEM_S_INITIALIZED); return NO_ERROR; } //*************************************************************************** // // CNt5Refresher::QueryInstances // // Called whenever a complete, fresh list of instances for a given // class is required. The objects are constructed and sent back to the // caller through the sink. The sink can be used in-line as here, or // the call can return and a separate thread could be used to deliver // the instances to the sink. // // Parameters: // A pointer to the relevant namespace. This // should not be AddRef'ed or retained past the // execution of this method. // The class name for which instances are required. // Reserved. // The user-supplied context (used during callbacks // into WINMGMT). // The sink to which to deliver the objects. The objects // can be delivered synchronously through the duration // of this call or asynchronously (assuming we // had a separate thread). A IWbemObjectSink::SetStatus // call is required at the end of the sequence. // //*************************************************************************** // ok HRESULT CNt5PerfProvider::QueryInstances( /* [in] */ IWbemServices __RPC_FAR *pNamespace, /* [string][in] */ WCHAR __RPC_FAR *wszClass, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pCtx, /* [in] */ IWbemObjectSink __RPC_FAR *pSink ) { if (pNamespace == 0 || wszClass == 0 || pSink == 0) return WBEM_E_INVALID_PARAMETER; // Ensure the class is in our cache and mapped. // ============================================ BOOL bRes = MapClass(pNamespace, wszClass, pCtx); if (bRes == FALSE) { // Class is not one of ours. return WBEM_E_INVALID_CLASS; } CClassMapInfo *pClsMap = FindClassMap(wszClass); // Refresh the instances. // ====================== PerfHelper::QueryInstances(pClsMap, pSink); // Tell WINMGMT we are finished. // =========================== pSink->SetStatus(0, WBEM_NO_ERROR, 0, 0); return NO_ERROR; } //*************************************************************************** // // CNt5Refresher::CreateRefresher // // Called whenever a new refresher is needed by the client. // // Parameters: // A pointer to the relevant namespace. Not used. // Not used. // Receives the requested refresher. // //*************************************************************************** // ok HRESULT CNt5PerfProvider::CreateRefresher( /* [in] */ IWbemServices __RPC_FAR *pNamespace, /* [in] */ long lFlags, /* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher ) { if (pNamespace == 0 || ppRefresher == 0) return WBEM_E_INVALID_PARAMETER; // Construct a new empty refresher. // ================================ CNt5Refresher *pNewRefresher = new CNt5Refresher; // Follow COM rules and AddRef() the thing before sending it back. // =============================================================== pNewRefresher->AddRef(); *ppRefresher = pNewRefresher; return NO_ERROR; } //*************************************************************************** // // CNt5Refresher::CreateRefreshableObject // // Called whenever a user wants to include an object in a refresher. // // Parameters: // A pointer to the relevant namespace in WINMGMT. // A pointer to a copy of the object which is to be // added. This object itself cannot be used, as // it not owned locally. // The refresher to which to add the object. // Not used. // Not used here. // A pointer to the internal object which was added // to the refresher. // The Object Id (for identification during removal). // //*************************************************************************** // ok HRESULT CNt5PerfProvider::CreateRefreshableObject( /* [in] */ IWbemServices __RPC_FAR *pNamespace, /* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate, /* [in] */ IWbemRefresher __RPC_FAR *pRefresher, /* [in] */ long lFlags, /* [in] */ IWbemContext __RPC_FAR *pContext, /* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable, /* [out] */ long __RPC_FAR *plId ) { *ppRefreshable = 0; // Make a copy of the template object. // =================================== IWbemClassObject *pOriginal = 0; pTemplate->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOriginal); IWbemClassObject *pNewCopy = 0; pOriginal->Clone(&pNewCopy); // Get the class name of the object. // ================================= VARIANT v; VariantInit(&v); BSTR strClassProp = SysAllocString(L"__CLASS"); pOriginal->Get(strClassProp, 0, &v, 0, 0); SysFreeString(strClassProp); // We are now done with the original object // ======================================== pOriginal->Release(); // We now get the IWbemObjectAccess form of the cloned object // and release the unused interface. // ========================================================== IWbemObjectAccess *pNewAccess = 0; pNewCopy->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewAccess); pNewCopy->Release(); // We don't need the IWbemClassObject interface any more // We now have an IWbemObjectAccess pointer for the refreshable // object in . // ============================================================ CNt5Refresher *pRef = (CNt5Refresher *) pRefresher; // Map the class info for this instance. // ===================================== BOOL bRes = MapClass(pNamespace, V_BSTR(&v), pContext); if (bRes == FALSE) { // Class is not one of ours. pNewAccess->Release(); VariantClear(&v); return WBEM_E_INVALID_CLASS; } CClassMapInfo *pClsMap = FindClassMap(V_BSTR(&v)); if (pClsMap == 0) { pNewAccess->Release(); VariantClear(&v); return WBEM_E_INVALID_CLASS; } // Add the object to the refresher. // This method will AddRef() the object before returning. // ====================================================== pRef->AddObject( pNewAccess, pClsMap, plId ); // Return object to the user. // ========================== *ppRefreshable = pNewAccess; VariantClear(&v); return NO_ERROR; } //*************************************************************************** // // CNt5Refresher::StopRefreshing // // Called whenever a user wants to remove an object from a refresher. // // Parameters: // The refresher object from which we are to // remove the perf object. // The ID of the object. // Not used. // //*************************************************************************** // ok HRESULT CNt5PerfProvider::StopRefreshing( /* [in] */ IWbemRefresher __RPC_FAR *pRefresher, /* [in] */ long lId, /* [in] */ long lFlags ) { CNt5Refresher *pRef = (CNt5Refresher *) pRefresher; BOOL bRes = pRef->RemoveObject(lId); if (bRes == FALSE) return WBEM_E_FAILED; return WBEM_NO_ERROR; } //*************************************************************************** // // CNt5Refresher::CreateRefreshableEnum // // Called whenever a user wants to create an enumeration in a refresher. // // Parameters: // The namespace this is for // Name of the class we are enumerating // The refresher object from which we are to // remove the perf object. // Not used. // Wbem Context object // Enumerator object into which refresher should place // its results // The enum id (for identification during removal) // //*************************************************************************** // ok HRESULT CNt5PerfProvider::CreateRefreshableEnum( /* [in] */ IWbemServices* pNamespace, /* [in, string] */ LPCWSTR wszClass, /* [in] */ IWbemRefresher* pRefresher, /* [in] */ long lFlags, /* [in] */ IWbemContext* pContext, /* [in] */ IWbemHiPerfEnum* pHiPerfEnum, /* [out] */ long* plId ) { // Just a placeholder for now return E_NOTIMPL; } //*************************************************************************** // // CNt5Refresher::GetObjects // // Called whenever a user wants to create an enumeration in a refresher. // // Parameters: // The namespace this is for // Number of objects in the array // Objects to retrieve (keys are set) // Not used. // Wbem Context object // Enumerator object into which refresher should place // its results // The enum id (for identification during removal) // //*************************************************************************** // ok HRESULT CNt5PerfProvider::GetObjects( /* [in] */ IWbemServices* pNamespace, /* [in] */ long lNumObjects, /* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj, /* [in] */ long lFlags, /* [in] */ IWbemContext* pContext) { // Just a placeholder for now return E_NOTIMPL; } //*************************************************************************** // // CNt5Refresher::MapClass // // Adds the class map to an internal cache. // // The pointer to the map info to add. This pointer // is acquired by this function and should not be // deleted by the caller. // //*************************************************************************** // ok void CNt5PerfProvider::AddClassMap( IN CClassMapInfo *pClsMap ) { for (int i = 0; i < m_aCache.Size(); i++) { CClassMapInfo *pTracer = (CClassMapInfo *) m_aCache[i]; if (_wcsicmp(pClsMap->m_pszClassName, pTracer->m_pszClassName) < 0) { m_aCache.InsertAt(i, pClsMap); return; } } // If here, add it to the end. // =========================== m_aCache.Add(pClsMap); } //*************************************************************************** // // CNt5Refresher::FindClassMap // //*************************************************************************** // ok CClassMapInfo *CNt5PerfProvider::FindClassMap( LPWSTR pszClassName ) { // Binary search the cache. // ======================== int l = 0, u = m_aCache.Size() - 1; while (l <= u) { int m = (l + u) / 2; CClassMapInfo *pClsMap = (CClassMapInfo *) m_aCache[m]; if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) < 0) u = m - 1; else if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) > 0) l = m + 1; else // Hit! return pClsMap; } return NULL; } //*************************************************************************** // // CNt5Refresher::MapClass // // Retrieves the requested class and places it in the cache. // // Parameters: // pNs The namespace which contains the class definition. // wsClass The class name. // pCtx The inbound context object. Only used for reentrant // calls. // //*************************************************************************** // ok BOOL CNt5PerfProvider::MapClass( IN IWbemServices *pNs, IN WCHAR *wszClass, IN IWbemContext *pCtx ) { HRESULT hRes = 0; // See if the class is already in the cache. // ========================================= if (FindClassMap(wszClass) != 0) return TRUE; // Get the class definition from WINMGMT. // ==================================== IWbemClassObject *pClsDef = 0; hRes = pNs->GetObject(CBSTR(wszClass), 0, pCtx, &pClsDef, 0); if (hRes) { // Unable to retrieve the class definition return FALSE; } // Verify the class is one of ours by checking // the "provider" qualifier to ensure it matches // the name that we we have for this component. // ============================================= IWbemQualifierSet *pQSet = 0; hRes = pClsDef->GetQualifierSet(&pQSet); if (hRes) { pClsDef->Release(); return FALSE; } VARIANT v; VariantInit(&v); pQSet->Get(CBSTR(L"Provider"), 0, &v, 0); pQSet->Release(); if (_wcsicmp(V_BSTR(&v), PROVIDER_NAME) != 0) { pClsDef->Release(); return FALSE; } // Get the property handles and mappings to the perf counter ids // by calling the Map() method of CClassMapInfo. // ============================================================== CClassMapInfo *pMapInfo = new CClassMapInfo; if (pMapInfo->Map(pClsDef) == FALSE) { delete pMapInfo; pClsDef->Release(); return FALSE; } // Add it to the cache. // ==================== AddClassMap(pMapInfo); return TRUE; }