2637 lines
82 KiB
C
2637 lines
82 KiB
C
//==========================================================================//
|
|
// Includes //
|
|
//==========================================================================//
|
|
|
|
|
|
#include <string.h> // strupr
|
|
#include <stdio.h> // 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) ;
|
|
}
|