//==========================================================================// // Includes // //==========================================================================// #include // strupr #include // for sprintf. #include "perfmon.h" #include "utils.h" #include "pmemory.h" // for MemoryXXX (mallloc-type) routines #include "playback.h" // for PlayingBackLog #include "perfdata.h" // external declarations for this file #include "system.h" // for DeleteUnusedSystems #include "line.h" // for LineFind???() #include "perfmops.h" // for AppendObjectToValueList() #include "perfmsg.h" // for event log messages //==========================================================================// // Constants // //==========================================================================// TCHAR NamesKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"; TCHAR Counters[] = L"Counters"; TCHAR Help[] = L"Help"; TCHAR LastHelp[] = L"Last Help"; TCHAR LastCounter[] = L"Last Counter"; TCHAR SysVersion[] = L"Version"; TCHAR CounterNameStr[] = L"Counter "; TCHAR ExplainNameStr[] = L"Explain "; #define szPerfSubkey (NULL) TCHAR NULL_NAME[] = L" "; #define RESERVED 0L TCHAR DefaultLangId[4] ; TCHAR EnglishLangId[4] ; static HANDLE *lpHandles ; static int NumberOfHandles = 0 ; //==========================================================================// // Macros // //==========================================================================// //==========================================================================// // Local Data // //==========================================================================// // When the conversion of this code is complete, this will be the *only* // allocated copy of the performance data. It will monotonically grow // to hold the largest of the system's performance data. // PPERFDATA pGlobalPerfData ; //==========================================================================// // Local Functions // //==========================================================================// NTSTATUS AddNamesToArray ( LPTSTR pNames, DWORD dwLastID, LPWSTR *lpCounterId ) ; //======================================// // Object Accessors // //======================================// void ObjectName ( PPERFSYSTEM pSystem, PPERFOBJECT pObject, LPTSTR lpszName, int iLen ) { strclr (lpszName) ; QueryPerformanceName (pSystem, pObject->ObjectNameTitleIndex, 0, iLen, lpszName, FALSE) ; } //======================================// // Counter Accessors // //======================================// PPERFINSTANCEDEF FirstInstance( PPERFOBJECT pObjectDef ) { return (PPERFINSTANCEDEF ) ((PCHAR) pObjectDef + pObjectDef->DefinitionLength); } PPERFINSTANCEDEF NextInstance( PPERFINSTANCEDEF pInstDef ) { PERF_COUNTER_BLOCK *pCounterBlock; pCounterBlock = (PERF_COUNTER_BLOCK *) ((PCHAR) pInstDef + pInstDef->ByteLength); return (PPERFINSTANCEDEF ) ((PCHAR) pCounterBlock + pCounterBlock->ByteLength); } LPWSTR GetInstanceName( PPERFINSTANCEDEF pInstDef ) { return (LPWSTR) ((PCHAR) pInstDef + pInstDef->NameOffset); } DWORD GetAnsiInstanceName ( PPERFINSTANCEDEF pInstance, LPWSTR lpszInstance, DWORD dwCodePage ) { LPSTR szSource; DWORD dwLength; szSource = (LPSTR)GetInstanceName(pInstance); // the locale should be set here // pInstance->NameLength == the number of bytes (chars) in the string dwLength = mbstowcs (lpszInstance, szSource, pInstance->NameLength); lpszInstance[dwLength] = 0; // null terminate string buffer return dwLength; } DWORD GetUnicodeInstanceName ( PPERFINSTANCEDEF pInstance, LPWSTR lpszInstance ) { LPWSTR wszSource; DWORD dwLength; wszSource = GetInstanceName(pInstance) ; // pInstance->NameLength == length of string in BYTES so adjust to // number of wide characters here dwLength = pInstance->NameLength / sizeof(WCHAR); wcsncpy (lpszInstance, (LPWSTR)wszSource, dwLength); lpszInstance[dwLength] = 0; return (DWORD)(wcslen(lpszInstance)); // just incase there's null's in the string } void GetInstanceNameStr ( PPERFINSTANCEDEF pInstance, LPWSTR lpszInstance, DWORD dwCodePage ) { DWORD dwCharSize; DWORD dwLength; if (dwCodePage > 0) { dwCharSize = sizeof(CHAR); dwLength = GetAnsiInstanceName (pInstance, lpszInstance, dwCodePage); } else { // it's a UNICODE name dwCharSize = sizeof(WCHAR); dwLength = GetUnicodeInstanceName (pInstance, lpszInstance); } // sanity check here... // the returned string length (in characters) plus the terminating NULL // should be the same as the specified length in bytes divided by the // character size. If not then the codepage and instance data type // don't line up so test that here if ((dwLength + 1) != (pInstance->NameLength / dwCharSize)) { // something isn't quite right so try the "other" type of string type if (dwCharSize == sizeof(CHAR)) { // then we tried to read it as an ASCII string and that didn't work // so try it as a UNICODE (if that doesn't work give up and return // it any way. dwLength = GetUnicodeInstanceName (pInstance, lpszInstance); } else if (dwCharSize == sizeof(WCHAR)) { // then we tried to read it as a UNICODE string and that didn't work // so try it as an ASCII string (if that doesn't work give up and return // it any way. dwLength = GetAnsiInstanceName (pInstance, lpszInstance, dwCodePage); } } } void GetPerfComputerName( PPERFDATA pPerfData, LPTSTR lpszComputerName ) { lstrcpy(lpszComputerName, szComputerPrefix) ; if (pPerfData) { wcsncpy (&lpszComputerName[2], (LPWSTR)((PBYTE) pPerfData + pPerfData->SystemNameOffset), pPerfData->SystemNameLength/sizeof(WCHAR)) ; } else { lpszComputerName[0] = TEXT('\0') ; } } //==========================================================================// // Exported Functions // //==========================================================================// int CounterIndex ( PPERFCOUNTERDEF pCounterToFind, PPERFOBJECT pObject ) /* Effect: Return the index ("counter number") of pCounterToFind within pObject. If the counter doesnt belong to pObject, return -1. */ { PPERFCOUNTERDEF pCounter ; UINT iCounter ; for (iCounter = 0, pCounter = FirstCounter (pObject) ; iCounter < pObject->NumCounters ; iCounter++, pCounter = NextCounter (pCounter)) { if (pCounter->CounterNameTitleIndex == pCounterToFind->CounterNameTitleIndex) return (iCounter) ; } return (-1) ; } HKEY OpenSystemPerfData ( IN LPCTSTR lpszSystem ) { HKEY hKey = NULL; LONG lStatus; lStatus = ERROR_CANTOPEN; // default error if none is returned if (IsLocalComputer(lpszSystem) || PlayingBackLog()) { bCloseLocalMachine = TRUE ; SetLastError (ERROR_SUCCESS); return HKEY_PERFORMANCE_DATA; } else { // Must be a remote system try { lStatus = RegConnectRegistry ( (LPTSTR)lpszSystem, HKEY_PERFORMANCE_DATA, &hKey); }finally { if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); hKey = NULL; } } } return (hKey); } LPWSTR *AddNewName( HKEY hKeyNames, PCOUNTERTEXT pCounterInfo, LPWSTR CounterBuffer, LPWSTR HelpBuffer, DWORD dwLastId, DWORD dwCounterSize, DWORD dwHelpSize, LANGID LangIdUsed ) { LPWSTR *lpReturnValue; LPWSTR *lpCounterId; LPWSTR lpCounterNames; LPWSTR lpHelpText; DWORD dwArraySize; DWORD dwBufferSize; DWORD dwValueType; LONG lWin32Status = ERROR_SUCCESS; NTSTATUS Status; DWORD dwLastError; dwArraySize = (dwLastId + 1 ) * sizeof(LPWSTR); lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize); if (!lpReturnValue) goto ERROR_EXIT; // initialize pointers into buffer lpCounterId = lpReturnValue; lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize); lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize); // read counters into memory dwBufferSize = dwCounterSize; lWin32Status = RegQueryValueEx ( hKeyNames, CounterBuffer, RESERVED, &dwValueType, (LPVOID)lpCounterNames, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT; if (bExplainTextButtonHit) { dwBufferSize = dwHelpSize; lWin32Status = RegQueryValueEx ( hKeyNames, HelpBuffer, RESERVED, &dwValueType, (LPVOID)lpHelpText, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT; } // load counter array items Status = AddNamesToArray (lpCounterNames, dwLastId, lpCounterId); if (Status != ERROR_SUCCESS) goto ERROR_EXIT; if (bExplainTextButtonHit) { Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId); } if (Status != ERROR_SUCCESS) goto ERROR_EXIT; if (pCounterInfo) { pCounterInfo->dwLastId = dwLastId; pCounterInfo->dwLangId = LangIdUsed; pCounterInfo->dwHelpSize = dwHelpSize; pCounterInfo->dwCounterSize = dwCounterSize; } return lpReturnValue; ERROR_EXIT: if (lWin32Status != ERROR_SUCCESS) { dwLastError = GetLastError(); } if (lpReturnValue) { MemoryFree ((LPVOID)lpReturnValue); } return NULL; } LPWSTR *BuildNewNameTable( PPERFSYSTEM pSystem, LPWSTR lpszLangId, // unicode value of Language subkey PCOUNTERTEXT pCounterInfo, LANGID iLangId, // lang ID of the lpszLangId DWORD dwLastId ) /*++ BuildNewNameTable Arguments: lpszLangId The unicode id of the language to look up. (English is 0x409) Return Value: pointer to an allocated table. (the caller must free it when finished!) the table is an array of pointers to zero terminated strings. NULL is returned if an error occured. --*/ { LONG lWin32Status; DWORD dwValueType; DWORD dwLastError; DWORD dwBufferSize; DWORD dwCounterSize; DWORD dwHelpSize; HKEY hKeyNames; TCHAR CounterBuffer [MiscTextLen] ; TCHAR ExplainBuffer [MiscTextLen] ; TCHAR subLangId [ShortTextLen] ; LANGID LangIdUsed = iLangId; //initialize local variables hKeyNames = pSystem->sysDataKey; // check for null arguments and insert defaults if necessary if (!lpszLangId) { lpszLangId = DefaultLangId; LangIdUsed = iLanguage ; } // get size of counter names and add that to the arrays lstrcpy (CounterBuffer, CounterNameStr); lstrcat (CounterBuffer, lpszLangId); lstrcpy (ExplainBuffer, ExplainNameStr); lstrcat (ExplainBuffer, lpszLangId); dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, CounterBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) { // check for ACCESS_DENIED error first since if it's here // it will be returned on all subsequent calls, we might as well // bail out now. if (lWin32Status == ERROR_ACCESS_DENIED) { goto BNT_BAILOUT; } // try take out the country ID LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL); TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed); lstrcpy (CounterBuffer, CounterNameStr); lstrcat (CounterBuffer, subLangId); lstrcpy (ExplainBuffer, ExplainNameStr); lstrcat (ExplainBuffer, subLangId); dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, CounterBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); } if (lWin32Status != ERROR_SUCCESS) { // try the EnglishLangId if (!strsame(EnglishLangId, subLangId)) { lstrcpy (CounterBuffer, CounterNameStr); lstrcat (CounterBuffer, EnglishLangId); lstrcpy (ExplainBuffer, ExplainNameStr); lstrcat (ExplainBuffer, EnglishLangId); LangIdUsed = iEnglishLanguage ; dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, CounterBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); } } // Fail, too bad... if (lWin32Status != ERROR_SUCCESS) { goto BNT_BAILOUT; } dwCounterSize = dwBufferSize; // If ExplainText is needed, then // get size of help text and add that to the arrays if (bExplainTextButtonHit) { dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, ExplainBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT; dwHelpSize = dwBufferSize; } else { dwHelpSize = 0; } return (AddNewName( hKeyNames, pCounterInfo, CounterBuffer, ExplainBuffer, dwLastId, dwCounterSize, dwHelpSize, LangIdUsed)); BNT_BAILOUT: if (lWin32Status != ERROR_SUCCESS) { dwLastError = GetLastError(); // set the LastError value since a null pointer will // be returned which doesn't tell much to the caller SetLastError (lWin32Status); } return NULL; } LPWSTR * BuildOldNameTable( HKEY hKeyRegistry, // handle to registry db with counter names LPWSTR lpszLangId, // unicode value of Language subkey PCOUNTERTEXT pCounterInfo, LANGID iLangId, // lang ID of the lpszLangId DWORD dwLastId ) /*++ BuildOldNameTable Arguments: hKeyRegistry Handle to an open registry (this can be local or remote.) and is the value returned by RegConnectRegistry or a default key. lpszLangId The unicode id of the language to look up. (English is 0x409) Return Value: pointer to an allocated table. (the caller must free it when finished!) the table is an array of pointers to zero terminated strings. NULL is returned if an error occured. --*/ { LPWSTR *lpReturnValue = NULL; LONG lWin32Status; DWORD dwValueType; DWORD dwLastError; DWORD dwBufferSize; DWORD dwCounterSize; DWORD dwHelpSize; HKEY hKeyNames; TCHAR tempBuffer [MiscTextLen] ; TCHAR subLangId [ShortTextLen] ; LPWSTR lpValueNameString; LANGID LangIdUsed = iLangId; TCHAR Slash[2]; //initialize local variables hKeyNames = NULL; Slash[0] = L'\\'; Slash[1] = L'\0'; // check for null arguments and insert defaults if necessary if (!lpszLangId) { lpszLangId = DefaultLangId; LangIdUsed = iLanguage ; } // get size of string buffer lpValueNameString = tempBuffer ; lstrcpy (lpValueNameString, NamesKey); lstrcat (lpValueNameString, Slash); lstrcat (lpValueNameString, lpszLangId); lWin32Status = RegOpenKeyEx ( hKeyRegistry, lpValueNameString, RESERVED, KEY_READ, &hKeyNames); if (lWin32Status != ERROR_SUCCESS) { // check for ACCESS_DENIED error first since if it's here // it will be returned on all subsequent calls, we might as well // bail out now. if (lWin32Status == ERROR_ACCESS_DENIED) { goto BNT_BAILOUT; } // try take out the country ID LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL); TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed); lstrcpy (lpValueNameString, NamesKey); lstrcat (lpValueNameString, Slash); lstrcat (lpValueNameString, subLangId); lWin32Status = RegOpenKeyEx ( hKeyRegistry, lpValueNameString, RESERVED, KEY_READ, &hKeyNames); } if (lWin32Status != ERROR_SUCCESS) { // try the EnglishLangId if (!strsame(EnglishLangId, subLangId)) { lstrcpy (lpValueNameString, NamesKey); lstrcat (lpValueNameString, Slash); lstrcat (lpValueNameString, EnglishLangId); LangIdUsed = iEnglishLanguage ; lWin32Status = RegOpenKeyEx ( hKeyRegistry, lpValueNameString, RESERVED, KEY_READ, &hKeyNames); } } // Fail, too bad... if (lWin32Status != ERROR_SUCCESS) { goto BNT_BAILOUT; } // get size of counter names and add that to the arrays dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, Counters, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT; dwCounterSize = dwBufferSize; // If ExplainText is needed, then // get size of help text and add that to the arrays if (bExplainTextButtonHit) { dwBufferSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, Help, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT; dwHelpSize = dwBufferSize; } else { dwHelpSize = 0; } lpReturnValue = AddNewName( hKeyNames, pCounterInfo, Counters, Help, dwLastId, dwCounterSize, dwHelpSize, LangIdUsed); RegCloseKey (hKeyNames); return lpReturnValue; BNT_BAILOUT: if (lWin32Status != ERROR_SUCCESS) { dwLastError = GetLastError(); // set the LastError value since a null pointer will // be returned which doesn't tell much to the caller SetLastError (lWin32Status); } if (lpReturnValue) { MemoryFree ((LPVOID)lpReturnValue); } if (hKeyNames) RegCloseKey (hKeyNames); return NULL; } LPWSTR * BuildNameTable( PPERFSYSTEM pSysInfo, HKEY hKeyRegistry, // handle to registry db with counter names LPWSTR lpszLangId, // unicode value of Language subkey PCOUNTERTEXT pCounterInfo, LANGID iLangId // lang ID of the lpszLangId ) /*++ BuildNameTable Arguments: hKeyRegistry Handle to an open registry (this can be local or remote.) and is the value returned by RegConnectRegistry or a default key. lpszLangId The unicode id of the language to look up. (English is 0x409) Return Value: pointer to an allocated table. (the caller must free it when finished!) the table is an array of pointers to zero terminated strings. NULL is returned if an error occured. --*/ { LPWSTR *lpReturnValue; LONG lWin32Status; DWORD dwLastError; DWORD dwValueType; DWORD dwLastHelp; DWORD dwLastCounter; DWORD dwLastId; DWORD dwBufferSize; HKEY hKeyValue; DWORD dwSystemVersion; //initialize local variables lpReturnValue = NULL; hKeyValue = NULL; // open registry to get number of items for computing array size lWin32Status = RegOpenKeyEx ( hKeyRegistry, NamesKey, RESERVED, KEY_READ, &hKeyValue); if (lWin32Status != ERROR_SUCCESS) { goto BNT_BAILOUT; } // get number of items dwBufferSize = sizeof (dwLastHelp); lWin32Status = RegQueryValueEx ( hKeyValue, LastHelp, RESERVED, &dwValueType, (LPBYTE)&dwLastHelp, &dwBufferSize); if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) { goto BNT_BAILOUT; } dwBufferSize = sizeof (dwLastCounter); lWin32Status = RegQueryValueEx ( hKeyValue, LastCounter, RESERVED, &dwValueType, (LPBYTE)&dwLastCounter, &dwBufferSize); if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) { goto BNT_BAILOUT; } if (dwLastCounter >= dwLastHelp) { dwLastId = dwLastCounter; } else { dwLastId = dwLastHelp; } // get system version dwBufferSize = sizeof (dwSystemVersion); lWin32Status = RegQueryValueEx ( hKeyValue, SysVersion, RESERVED, &dwValueType, (LPBYTE)&dwSystemVersion, &dwBufferSize); if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) { pSysInfo->SysVersion = 0x10000; } else { pSysInfo->SysVersion = dwSystemVersion; } if (pSysInfo->SysVersion <= 0x10000) { lpReturnValue = BuildOldNameTable ( hKeyRegistry, lpszLangId, pCounterInfo, iLangId, dwLastId) ; } else { lpReturnValue = BuildNewNameTable ( pSysInfo, lpszLangId, pCounterInfo, iLangId, dwLastId) ; } RegCloseKey (hKeyValue); return lpReturnValue; BNT_BAILOUT: if (lWin32Status != ERROR_SUCCESS) { dwLastError = GetLastError(); // set the LastError value since a null pointer will // be returned which doesn't tell much to the caller SetLastError (lWin32Status); } if (hKeyValue) RegCloseKey (hKeyValue); return NULL; } DWORD GetSystemKey ( PPERFSYSTEM pSysInfo, HKEY *phKeyMachine ) { DWORD dwStatus; // connect to system registry if (IsLocalComputer(pSysInfo->sysName) || (PlayingBackLog() && PlaybackLog.pBaseCounterNames)) { *phKeyMachine = HKEY_LOCAL_MACHINE; } else { try { dwStatus = RegConnectRegistry ( pSysInfo->sysName, HKEY_LOCAL_MACHINE, phKeyMachine); if (dwStatus != ERROR_SUCCESS) { if (PlayingBackLog()) { // If remote machine is not on and we are // playing back log, then, use the counters from // local machine. *phKeyMachine = HKEY_LOCAL_MACHINE; } else { return dwStatus; } } }finally { ; // nothing } } return 0; } DWORD GetSystemNames( PPERFSYSTEM pSysInfo ) { HKEY hKeyMachine = 0; DWORD dwStatus; if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) { return dwStatus; } // if here, then hKeyMachine is an open key to the system's // HKEY_LOCAL_MACHINE registry database // only one language is supported by this approach. // multiple language support would: // 1. enumerate language keys // and for each key: // 2. allocate memory for structures // 3. call BuildNameTable for each lang key. pSysInfo->CounterInfo.pNextTable = NULL; pSysInfo->CounterInfo.dwLangId = iLanguage ; // default Lang ID if (PlayingBackLog() && PlaybackLog.pBaseCounterNames) { pSysInfo->CounterInfo.TextString = LogBuildNameTable (pSysInfo) ; } else { pSysInfo->CounterInfo.TextString = BuildNameTable ( pSysInfo, hKeyMachine, NULL, // use default &pSysInfo->CounterInfo, 0); } if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) { RegCloseKey (hKeyMachine) ; } if (pSysInfo->CounterInfo.TextString == NULL) { return GetLastError(); } else { return ERROR_SUCCESS; } } BOOL GetHelpText( PPERFSYSTEM pSysInfo ) { LPWSTR *lpCounterId; LPWSTR lpHelpText; LONG lWin32Status; DWORD dwValueType; DWORD dwArraySize; DWORD dwBufferSize; DWORD dwCounterSize; DWORD dwHelpSize; NTSTATUS Status; DWORD dwLastId; TCHAR Slash[2]; HKEY hKeyNames; TCHAR SysLangId [ShortTextLen] ; TCHAR ValueNameString [MiscTextLen] ; HKEY hKeyMachine = 0; DWORD dwStatus; SetHourglassCursor() ; //initialize local variables lpHelpText = NULL; hKeyNames = hKeyMachine = NULL; Slash[0] = L'\\'; Slash[1] = L'\0'; dwBufferSize = 0; TSPRINTF (SysLangId, TEXT("%03x"), pSysInfo->CounterInfo.dwLangId) ; if (pSysInfo->SysVersion <= 0x10000) { // old version, get help from registry if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) { goto ERROR_EXIT; } lstrcpy (ValueNameString, NamesKey); lstrcat (ValueNameString, Slash); lstrcat (ValueNameString, SysLangId); lWin32Status = RegOpenKeyEx ( hKeyMachine, ValueNameString, RESERVED, KEY_READ, &hKeyNames); if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT; } else { // new system version, get it from the HKEY_PERFORMANCE hKeyNames = pSysInfo->sysDataKey; lstrcpy (ValueNameString, ExplainNameStr); lstrcat (ValueNameString, SysLangId); } dwHelpSize = 0; lWin32Status = RegQueryValueEx ( hKeyNames, pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString, RESERVED, &dwValueType, NULL, &dwHelpSize); if (lWin32Status != ERROR_SUCCESS || dwHelpSize == 0) goto ERROR_EXIT; dwLastId = pSysInfo->CounterInfo.dwLastId; dwArraySize = (dwLastId + 1) * sizeof (LPWSTR); dwCounterSize = pSysInfo->CounterInfo.dwCounterSize; // allocate another memory to get the help text lpHelpText = MemoryAllocate (dwHelpSize); if (!lpHelpText) goto ERROR_EXIT; dwBufferSize = dwHelpSize; lWin32Status = RegQueryValueEx ( hKeyNames, pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString, RESERVED, &dwValueType, (LPVOID)lpHelpText, &dwBufferSize); if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT; // setup the help text pointers lpCounterId = pSysInfo->CounterInfo.TextString; Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId) ; if (Status != ERROR_SUCCESS) goto ERROR_EXIT; pSysInfo->CounterInfo.dwHelpSize = dwHelpSize; if (pSysInfo->SysVersion <= 0x010000) RegCloseKey (hKeyNames); if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) { RegCloseKey (hKeyMachine) ; } pSysInfo->CounterInfo.HelpTextString = lpHelpText; SetArrowCursor() ; return TRUE; ERROR_EXIT: SetArrowCursor() ; if (lpHelpText) { MemoryFree ((LPVOID)lpHelpText); } if (hKeyNames) { RegCloseKey (hKeyNames); } if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) { RegCloseKey (hKeyMachine) ; } return FALSE; } // // QueryPerformanceName - Get a title, given an index // // Inputs: // // pSysInfo - Pointer to sysinfo struct for the // system in question // // dwTitleIndex - Index of Title entry // // LangID - language in which title should be displayed // // cbTitle - # of char in the lpTitle buffer // // lpTitle - pointer to a buffer to receive the // Title // // Help - TRUE is help is desired, else counter or // object is assumed DWORD QueryPerformanceName( PPERFSYSTEM pSysInfo, DWORD dwTitleIndex, LANGID LangID, DWORD cbTitle, LPTSTR lpTitle, BOOL Help ) { LPWSTR lpTitleFound; NTSTATUS Status; BOOL bGetTextSuccess = TRUE ; DBG_UNREFERENCED_PARAMETER(LangID); if (Help && pSysInfo->CounterInfo.dwHelpSize == 0) { // we have not get the help text yet, go get it bGetTextSuccess = GetHelpText (pSysInfo); } if (!bGetTextSuccess) { Status = ERROR_INVALID_NAME; goto ErrorExit; } if ((dwTitleIndex > 0) && (dwTitleIndex <= pSysInfo->CounterInfo.dwLastId)) { // then title should be found in the array lpTitleFound = pSysInfo->CounterInfo.TextString[dwTitleIndex]; if (!lpTitleFound) { // no entry for this index Status = ERROR_INVALID_NAME; } else if ((DWORD)lstrlen(lpTitleFound) < cbTitle) { lstrcpy (lpTitle, lpTitleFound); return (ERROR_SUCCESS); } else { Status = ERROR_MORE_DATA; } } else { Status = ERROR_INVALID_NAME; } ErrorExit: // if here, then an error occured, so return a blank if ((DWORD)lstrlen (NULL_NAME) < cbTitle) { lstrcpy (lpTitle, NULL_NAME); } return Status; // title not returned } LONG GetSystemPerfData ( IN HKEY hKeySystem, IN LPTSTR lpszValue, OUT PPERFDATA pPerfData, OUT PDWORD pdwPerfDataLen ) { LONG lError ; DWORD Type ; // have to pass in a Type to RegQueryValueEx(W) or else it // will crash lError = RegQueryValueEx (hKeySystem, lpszValue, NULL, &Type, (LPSTR) pPerfData, pdwPerfDataLen) ; return (lError) ; } BOOL CloseSystemPerfData ( HKEY hKeySystem ) { return (TRUE) ; } int CBLoadObjects ( HWND hWndCB, PPERFDATA pPerfData, PPERFSYSTEM pSysInfo, DWORD dwDetailLevel, LPTSTR lpszDefaultObject, BOOL bIncludeAll ) /* Effect: Load into the combo box CB one item for each Object in pPerfData. For each item, look up the object's name in the registry strings associated with pSysInfo, and attach the object to the data field of the CB item. Dont add those objects that are more detailed than dwDetailLevel. Set the current selected CB item to the object named lpszDefaultObject, or to the default object specified in pPerfData if lpszDefaultObject is NULL. */ { UINT i ; INT_PTR iIndex ; PPERFOBJECT pObject ; TCHAR szObject [PerfObjectLen + 1] ; TCHAR szDefaultObject [PerfObjectLen + 1] ; CBReset (hWndCB) ; strclr (szDefaultObject) ; pObject = FirstObject (pPerfData) ; for (i = 0, pObject = FirstObject (pPerfData) ; i < pPerfData->NumObjectTypes ; i++, pObject = NextObject (pObject)) { // for if (pObject->DetailLevel <= dwDetailLevel) { // if strclr (szObject) ; QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex, 0, PerfObjectLen, szObject, FALSE) ; // if szObject not empty, add it to the Combo-box if (!strsame(szObject, NULL_NAME)) { iIndex = CBAdd (hWndCB, szObject) ; CBSetData (hWndCB, iIndex, (DWORD_PTR) pObject) ; if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject) lstrcpy (szDefaultObject, szObject) ; } } } if (bIncludeAll) { StringLoad (IDS_ALLOBJECTS, szObject) ; CBInsert (hWndCB, 0, szObject) ; // assume "ALL" is default unless overridden lstrcpy (szDefaultObject, szObject) ; } if (lpszDefaultObject) lstrcpy (szDefaultObject, lpszDefaultObject) ; iIndex = CBFind (hWndCB, szDefaultObject) ; CBSetSelection (hWndCB, (iIndex != CB_ERR) ? iIndex : 0) ; return (i) ; } int LBLoadObjects ( HWND hWndLB, PPERFDATA pPerfData, PPERFSYSTEM pSysInfo, DWORD dwDetailLevel, LPTSTR lpszDefaultObject, BOOL bIncludeAll ) /* Effect: Load into the list box LB one item for each Object in pPerfData. For each item, look up the object's name in the registry strings associated with pSysInfo, and attach the object to the data field of the LB item. Dont add those objects that are more detailed than dwDetailLevel. Set the current selected LB item to the object named lpszDefaultObject, or to the default object specified in pPerfData if lpszDefaultObject is NULL. */ { UINT i ; INT_PTR iIndex = 0; PPERFOBJECT pObject ; TCHAR szObject [PerfObjectLen + 1] ; TCHAR szDefaultObject [PerfObjectLen + 1] ; LBReset (hWndLB) ; strclr (szDefaultObject) ; pObject = FirstObject (pPerfData) ; for (i = 0, pObject = FirstObject (pPerfData) ; i < pPerfData->NumObjectTypes ; i++, pObject = NextObject (pObject)) { if (pObject->DetailLevel <= dwDetailLevel) { strclr (szObject) ; QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex, 0, PerfObjectLen, szObject, FALSE) ; // if szObject is not empty, add it to the listbox if (!strsame(szObject, NULL_NAME)) { iIndex = LBAdd (hWndLB, szObject) ; LBSetData (hWndLB, iIndex, (DWORD_PTR) pObject) ; if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject) lstrcpy (szDefaultObject, szObject) ; } } } if (bIncludeAll) { StringLoad (IDS_ALLOBJECTS, szObject) ; LBInsert (hWndLB, 0, szObject) ; LBSetData (hWndLB, iIndex, 0) ; // assume "ALL" is default unless overridden lstrcpy (szDefaultObject, szObject) ; } if (lpszDefaultObject) lstrcpy (szDefaultObject, lpszDefaultObject) ; iIndex = LBFind (hWndLB, szDefaultObject) ; LBSetSelection (hWndLB, (iIndex != LB_ERR) ? iIndex : 0) ; return (i) ; } /***************************************************************************\ * GetObjectDef() * * Entry: pointer to data block and the number of the object type * Exit: returns a pointer to the specified object type definition * \***************************************************************************/ PPERFOBJECT GetObjectDef( PPERFDATA pDataBlock, DWORD NumObjectType ) { DWORD NumTypeDef; PPERFOBJECT pObjectDef; pObjectDef = FirstObject(pDataBlock); for ( NumTypeDef = 0; NumTypeDef < pDataBlock->NumObjectTypes; NumTypeDef++ ) { if ( NumTypeDef == NumObjectType ) { return pObjectDef; } pObjectDef = NextObject(pObjectDef); } return 0; } /***************************************************************************\ * GetObjectDefByTitleIndex() * * Entry: pointer to data block and the title index of the object type * Exit: returns a pointer to the specified object type definition * \***************************************************************************/ PPERFOBJECT GetObjectDefByTitleIndex( PPERFDATA pDataBlock, DWORD ObjectTypeTitleIndex ) { DWORD NumTypeDef; PPERFOBJECT pObjectDef; pObjectDef = FirstObject(pDataBlock); for ( NumTypeDef = 0; NumTypeDef < pDataBlock->NumObjectTypes; NumTypeDef++ ) { if ( pObjectDef->ObjectNameTitleIndex == ObjectTypeTitleIndex ) { return pObjectDef; } pObjectDef = NextObject(pObjectDef); } return 0; } /***************************************************************************\ * GetObjectDefByName() * * Entry: pointer to data block and the name of the object type * Exit: returns a pointer to the specified object type definition * \***************************************************************************/ PPERFOBJECT GetObjectDefByName( PPERFSYSTEM pSystem, PPERFDATA pDataBlock, LPTSTR pObjectName ) { DWORD NumTypeDef; TCHAR szObjectName [PerfObjectLen + 1] ; PPERFOBJECT pObjectDef; pObjectDef = FirstObject(pDataBlock); for ( NumTypeDef = 0; NumTypeDef < pDataBlock->NumObjectTypes; NumTypeDef++ ) { ObjectName (pSystem, pObjectDef, szObjectName, PerfObjectLen) ; if (strsame (szObjectName, pObjectName) ) { return pObjectDef; } pObjectDef = NextObject(pObjectDef); } return 0; } /***************************************************************************\ * GetObjectIdByName() * * Entry: pointer to data block and the name of the object type * Exit: returns the Object title index for the specified Object Name * \***************************************************************************/ DWORD GetObjectIdByName( PPERFSYSTEM pSystem, PPERFDATA pDataBlock, LPTSTR pObjectName ) { DWORD NumTypeDef; TCHAR szObjectName [PerfObjectLen + 1] ; PPERFOBJECT pObjectDef; pObjectDef = FirstObject(pDataBlock); for ( NumTypeDef = 0; NumTypeDef < pDataBlock->NumObjectTypes; NumTypeDef++ ) { ObjectName (pSystem, pObjectDef, szObjectName, PerfObjectLen) ; if (strsame (szObjectName, pObjectName) ) { return pObjectDef->ObjectNameTitleIndex; } pObjectDef = NextObject(pObjectDef); } return 0; } /***************************************************************************\ * GetCounterDef() * * Entry: pointer to object type definition the number of the Counter * definition * Exit: returns a pointer to the specified Counter definition * \***************************************************************************/ PPERFCOUNTERDEF GetCounterDef( PPERFOBJECT pObjectDef, DWORD NumCounter ) { DWORD NumCtrDef; PPERFCOUNTERDEF pCounterDef; pCounterDef = FirstCounter(pObjectDef); for ( NumCtrDef = 0; NumCtrDef < pObjectDef->NumCounters; NumCtrDef++ ) { if ( NumCtrDef == NumCounter ) { return pCounterDef; } pCounterDef = NextCounter(pCounterDef); } return 0; } /***************************************************************************\ * GetCounterNumByTitleIndex() * * Entry: pointer to object type definition and the title index of * the name of the Counter definition * Exit: returns the number of the specified Counter definition * \***************************************************************************/ LONG GetCounterNumByTitleIndex( PPERFOBJECT pObjectDef, DWORD CounterTitleIndex ) { DWORD NumCtrDef; PPERFCOUNTERDEF pCounterDef; pCounterDef = FirstCounter(pObjectDef); for ( NumCtrDef = 0; NumCtrDef < pObjectDef->NumCounters; NumCtrDef++ ) { if ( pCounterDef->CounterNameTitleIndex == CounterTitleIndex ) { return NumCtrDef; } pCounterDef = NextCounter(pCounterDef); } return 0; } /***************************************************************************\ * GetCounterData() * * Entry: pointer to object definition and number of counter, must be * an object with no instances * Exit: returns a pointer to the data * \***************************************************************************/ PVOID GetCounterData( PPERFOBJECT pObjectDef, PPERFCOUNTERDEF pCounterDef ) { PERF_COUNTER_BLOCK *pCtrBlock; pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pObjectDef + pObjectDef->DefinitionLength); return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset); } /***************************************************************************\ * GetInstanceCounterData() * * Entry: pointer to object definition and number of counter, and a pointer * to the instance for which the data is to be retrieved * Exit: returns a pointer to the data * \***************************************************************************/ PVOID GetInstanceCounterData( PPERFOBJECT pObjectDef, PPERFINSTANCEDEF pInstanceDef, PPERFCOUNTERDEF pCounterDef ) { PERF_COUNTER_BLOCK *pCtrBlock; pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pInstanceDef + pInstanceDef->ByteLength); return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset); } /***************************************************************************\ * GetNextInstance() * * Entry: pointer to instance definition * Exit: returns a pointer to the next instance definition. If none, * points to byte past this instance * \***************************************************************************/ PPERFINSTANCEDEF GetNextInstance( PPERFINSTANCEDEF pInstDef ) { PERF_COUNTER_BLOCK *pCtrBlock; pCtrBlock = (PERF_COUNTER_BLOCK *) ((PCHAR) pInstDef + pInstDef->ByteLength); return (PPERFINSTANCEDEF ) ((PCHAR) pCtrBlock + pCtrBlock->ByteLength); } /***************************************************************************\ * GetInstance() * * Entry: pointer to object type definition, the name of the instance, * the name of the parent object type, and the parent instance index. * The name of the parent object type is NULL if no parent. * Exit: returns a pointer to the specified instance definition * \***************************************************************************/ PPERFINSTANCEDEF GetInstance( PPERFOBJECT pObjectDef, LONG InstanceNumber ) { PPERFINSTANCEDEF pInstanceDef; LONG NumInstance; if (!pObjectDef) { return 0; } pInstanceDef = FirstInstance(pObjectDef); for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { if ( InstanceNumber == NumInstance ) { return pInstanceDef; } pInstanceDef = GetNextInstance(pInstanceDef); } return 0; } /***************************************************************************\ * GetInstanceByUniqueID() * * Entry: pointer to object type definition, and * the unique ID of the instance. * Exit: returns a pointer to the specified instance definition * \***************************************************************************/ PPERFINSTANCEDEF GetInstanceByUniqueID( PPERFOBJECT pObjectDef, LONG UniqueID, DWORD dwIndex ) { PPERFINSTANCEDEF pInstanceDef; DWORD dwLocalIndex; LONG NumInstance; pInstanceDef = FirstInstance(pObjectDef); dwLocalIndex = dwIndex; for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { if ( pInstanceDef->UniqueID == UniqueID ) { if (dwLocalIndex == 0) { return pInstanceDef; } else { --dwLocalIndex; } } pInstanceDef = GetNextInstance(pInstanceDef); } return 0; } /***************************************************************************\ * GetInstanceByNameUsingParentTitleIndex() * * Entry: pointer to object type definition, the name of the instance, * and the name of the parent instance. * The name of the parent instance is NULL if no parent. * Exit: returns a pointer to the specified instance definition * \***************************************************************************/ PPERFINSTANCEDEF GetInstanceByNameUsingParentTitleIndex( PPERFDATA pDataBlock, PPERFOBJECT pObjectDef, LPTSTR pInstanceName, LPTSTR pParentName, DWORD dwIndex ) { BOOL fHaveParent; PPERFOBJECT pParentObj; PPERFINSTANCEDEF pParentInst, pInstanceDef; LONG NumInstance; TCHAR InstanceName[256]; DWORD dwLocalIndex; fHaveParent = FALSE; pInstanceDef = FirstInstance(pObjectDef); dwLocalIndex = dwIndex; memset(InstanceName, 0, sizeof(TCHAR) * 256); for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { GetInstanceNameStr(pInstanceDef, InstanceName, pObjectDef->CodePage); if ( lstrcmpi(InstanceName, pInstanceName) == 0 ) { // Instance name matches if ( pParentName == NULL ) { // No parent, we're done if this is the right "copy" if (dwLocalIndex == 0) { return pInstanceDef; } else { --dwLocalIndex; } } else { // Must match parent as well pParentObj = GetObjectDefByTitleIndex( pDataBlock, pInstanceDef->ParentObjectTitleIndex); if (!pParentObj) { // can't locate the parent, forget it break ; } // Object type of parent found; now find parent // instance pParentInst = GetInstance(pParentObj, pInstanceDef->ParentObjectInstance); if (!pParentInst) { // can't locate the parent instance, forget it break ; } GetInstanceNameStr(pParentInst,InstanceName, pParentObj->CodePage); if ( lstrcmpi(InstanceName, pParentName) == 0 ) { // Parent Instance Name matches that passed in if (dwLocalIndex == 0) { return pInstanceDef; } else { --dwLocalIndex; } } } } pInstanceDef = GetNextInstance(pInstanceDef); } return 0; } /***************************************************************************\ * GetInstanceByName() * * Entry: pointer to object type definition, the name of the instance, * and the name of the parent instance. * The name of the parent instance is NULL if no parent. * Exit: returns a pointer to the specified instance definition * \***************************************************************************/ PPERFINSTANCEDEF GetInstanceByName( PPERFDATA pDataBlock, PPERFOBJECT pObjectDef, LPTSTR pInstanceName, LPTSTR pParentName, DWORD dwIndex ) { BOOL fHaveParent; PPERFOBJECT pParentObj; PPERFINSTANCEDEF pParentInst, pInstanceDef; LONG NumInstance; TCHAR InstanceName[256]; DWORD dwLocalIndex; fHaveParent = FALSE; pInstanceDef = FirstInstance(pObjectDef); dwLocalIndex = dwIndex; memset(InstanceName, 0, sizeof(TCHAR) * 256); for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { GetInstanceNameStr(pInstanceDef,InstanceName, pObjectDef->CodePage); if ( lstrcmpi(InstanceName, pInstanceName) == 0 ) { // Instance name matches if ( !pInstanceDef->ParentObjectTitleIndex ) { // No parent, we're done if (dwLocalIndex == 0) { return pInstanceDef; } else { --dwLocalIndex; } } else { // Must match parent as well pParentObj = GetObjectDefByTitleIndex( pDataBlock, pInstanceDef->ParentObjectTitleIndex); // Object type of parent found; now find parent // instance if (pParentObj == NULL) continue; pParentInst = GetInstance(pParentObj, pInstanceDef->ParentObjectInstance); GetInstanceNameStr(pParentInst,InstanceName, pParentObj->CodePage); if ( lstrcmpi(InstanceName, pParentName) == 0 ) { // Parent Instance Name matches that passed in if (dwLocalIndex == 0) { return pInstanceDef; } else { --dwLocalIndex; } } } } pInstanceDef = GetNextInstance(pInstanceDef); } return 0; } // GetInstanceByName BOOL FailedLineData ( PPERFDATA pPerfData, PLINE pLine ) /* This routine handles the case where there is no data for a system. */ { LARGE_INTEGER liDummy ; // System no longer exists. liDummy.LowPart = liDummy.HighPart = 0; if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV) { // Timer inverse with Performance Counter as timer pLine->lnaOldCounterValue[0] = pLine->lnOldTime ; pLine->lnaCounterValue[0] = pLine->lnNewTime ; } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV || pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV) { // Timer inverse with System Time as timer pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ; pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ; } else { // Normal timer pLine->lnaOldCounterValue[0] = pLine->lnaCounterValue[0] = pLine->lnaOldCounterValue[1] = pLine->lnaCounterValue[1] = liDummy ; } return TRUE ; } BOOL UpdateLineData ( PPERFDATA pPerfData, PLINE pLine, PPERFSYSTEM pSystem ) /* Assert: pPerfData holds the performance data for the same system as pLine. */ { PPERFOBJECT pObject ; PPERFINSTANCEDEF pInstanceDef ; PPERFCOUNTERDEF pCounterDef ; PPERFCOUNTERDEF pCounterDef2 ; PDWORD pCounterValue ; PDWORD pCounterValue2 = NULL; UINT iCounterIndex ; LARGE_INTEGER liDummy[2] ; // Use Object time units if available, otherwise use system // performance timer pLine->lnOldTime = pLine->lnNewTime; pLine->lnOldTime100Ns = pLine->lnNewTime100Ns; pLine->lnNewTime100Ns = pPerfData->PerfTime100nSec; pLine->lnPerfFreq = pPerfData->PerfFreq ; if ((pLine->lnObject.TotalByteLength == 0) && !(PlayingBackLog())) { // this is the case when openning a setting file and the remote // system is not up at that time. We have all the names but no // pObject, pCounter, etc. So, we have to re-built the linedata. PPERFOBJECT pObject ; PPERFCOUNTERDEF pCounter ; PPERFINSTANCEDEF pInstance ; pObject = LineFindObject (pSystem, pPerfData, pLine) ; if (!pObject) { //Something wrong, this object is still not there... return FALSE ; } pCounter = LineFindCounter (pSystem, pObject, pPerfData, pLine) ; if (!pCounter) { return FALSE ; } if (pObject && pLine->lnObject.NumInstances > 0 && pLine->lnInstanceName == NULL) { return FALSE ; } pInstance = LineFindInstance (pPerfData, pObject, pLine) ; if (!pInstance) { if (pLine->lnParentObjName) { MemoryFree (pLine->lnParentObjName) ; pLine->lnParentObjName = NULL ; } } pLine->lnCounterType = pCounter->CounterType; pLine->lnCounterLength = pCounter->CounterSize; if (pSystem->lpszValue && strsame (pSystem->lpszValue, L"Global")) { DWORD dwBufferSize = MemorySize (pSystem->lpszValue) ; memset (pSystem->lpszValue, 0, dwBufferSize) ; } AppendObjectToValueList ( pLine->lnObject.ObjectNameTitleIndex, pSystem->lpszValue); } pObject = GetObjectDefByTitleIndex( pPerfData, pLine->lnObject.ObjectNameTitleIndex); if (!pObject) { // Object Type no longer exists. This is possible if we are // looking at a log file which has not always collected all // the same data, such as appending measurements of different // object types. pCounterValue = pCounterValue2 = (PDWORD) liDummy; liDummy[0].QuadPart = 0; pLine->lnNewTime = pPerfData->PerfTime; if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV) { // Timer inverse with Performance Counter as timer pLine->lnaOldCounterValue[0] = pLine->lnOldTime ; pLine->lnaCounterValue[0] = pLine->lnNewTime ; } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV || pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV) { // Timer inverse with System Time as timer pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ; pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ; } else { // Normal timer or counter pLine->lnaOldCounterValue[0] = pLine->lnaCounterValue[0] = pLine->lnaOldCounterValue[1] = pLine->lnaCounterValue[1] = liDummy[0] ; } return TRUE ; } else { pCounterDef = &pLine->lnCounterDef ; // if (pObject->PerfFreq.QuadPart > 0) { if (pCounterDef->CounterType & PERF_OBJECT_TIMER) { pLine->lnNewTime = pObject->PerfTime; } else { pLine->lnNewTime = pPerfData->PerfTime; } iCounterIndex = CounterIndex (pCounterDef, pObject) ; // Get second counter, only if we are not at // the end of the counters; some computations // require a second counter if (iCounterIndex < pObject->NumCounters-1 && iCounterIndex != -1) { pCounterDef2 = GetCounterDef(pObject, iCounterIndex+1); } else { pCounterDef2 = NULL; } if (pObject->NumInstances > 0) { if ( pLine->lnUniqueID != PERF_NO_UNIQUE_ID ) { pInstanceDef = GetInstanceByUniqueID(pObject, pLine->lnUniqueID, pLine->dwInstanceIndex); } else { pInstanceDef = GetInstanceByNameUsingParentTitleIndex( pPerfData, pObject, pLine->lnInstanceName, pLine->lnPINName, pLine->dwInstanceIndex); } if (pInstanceDef) { pLine->lnInstanceDef = *pInstanceDef; pCounterValue = GetInstanceCounterData(pObject, pInstanceDef, pCounterDef); if ( pCounterDef2 ) { pCounterValue2 = GetInstanceCounterData(pObject, pInstanceDef, pCounterDef2); } } else { pCounterValue = pCounterValue2 = (PDWORD) liDummy; liDummy[0].QuadPart = 0; liDummy[1].QuadPart = 0; } // Got everything... } // instances exist, look at them for counter blocks else { pCounterValue = GetCounterData(pObject, pCounterDef); if (pCounterDef2) { pCounterValue2 = GetCounterData(pObject, pCounterDef2); } } // counter def search when no instances } pLine->lnaOldCounterValue[0] = pLine->lnaCounterValue[0] ; if (pLine->lnCounterLength <= 4) { // HighPart was initialize to 0 pLine->lnaCounterValue[0].HighPart = 0; pLine->lnaCounterValue[0].LowPart = *pCounterValue; } else { pLine->lnaCounterValue[0] = *(LARGE_INTEGER UNALIGNED *) pCounterValue; } // Get second counter, only if we are not at // the end of the counters; some computations // require a second counter if ( pCounterDef2 ) { pLine->lnaOldCounterValue[1] = pLine->lnaCounterValue[1] ; if (pCounterDef2->CounterSize <= 4) { // HighPart was initialize to 0 pLine->lnaCounterValue[1].HighPart = 0; pLine->lnaCounterValue[1].LowPart = *pCounterValue2; } else pLine->lnaCounterValue[1] = *((LARGE_INTEGER UNALIGNED *) pCounterValue2); } return (TRUE) ; } // UpdateLineData BOOL UpdateSystemData ( PPERFSYSTEM pSystem, PPERFDATA *ppPerfData ) { #define PERF_SYSTEM_TIMEOUT (60L * 1000L) long lError ; DWORD Status ; DWORD Size; BOOL TimeToCheck = FALSE ; LONGLONG llLastTimeStamp; if (!ppPerfData) return (FALSE) ; while (TRUE) { if (pSystem->FailureTime) { DWORD CurrentTickCount = GetTickCount() ; if (CurrentTickCount < pSystem->FailureTime) { // wrap-around case if (CurrentTickCount >= PERF_SYSTEM_TIMEOUT) TimeToCheck = TRUE ; else if ( ~pSystem->FailureTime >= PERF_SYSTEM_TIMEOUT) TimeToCheck = TRUE ; else if (CurrentTickCount + (~pSystem->FailureTime) >= PERF_SYSTEM_TIMEOUT) TimeToCheck = TRUE ; } else { if (CurrentTickCount - pSystem->FailureTime >= PERF_SYSTEM_TIMEOUT) TimeToCheck = TRUE ; } if (TimeToCheck) { // free any memory hanging off this system SystemFree (pSystem, FALSE) ; // get the registry info pSystem->sysDataKey = OpenSystemPerfData(pSystem->sysName) ; Status = !ERROR_SUCCESS ; if (pSystem->sysDataKey) { Status = GetSystemNames(pSystem); } if (Status != ERROR_SUCCESS) { // something wrong in getting the registry info, // remote system must be still down (??) pSystem->FailureTime = GetTickCount(); // Free any memory that may have created SystemFree (pSystem, FALSE) ; return (FALSE) ; } // time to check again pSystem->FailureTime = 0 ; } else { // not time to check again return (FALSE) ; } } if (pSystem->FailureTime == 0 ) { Size = MemorySize ((LPMEMORY)*ppPerfData); // save the last sample timestamp for this system if (pSystem->pSystemPerfData != NULL) { llLastTimeStamp = pSystem->pSystemPerfData->PerfTime.QuadPart; } lError = GetSystemPerfData (pSystem->sysDataKey, pSystem->lpszValue, *ppPerfData, &Size) ; if ((!lError) && (Size > 0) && (*ppPerfData)->Signature[0] == (WCHAR)'P' && (*ppPerfData)->Signature[1] == (WCHAR)'E' && (*ppPerfData)->Signature[2] == (WCHAR)'R' && (*ppPerfData)->Signature[3] == (WCHAR)'F' ) { if (pSystem->dwSystemState == SYSTEM_OK) { if (pSystem->pSystemPerfData != NULL) { if (pSystem->pSystemPerfData->PerfTime.QuadPart < llLastTimeStamp) { if (bReportEvents) { // then a system error occured, so log it dwMessageDataBytes = 0; szMessageArray[wMessageIndex++] = pSystem->sysName; ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, // error type 0, // category (not used) (DWORD)PERFMON_ERROR_TIMESTAMP, // event, NULL, // SID (not used), wMessageIndex, // number of strings 0, // sizeof raw data szMessageArray, // message text array NULL); // raw data } } } return (TRUE) ; } else if (pSystem->dwSystemState == SYSTEM_DOWN || pSystem->dwSystemState == SYSTEM_DOWN_RPT ) { if (TimeToCheck && bReportEvents) { // then the system just came back so display the message wMessageIndex = 0; szMessageArray[wMessageIndex++] = pSystem->sysName; ReportEvent (hEventLog, EVENTLOG_INFORMATION_TYPE, // error type 0, // category (not used) (DWORD)PERFMON_INFO_SYSTEM_RESTORED, // event, NULL, // SID (not used), wMessageIndex, // number of strings 0, // sizeof raw data szMessageArray, // message text array NULL); // raw data } pSystem->dwSystemState = SYSTEM_RECONNECT ; } else if (pSystem->dwSystemState == SYSTEM_RECONNECT_RPT) { pSystem->dwSystemState = SYSTEM_OK ; } // for SYSTEM_RECONNECT case, we want to wait for Alert // view to report the re-connection first return (TRUE) ; } if (lError == ERROR_MORE_DATA) { Size = MemorySize ((LPMEMORY)*ppPerfData) + dwPerfDataIncrease; *ppPerfData = MemoryResize ((LPMEMORY)*ppPerfData, Size); if (!*ppPerfData) { if (pSystem->dwSystemState != SYSTEM_DOWN_RPT) { if (bReportEvents) { // then the system just came back so display the message wMessageIndex = 0; dwMessageDataBytes = 0; szMessageArray[wMessageIndex++] = pSystem->sysName; dwMessageData[dwMessageDataBytes++] = Size; dwMessageData[dwMessageDataBytes++] = GetLastError(); dwMessageDataBytes *= sizeof(DWORD); ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, // error type 0, // category (not used) (DWORD)PERFMON_ERROR_PERF_DATA_ALLOC, // event, NULL, // SID (not used), wMessageIndex, // number of strings dwMessageDataBytes, // sizeof raw data szMessageArray, // message text array (LPVOID)&dwMessageData[0]); // raw data } pSystem->dwSystemState = SYSTEM_DOWN ; } pSystem->FailureTime = GetTickCount(); return (FALSE) ; } } else { if (pSystem->dwSystemState != SYSTEM_DOWN_RPT) { if (bReportEvents) { // then the system just came back so display the message wMessageIndex = 0; dwMessageDataBytes = 0; szMessageArray[wMessageIndex++] = pSystem->sysName; dwMessageData[dwMessageDataBytes++] = lError; dwMessageDataBytes *= sizeof(DWORD); ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, // error type 0, // category (not used) (DWORD)PERFMON_ERROR_SYSTEM_OFFLINE, // event, NULL, // SID (not used), wMessageIndex, // number of strings dwMessageDataBytes, // sizeof raw data szMessageArray, // message text array (LPVOID)&dwMessageData[0]); // raw data } pSystem->dwSystemState = SYSTEM_DOWN ; } pSystem->FailureTime = GetTickCount(); return (FALSE) ; } // else } // if } // while } BOOL FailedLinesForSystem ( LPTSTR lpszSystem, PPERFDATA pPerfData, PLINE pLineFirst ) { PLINE pLine ; BOOL bMatchFound = FALSE ; // no line from this system for (pLine = pLineFirst; pLine; pLine = pLine->pLineNext) { if (strsamei (lpszSystem, pLine->lnSystemName)) { FailedLineData (pPerfData, pLine) ; if (pLine->bFirstTime) { pLine->bFirstTime-- ; } bMatchFound = TRUE ; // one or more lines from this system } } return (bMatchFound) ; } BOOL UpdateLinesForSystem (LPTSTR lpszSystem, PPERFDATA pPerfData, PLINE pLineFirst, PPERFSYSTEM pSystem) { PLINE pLine ; BOOL bMatchFound = FALSE ; // no line from this system for (pLine = pLineFirst; pLine; pLine = pLine->pLineNext) { if (strsamei (lpszSystem, pLine->lnSystemName)) { UpdateLineData (pPerfData, pLine, pSystem) ; if (pLine->bFirstTime) { pLine->bFirstTime-- ; } bMatchFound = TRUE ; // one or more lines from this system } } return (bMatchFound) ; } BOOL PerfDataInitializeInstance (void) { // pGlobalPerfData = MemoryAllocate (STARTING_SYSINFO_SIZE) ; // return (pGlobalPerfData != NULL) ; return (TRUE) ; } NTSTATUS AddNamesToArray ( LPTSTR lpNames, DWORD dwLastId, LPWSTR *lpCounterId ) { LPWSTR lpThisName; LPWSTR lpStopString; DWORD dwThisCounter; NTSTATUS Status = ERROR_SUCCESS; for (lpThisName = lpNames; *lpThisName; ) { // first string should be an integer (in decimal unicode digits) dwThisCounter = wcstoul(lpThisName, &lpStopString, 10); if ((dwThisCounter == 0) || (dwThisCounter == ULONG_MAX)) { Status += 1; goto ADD_BAILOUT; // bad entry } // point to corresponding counter name while (*lpThisName++); if (dwThisCounter <= dwLastId) { // and load array element; lpCounterId[dwThisCounter] = lpThisName; } while (*lpThisName++); } ADD_BAILOUT: return (Status) ; } // try the new way of getting data... BOOL UpdateLines ( PPPERFSYSTEM ppSystemFirst, PLINE pLineFirst ) { PPERFSYSTEM pSystem ; int iNoUseSystemDetected = 0 ; int NumberOfSystems = 0 ; DWORD WaitStatus ; HANDLE *lpPacketHandles ; // allocate the handle array for multiple wait if (NumberOfHandles == 0) { NumberOfHandles = MAXIMUM_WAIT_OBJECTS ; lpHandles = (HANDLE *) MemoryAllocate (NumberOfHandles * sizeof (HANDLE)) ; if (!lpHandles) { // out of memory, can't go on NumberOfHandles = 0 ; return FALSE ; } } for (pSystem = *ppSystemFirst; pSystem; pSystem = pSystem->pSystemNext) { // lock the state data mutex, should be quick unless this thread // is still getting data from last time if (pSystem->hStateDataMutex == 0) continue ; WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L); if (WaitStatus == WAIT_OBJECT_0) { ResetEvent (pSystem->hPerfDataEvent) ; pSystem->StateData = WAIT_FOR_PERF_DATA ; // add this to the wait if (NumberOfSystems >= NumberOfHandles) { NumberOfHandles += MAXIMUM_WAIT_OBJECTS ; lpHandles = (HANDLE *) MemoryResize ( lpHandles, NumberOfHandles * sizeof (HANDLE)) ; if (!lpHandles) { // out of memory, can't go on NumberOfHandles = 0 ; return FALSE ; } } lpHandles [NumberOfSystems] = pSystem->hPerfDataEvent ; NumberOfSystems++ ; // Send Message to thread to take a data sample PostThreadMessage ( pSystem->dwThreadID, WM_GET_PERF_DATA, (WPARAM)0, (LPARAM)0) ; ReleaseMutex(pSystem->hStateDataMutex); } else { // wait timed out, report error if (bReportEvents) { wMessageIndex = 0; dwMessageDataBytes = 0; szMessageArray[wMessageIndex++] = pSystem->sysName; ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, // error type 0, // category (not used) (DWORD)PERFMON_ERROR_LOCK_TIMEOUT, // event, NULL, // SID (not used), wMessageIndex, // number of strings 0, // sizeof raw data szMessageArray, // message text array NULL); // raw data } } } Sleep (10); // give the data collection thread a chance to get going // wait for all the data if (NumberOfSystems) { // increase timeout if we are monitoring lots of systems // For every additional 5 systems, add 5 more seconds lpPacketHandles = lpHandles ; do { WaitStatus = WaitForMultipleObjects ( min (NumberOfSystems, MAXIMUM_WAIT_OBJECTS), lpPacketHandles, TRUE, // wait for all objects DataTimeOut + (NumberOfSystems / 5) * DEFAULT_DATA_TIMEOUT); if (WaitStatus == WAIT_TIMEOUT || NumberOfSystems <= MAXIMUM_WAIT_OBJECTS) { //if (WaitStatus == WAIT_TIMEOUT) // mike2(TEXT("WaitTimeOut for %ld systems\n"), NumberOfSystems) ; break ; } // more systems --> more to wait NumberOfSystems -= MAXIMUM_WAIT_OBJECTS ; lpPacketHandles += MAXIMUM_WAIT_OBJECTS ; } while (TRUE) ; for (pSystem = *ppSystemFirst; pSystem; pSystem = pSystem->pSystemNext) { if (pSystem->hStateDataMutex == 0) continue ; // lock the state data mutex WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L); if (WaitStatus == WAIT_OBJECT_0) { if (pSystem->StateData != PERF_DATA_READY) { if (!FailedLinesForSystem (pSystem->sysName, pSystem->pSystemPerfData, pLineFirst)) { if (!bAddLineInProgress) { // mark this system as no-longer-needed iNoUseSystemDetected++ ; pSystem->bSystemNoLongerNeeded = TRUE ; } } } else { if (!UpdateLinesForSystem (pSystem->sysName, pSystem->pSystemPerfData, pLineFirst, pSystem)) { if (!bAddLineInProgress) { // mark this system as no-longer-needed iNoUseSystemDetected++ ; pSystem->bSystemNoLongerNeeded = TRUE ; } } } pSystem->StateData = IDLE_STATE ; ReleaseMutex(pSystem->hStateDataMutex); } else { if (!FailedLinesForSystem (pSystem->sysName, pSystem->pSystemPerfData, pLineFirst)) { if (!bAddLineInProgress) { // mark this system as no-longer-needed iNoUseSystemDetected++ ; pSystem->bSystemNoLongerNeeded = TRUE ; } } } } // check for un-used systems if (iNoUseSystemDetected) { // some unused system(s) detected. DeleteUnusedSystems (ppSystemFirst, iNoUseSystemDetected) ; } } return (TRUE) ; } void PerfDataThread ( PPERFSYSTEM pSystem ) { MSG msg ; BOOL bGetPerfData ; DWORD WaitStatus ; while (GetMessage (&msg, NULL, 0, 0)) { if (LOWORD(msg.message) == WM_GET_PERF_DATA) { // this system has been marked as no long used, // forget about getting data and continue until // we get to the WM_FREE_SYSTEM msg if (pSystem->bSystemNoLongerNeeded) continue ; bGetPerfData = FALSE ; if (!bAddLineInProgress || (pSystem->lpszValue && !strsame (pSystem->lpszValue, L"Global"))) { bGetPerfData = UpdateSystemData (pSystem, &(pSystem->pSystemPerfData)) ; } WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 1000L); if (WaitStatus == WAIT_OBJECT_0) { if (pSystem->StateData == WAIT_FOR_PERF_DATA) { pSystem->StateData = bGetPerfData ? PERF_DATA_READY : PERF_DATA_FAIL ; } else { //mike2(TEXT("Thread - System = %s, WaitStatus = %d\n"), //pSystem->sysName, WaitStatus) ; } ReleaseMutex(pSystem->hStateDataMutex); SetEvent (pSystem->hPerfDataEvent) ; } } // WM_GET_PERF_DATA MSG else if (LOWORD(msg.message) == WM_FREE_SYSTEM) { //mike2(TEXT("Thread - System = %s closing\n"), //pSystem->sysName) ; // do the memory cleanup during SystemFree stage // cleanup all the data collection variables if (pSystem->hPerfDataEvent) CloseHandle (pSystem->hPerfDataEvent) ; if (pSystem->hStateDataMutex) CloseHandle (pSystem->hStateDataMutex) ; if (pSystem->pSystemPerfData) MemoryFree ((LPMEMORY)pSystem->pSystemPerfData); if (pSystem->lpszValue) { MemoryFree (pSystem->lpszValue); pSystem->lpszValue = NULL ; } CloseHandle (pSystem->hThread); MemoryFree (pSystem) ; break ; // get out of message loop } // WM_FREE_SYSTEM MSG } ExitThread (TRUE) ; }