//*************************************************************************** // // PGDE.CPP // // Module: HEALTHMON SERVER AGENT // // Purpose: CPolledGetObjectDataCollector class to do WMI instance collection. // // Copyright (c)1999 Microsoft Corporation, All Rights Reserved // //*************************************************************************** #include "pgde.h" #include "system.h" extern CSystem* g_pSystem; ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CPolledGetObjectDataCollector::CPolledGetObjectDataCollector() { MY_OUTPUT(L"ENTER ***** CPolledGetObjectDataCollector...", 1); m_pRefresher = NULL; m_pConfigureRefresher = NULL; m_pEnum = NULL; m_pObjAccess = NULL; m_lId = 0; m_szObjectPath = NULL; m_deType = HM_PGDE; m_lNumInstancesCollected = 0; m_pEnumObjs = NULL; m_pCallResult = NULL; MY_OUTPUT(L"EXIT ***** CPolledGetObjectDataCollector...", 1); } CPolledGetObjectDataCollector::~CPolledGetObjectDataCollector() { MY_OUTPUT(L"ENTER ***** ~CPolledGetObjectDataCollector...", 1); if (m_szObjectPath) { delete [] m_szObjectPath; } if (m_pRefresher != NULL) { m_pRefresher->Release(); m_pRefresher = NULL; } if (m_pConfigureRefresher != NULL) { m_pConfigureRefresher->Release(); m_pConfigureRefresher = NULL; } if (m_pEnum != NULL) { m_pEnum->Release(); m_pEnum = NULL; } if (m_pObjAccess != NULL) { m_pObjAccess->Release(); m_pObjAccess = NULL; } EnumDone(); MY_OUTPUT(L"EXIT ***** ~CPolledGetObjectDataCollector...", 1); } // // Load a single DataCollector, and everything under it. // HRESULT CPolledGetObjectDataCollector::LoadInstanceFromMOF(IWbemClassObject* pObj, CDataGroup *pParentDG, LPTSTR pszParentObjPath, BOOL bModifyPass/*FALSE*/) { HRESULT hRes; IWbemClassObject* pConfigObj = NULL; BOOL bRetValue = TRUE; HRESULT hRetRes = S_OK; int i, iSize; CThreshold* pThreshold; MY_OUTPUT(L"ENTER ***** CPolledGetObjectDataCollector::LoadInstanceFromMOF...", 4); iSize = m_thresholdList.size(); for (i = 0; i < iSize ; i++) { MY_ASSERT(im_bValidLoad == FALSE) return WBEM_E_INVALID_OBJECT; // return S_OK; } if (m_szObjectPath) { delete [] m_szObjectPath; m_szObjectPath = NULL; } m_lNumInstancesCollected = 0; // // Call the base class to load the common properties. Then do the specific ones. // hRetRes = CDataCollector::LoadInstanceFromMOF(pObj, pParentDG, pszParentObjPath, bModifyPass); MY_HRESASSERT(hRetRes); if (hRetRes!=S_OK) return hRetRes; // Get the GUID property hRetRes = GetStrProperty(pObj, L"ObjectPath", &m_szObjectPath); MY_HRESASSERT(hRetRes); if (hRetRes!=S_OK) goto error; // Decide if the path sets us up for multiple instances if (wcschr(m_szObjectPath, L'=')) { m_bMultiInstance = FALSE; } else { m_bMultiInstance = TRUE; } // // Check to see if the High Performance interfaces are supported // Otherwise we just revert to less efficient WMI interfaces // hRes = E_UNEXPECTED; if (SUCCEEDED(hRes)) { } else { m_pRefresher = NULL; bRetValue = FALSE; } if (bModifyPass) { } MY_OUTPUT(L"EXIT ***** CPolledGetObjectDataCollector::LoadInstanceFromMOF...", 4); return S_OK; error: MY_ASSERT(FALSE); m_bValidLoad = FALSE; Cleanup(FALSE); return hRetRes; } // // Get the instance out of WMI, and store all the properties we care about. // Also calculate statistics for them. // BOOL CPolledGetObjectDataCollector::CollectInstance(void) { BSTR bstrName = NULL; TCHAR szTemp[1024]; HRESULT hRes; IWbemClassObject *pObj = NULL; BOOL bRetValue = TRUE; PNSTRUCT *ppn; INSTSTRUCT inst; INSTSTRUCT *pinst; int i, j, iSize, jSize; SAFEARRAY *psaNames = NULL; BSTR PropName = NULL; CThreshold *pThreshold; IRSSTRUCT *pirs; ACTUALINSTSTRUCT *pActualInst; MY_OUTPUT(L"ENTER ***** CPolledGetObjectDataCollector::CollectInstance...", 1); m_lNumInstancesCollected = 0; if (m_pIWbemServices == NULL) { //XXX m_lCurrState = HM_CRITICAL; MY_ASSERT(FALSE); m_ulErrorCode = HMRES_BADWMI; GetLatestAgentError(HMRES_BADWMI, m_szErrorDescription); StoreStandardProperties(); return FALSE; } // // First we can tell if this is going to be single instance, or multi-instance // //XXXCould split this out into four functions that call from here. if (m_bMultiInstance==TRUE) { //XXXNeed to change this to be asyncronous??? // // MULTI-INSTANCE CASE // // // Check to see if the High Performance interfaces are supported // if (m_pRefresher!=NULL) { // Ask for the refresh #ifdef SAVE hRes = m_pRefresher->Refresh(0L); if (FAILED(hRes)) { } #endif // Now get the instance } else { // // We get an instance at a time, so we can set all to not needed first, // then go through them, do StoreValues... and delete what is not needed. // // // Mark each instance, so we can tell if we still need them. // iSize = m_pnList.size(); for (i = 0; i < iSize ; i++) { MY_ASSERT(iinstList.size(); for (j = 0; j < jSize ; j++) { MY_ASSERT(jinstList.size()); pinst = &ppn->instList[j]; pinst->bNeeded = FALSE; } } // Also for all thresholds under this DataCollector iSize = m_thresholdList.size(); for (i = 0; i < iSize; i++) { MY_ASSERT(im_irsList.size(); for (j = 0; j < jSize; j++) { MY_ASSERT(jm_irsList.size()); pirs = &pThreshold->m_irsList[j]; pirs->bNeeded = FALSE; } } iSize = m_actualInstList.size(); for (i=0; i < iSize; i++) { MY_ASSERT(ibNeeded = FALSE; } // // Enumerate through the instances // bstrName = SysAllocString(m_szObjectPath); m_pEnumObjs = NULL; hRes = m_pIWbemServices->CreateInstanceEnum(bstrName, WBEM_FLAG_SHALLOW|WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &m_pEnumObjs); if (hRes != S_OK) { m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); bRetValue = FALSE; MY_HRESASSERT(hRes); MY_OUTPUT2(L"PGDE-Unexpected Error: 0x%08x",hRes,4); MY_OUTPUT2(L"m_szGUID was=%s",m_szGUID,4); MY_OUTPUT2(L"bstrName was=%s",bstrName,4); MY_OUTPUT2(L"CreateInstanceEnum(%s)",m_szObjectPath,4); } else { m_bKeepCollectingSemiSync = TRUE; bRetValue = CollectInstanceSemiSync(); } SysFreeString(bstrName); } } else { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //XXX //XXX //XXX //We should just always use the multi-instance code, and delete this code. //The multi-instance code will still work in the single instance case!!!!! //XXX //XXX //XXX //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // SINGLE INSTANCE CASE // // // Check to see if the High Performance interfaces are supported // if (m_pRefresher!=NULL) { // Ask for the refresh #ifdef SAVE hRes = m_pRefresher->Refresh(0L); if (FAILED(hRes)) { } #endif // Now get the instances } else { // // Mark each instance, so we can tell if we still need them. // iSize = m_pnList.size(); for (i = 0; i < iSize ; i++) { MY_ASSERT(iinstList.size(); for (j = 0; j < jSize ; j++) { MY_ASSERT(jinstList.size()); pinst = &ppn->instList[j]; pinst->bNeeded = FALSE; } } // Also for all thresholds under this DataCollector iSize = m_thresholdList.size(); for (i = 0; i < iSize; i++) { MY_ASSERT(im_irsList.size(); for (j = 0; j < jSize; j++) { MY_ASSERT(jm_irsList.size()); pirs = &pThreshold->m_irsList[j]; pirs->bNeeded = FALSE; } } iSize = m_actualInstList.size(); for (i=0; i < iSize; i++) { MY_ASSERT(ibNeeded = FALSE; } // // This is the single instance, NON-HighPerformance case // swprintf(szTemp, L"%s", m_szObjectPath); hRes = GetWbemObjectInstSemiSync(&m_pIWbemServices, szTemp, m_pContext, &m_pCallResult); if (hRes != S_OK || m_pCallResult == NULL) { m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); bRetValue = FALSE; MY_HRESASSERT(hRes); MY_OUTPUT2(L"PGDE-Unexpected Error: 0x%08x",hRes,4); MY_OUTPUT2(L"m_szGUID was=%s",m_szGUID,4); MY_OUTPUT2(L"CreateWbemObjectInstSemiSync(%s)",m_szObjectPath,4); } else { m_bKeepCollectingSemiSync = TRUE; bRetValue = CollectInstanceSemiSync(); } } } MY_OUTPUT(L"EXIT ***** CPolledGetObjectDataCollector::CollectInstance...", 1); return bRetValue; } BOOL CPolledGetObjectDataCollector::CollectInstanceSemiSync(void) { LPTSTR pszID = NULL; HRESULT hRes; IWbemClassObject *pObj; IWbemClassObject *apObj[10]; INSTSTRUCT inst; long lStatus; ULONG uReturned = 0; MY_OUTPUT(L"ENTER ***** CPolledGetObjectDataCollector::CollectInstanceSemiSync...", 1); if (m_bMultiInstance==TRUE) { MY_ASSERT(m_pEnumObjs); // We never want to block here, so we set it for zero second timeout, // and have it return immediatly what it has available. hRes = m_pEnumObjs->Next(0, 10, apObj, &uReturned); if (hRes == WBEM_S_TIMEDOUT) { // Didn't get full list of instances yet. if (!ProcessObjects(uReturned, apObj)) { EnumDone(); return FALSE; } return FALSE; } else if (hRes == WBEM_S_FALSE) { // // Means that we are done. The number returned was less than asked for. // But we still process what we did recieve to finish it off. // Add in a fake instance for the number of instances returned. // if (!ProcessObjects(uReturned, apObj)) { EnumDone(); return FALSE; } else { m_ulErrorCode = 0; StoreStandardProperties(); EnumDone(); //XXXWhy was this here??? m_lCurrState = HM_GOOD; return TRUE; } } else if (hRes == WBEM_S_NO_ERROR) { // Means that we have an instance, The number returned was what was requested } else { MY_HRESASSERT(hRes); MY_OUTPUT2(L"PGDE-Unexpected Error MultiInstance Next(): 0x%08x",hRes,4); MY_OUTPUT2(L"m_szGUID was=%s",m_szGUID,4); MY_OUTPUT2(L"ObjectPath was=%s",m_szObjectPath,4); m_ulErrorCode = hRes; GetLatestWMIError(HMRES_ENUMFAIL, hRes, m_szErrorDescription); StoreStandardProperties(); EnumDone(); return FALSE; } if (apObj[0] == NULL) { // // NULL in this case can actually happen. An example is where the // threshold is to see if the SQL Server service is running. If it // is not even on the machine, then we would get an error looking // for its instance. // m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); EnumDone(); } else { MY_ASSERT(uReturned>=1); if (!ProcessObjects(uReturned, apObj)) { EnumDone(); return FALSE; } // else // { // m_ulErrorCode = 0; // } } } else { MY_ASSERT(m_pCallResult); lStatus = 0; // // Keep trying until we get WBEM_S_NO_ERROR. Then we know the GetObject call has completed. // hRes will contain the result of the origional GetObject call if needed. // hRes = m_pCallResult->GetCallStatus(0, &lStatus); if (hRes == WBEM_S_TIMEDOUT) { return FALSE; } else if (hRes == WBEM_S_NO_ERROR) { // Means that we are done. // HOWEVER, we don't know if we ever retrieved any instances! // This is different from the multi-instance case, because we do // ask for a single specific instance, and will know below if it is there! } else { MY_HRESASSERT(hRes); MY_OUTPUT2(L"PGDE-Unexpected Error SingleInstance GetCallStatus: 0x%08x",hRes,4); MY_OUTPUT2(L"m_szGUID was=%s",m_szGUID,4); MY_OUTPUT2(L"ObjectPath was=%s",m_szObjectPath,4); m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); EnumDone(); return FALSE; } // // This may mean that the call completed, and the object was not found (e.g. bad path). // if (lStatus != 0) { MY_HRESASSERT(lStatus); m_ulErrorCode = lStatus; GetLatestWMIError(HMRES_OBJECTNOTFOUND, lStatus, m_szErrorDescription); StoreStandardProperties(); EnumDone(); return FALSE; } // // Get the Object finaly. // hRes = m_pCallResult->GetResultObject(0, &pObj); if (pObj == NULL) { MY_ASSERT(FALSE); // // NULL in this case can actually happen. An example is where the // threshold is to see if the SQL Server service is running. If it // is not even on the machine, then we would get an error looking // for its instance. // m_lCurrState = HM_WARNING; m_ulErrorCode = 0; EnumDone(); } else { // // Figure out the key property name to identify instances with. // hRes = GetInstanceID(pObj, &pszID); if (hRes != S_OK) { pObj->Release(); m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); EnumDone(); return FALSE; } // // Mark instances need to keep around, and add new ones // hRes = CheckInstanceExistance(pObj, pszID); if (hRes != S_OK) { delete [] pszID; pObj->Release(); m_ulErrorCode = hRes; GetLatestWMIError(HMRES_OBJECTNOTFOUND, hRes, m_szErrorDescription); StoreStandardProperties(); EnumDone(); return FALSE; } m_lNumInstancesCollected = 1; StoreValues(pObj, pszID); delete [] pszID; pObj->Release(); pObj = NULL; // // We are done. // Add in a fake instance for the number of instances returned. // m_ulErrorCode = 0; StoreStandardProperties(); m_lCurrState = HM_GOOD; EnumDone(); } return TRUE; } MY_OUTPUT(L"EXIT ***** CPolledGetObjectDataCollector::CollectInstanceSemiSync...", 1); return FALSE; } BOOL CPolledGetObjectDataCollector::ProcessObjects(ULONG uReturned, IWbemClassObject **apObj) { HRESULT hRes; LPTSTR pszID; ULONG n; BOOL bRetValue = TRUE; for (n = 0; n < uReturned; n++) { if (g_pSystem->m_lNumInstancesAccepted Release(); apObj[n] = NULL; } return bRetValue; } //XXXIs EnumDone needed in all cases, if so place it in the base class BOOL CPolledGetObjectDataCollector::EnumDone(void) { IRSSTRUCT *pirs; IWbemClassObject *pObj = NULL; BOOL bRetValue = TRUE; PNSTRUCT *ppn; INSTSTRUCT inst; INSTSTRUCT *pinst; int i, j, iSize, jSize; CThreshold *pThreshold; SAFEARRAY *psaNames = NULL; BSTR PropName = NULL; INSTLIST::iterator iaPINST; IRSLIST::iterator iaPIRS; ACTUALINSTLIST::iterator iaPAI; ACTUALINSTSTRUCT *pActualInst; CleanupSemiSync(); //XXXAdd similar code to get rid of what is not needed in the m_instList //XXXOnce again take common code and place it in the base class!VVVVVVVVVVVVVVVVVVVVVVVVv // // Now loop through and get rid of instances that are no longer around // iSize = m_pnList.size(); for (i = 0; i < iSize; i++) { MY_ASSERT(iinstList.begin(); jSize = ppn->instList.size(); for (j = 0; j < jSize && iaPINST ; j++) { pinst = iaPINST; if (pinst->bNeeded == FALSE) { if (pinst->szInstanceID) delete [] pinst->szInstanceID; if (pinst->szCurrValue) delete [] pinst->szCurrValue; pinst->szCurrValue = NULL; iaPINST = ppn->instList.erase(iaPINST); } else { iaPINST++; } } } // Also for all thresholds under this DataCollector iSize = m_thresholdList.size(); for (i = 0; i < iSize; i++) { MY_ASSERT(im_irsList.begin(); jSize = pThreshold->m_irsList.size(); for (j = 0; j < jSize && iaPIRS ; j++) { pirs = iaPIRS; if (pirs->bNeeded == FALSE) { if (pirs->szInstanceID) delete [] pirs->szInstanceID; iaPIRS = pThreshold->m_irsList.erase(iaPIRS); } else { iaPIRS++; } } } iaPAI = m_actualInstList.begin(); jSize = m_actualInstList.size(); for (j = 0; j < jSize && iaPAI; j++) { pActualInst = iaPAI; if (pActualInst->bNeeded == FALSE) { if (pActualInst->szInstanceID) { delete [] pActualInst->szInstanceID; } if (pActualInst->pInst) { pActualInst->pInst->Release(); pActualInst->pInst = NULL; } iaPAI = m_actualInstList.erase(iaPAI); } else { iaPAI++; } } //XXXOnce again take common code and place it in the base class!^^^^^^^^^^^^^^^^^^^^^^^^^ return TRUE; } BOOL CPolledGetObjectDataCollector::CleanupSemiSync(void) { if (m_bMultiInstance==TRUE) { if (m_pEnumObjs) { m_pEnumObjs->Release(); m_pEnumObjs = NULL; } } else { if (m_pCallResult) { m_pCallResult->Release(); m_pCallResult = NULL; } } m_bKeepCollectingSemiSync = FALSE; m_lCollectionTimeOutCount = 0; return TRUE; }