2362 lines
71 KiB
C
2362 lines
71 KiB
C
//==========================================================================//
|
||
// Includes //
|
||
//==========================================================================//
|
||
|
||
|
||
#include <string.h> // strupr
|
||
#include <stdio.h> // for sprintf.
|
||
#include "setedit.h"
|
||
#include "utils.h"
|
||
|
||
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
|
||
#include "perfdata.h" // external declarations for this file
|
||
#include "system.h" // for DeleteUnusedSystems
|
||
|
||
//==========================================================================//
|
||
// 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
|
||
)
|
||
{ // ObjectName
|
||
strclr (lpszName) ;
|
||
QueryPerformanceName (pSystem,
|
||
pObject->ObjectNameTitleIndex,
|
||
0, iLen, lpszName, FALSE) ;
|
||
} // ObjectName
|
||
|
||
|
||
|
||
//======================================//
|
||
// Counter Accessors //
|
||
//======================================//
|
||
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
FirstInstance(
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef
|
||
)
|
||
{
|
||
return (PERF_INSTANCE_DEFINITION *)
|
||
((PCHAR) pObjectDef + pObjectDef->DefinitionLength);
|
||
}
|
||
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
NextInstance(
|
||
PERF_INSTANCE_DEFINITION *pInstDef
|
||
)
|
||
{
|
||
PERF_COUNTER_BLOCK *pCounterBlock;
|
||
|
||
pCounterBlock = (PERF_COUNTER_BLOCK *)
|
||
((PCHAR) pInstDef + pInstDef->ByteLength);
|
||
|
||
return (PERF_INSTANCE_DEFINITION *)
|
||
((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
|
||
}
|
||
|
||
|
||
|
||
LPTSTR
|
||
GetInstanceName(
|
||
PPERFINSTANCEDEF pInstDef)
|
||
{
|
||
return (LPTSTR) ((PCHAR) pInstDef + pInstDef->NameOffset);
|
||
}
|
||
|
||
|
||
void
|
||
GetInstanceNameStr (
|
||
PPERFINSTANCEDEF pInstance,
|
||
LPTSTR lpszInstance
|
||
)
|
||
{
|
||
// This function used to test for ansi names, but
|
||
// instance names should ALWAYS be wide character
|
||
// strings so this is removed (especially since
|
||
// looking for a null byte is a bogus test in the
|
||
// first place)
|
||
|
||
LPTSTR pSource;
|
||
|
||
pSource = (LPTSTR) GetInstanceName(pInstance) ;
|
||
|
||
wcsncpy (lpszInstance,
|
||
(LPTSTR)pSource,
|
||
pInstance->NameLength);
|
||
}
|
||
|
||
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,
|
||
PERF_OBJECT_TYPE UNALIGNED *pObject)
|
||
/*
|
||
Effect: Return the index ("counter number") of pCounterToFind
|
||
within pObject. If the counter doesnt belong to pObject,
|
||
return -1.
|
||
*/
|
||
{ // CounterIndex
|
||
PPERFCOUNTERDEF pCounter ;
|
||
UINT iCounter ;
|
||
|
||
for (iCounter = 0, pCounter = FirstCounter (pObject) ;
|
||
iCounter < pObject->NumCounters ;
|
||
iCounter++, pCounter = NextCounter (pCounter)) { // for
|
||
if (pCounter->CounterNameTitleIndex ==
|
||
pCounterToFind->CounterNameTitleIndex)
|
||
return (iCounter) ;
|
||
} // for
|
||
|
||
return (-1) ;
|
||
} // CounterIndex
|
||
|
||
|
||
HKEY
|
||
OpenSystemPerfData (
|
||
IN LPCTSTR lpszSystem
|
||
)
|
||
{ // OpenSystemPerfData
|
||
|
||
HKEY hKey = NULL;
|
||
LONG lStatus;
|
||
|
||
lStatus = ERROR_CANTOPEN; // default error if none is returned
|
||
|
||
if (IsLocalComputer(lpszSystem)) {
|
||
bCloseLocalMachine = TRUE ;
|
||
SetLastError (ERROR_SUCCESS);
|
||
return HKEY_PERFORMANCE_DATA;
|
||
} else if (lstrlen (lpszSystem) < MAX_COMPUTERNAME_LENGTH+3) {
|
||
// 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);
|
||
|
||
} // OpenSystemPerfData
|
||
|
||
|
||
|
||
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;
|
||
NTSTATUS Status;
|
||
DWORD dwLastError;
|
||
|
||
dwArraySize = (dwLastId + 1 ) * sizeof(LPWSTR);
|
||
lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize);
|
||
|
||
if (!lpReturnValue) {
|
||
lWin32Status = ERROR_NOT_ENOUGH_MEMORY;
|
||
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);
|
||
lstrcpy (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);
|
||
lstrcpy (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;
|
||
*phKeyMachine = HKEY_LOCAL_MACHINE;
|
||
|
||
// connect to system registry
|
||
|
||
if (IsLocalComputer(pSysInfo->sysName)) {
|
||
*phKeyMachine = HKEY_LOCAL_MACHINE;
|
||
} else if (lstrlen(pSysInfo->sysName) < MAX_COMPUTERNAME_LENGTH+3) {
|
||
try {
|
||
dwStatus = RegConnectRegistry (
|
||
pSysInfo->sysName,
|
||
HKEY_LOCAL_MACHINE,
|
||
phKeyMachine);
|
||
|
||
if (dwStatus != ERROR_SUCCESS) {
|
||
// return dwStatus;
|
||
// comnputer name not found, use the local system's registry
|
||
*phKeyMachine = HKEY_LOCAL_MACHINE;
|
||
return 0;
|
||
}
|
||
}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
|
||
|
||
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 SIZE_T * pdwPerfDataLen
|
||
)
|
||
{ // GetSystemPerfData
|
||
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, (DWORD *)pdwPerfDataLen) ;
|
||
return (lError) ;
|
||
} // GetSystemPerfData
|
||
|
||
|
||
BOOL
|
||
CloseSystemPerfData (
|
||
HKEY hKeySystem
|
||
)
|
||
{ // CloseSystemPerfData
|
||
return (TRUE) ;
|
||
} // CloseSystemPerfData
|
||
|
||
|
||
|
||
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.
|
||
*/
|
||
{ // CBLoadObjects
|
||
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 szObject not empty
|
||
} // if
|
||
} // for
|
||
|
||
|
||
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) ;
|
||
} // CBLoadObjects
|
||
|
||
|
||
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.
|
||
*/
|
||
{ // LBLoadObjects
|
||
UINT i ;
|
||
INT_PTR iIndex ;
|
||
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)) { // for
|
||
if (pObject->DetailLevel <= dwDetailLevel) { // if
|
||
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 szObject is not empty
|
||
}
|
||
} // for
|
||
|
||
|
||
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) ;
|
||
} // LBLoadObjects
|
||
|
||
|
||
/***************************************************************************\
|
||
* GetObjectDef()
|
||
*
|
||
* Entry: pointer to data block and the number of the object type
|
||
* Exit: returns a pointer to the specified object type definition
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_OBJECT_TYPE *
|
||
GetObjectDef(
|
||
PERF_DATA_BLOCK *pDataBlock,
|
||
DWORD NumObjectType
|
||
)
|
||
{
|
||
DWORD NumTypeDef;
|
||
|
||
PERF_OBJECT_TYPE *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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_OBJECT_TYPE *
|
||
GetObjectDefByTitleIndex(
|
||
PERF_DATA_BLOCK *pDataBlock,
|
||
DWORD ObjectTypeTitleIndex
|
||
)
|
||
{
|
||
DWORD NumTypeDef;
|
||
|
||
PERF_OBJECT_TYPE *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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_OBJECT_TYPE *
|
||
GetObjectDefByName(
|
||
PPERFSYSTEM pSystem,
|
||
PERF_DATA_BLOCK *pDataBlock,
|
||
LPTSTR pObjectName
|
||
)
|
||
{
|
||
DWORD NumTypeDef;
|
||
TCHAR szObjectName [PerfObjectLen + 1] ;
|
||
|
||
PERF_OBJECT_TYPE *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;
|
||
}
|
||
|
||
/***************************************************************************\
|
||
* GetCounterDef()
|
||
*
|
||
* Entry: pointer to object type definition the number of the Counter
|
||
* definition
|
||
* Exit: returns a pointer to the specified Counter definition
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_COUNTER_DEFINITION *
|
||
GetCounterDef(
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
DWORD NumCounter
|
||
)
|
||
{
|
||
DWORD NumCtrDef;
|
||
|
||
PERF_COUNTER_DEFINITION *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(
|
||
PERF_OBJECT_TYPE *pObjectDef,
|
||
DWORD CounterTitleIndex
|
||
)
|
||
{
|
||
DWORD NumCtrDef;
|
||
|
||
PERF_COUNTER_DEFINITION *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(
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
PERF_COUNTER_DEFINITION *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(
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
PERF_INSTANCE_DEFINITION *pInstanceDef,
|
||
PERF_COUNTER_DEFINITION *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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
GetNextInstance(
|
||
PERF_INSTANCE_DEFINITION *pInstDef
|
||
)
|
||
{
|
||
PERF_COUNTER_BLOCK *pCtrBlock;
|
||
|
||
pCtrBlock = (PERF_COUNTER_BLOCK *)
|
||
((PCHAR) pInstDef + pInstDef->ByteLength);
|
||
|
||
return (PERF_INSTANCE_DEFINITION *)
|
||
((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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
GetInstance(
|
||
PERF_OBJECT_TYPE *pObjectDef,
|
||
LONG InstanceNumber
|
||
)
|
||
{
|
||
|
||
PERF_INSTANCE_DEFINITION *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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
GetInstanceByUniqueID(
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
LONG UniqueID,
|
||
DWORD dwIndex
|
||
)
|
||
{
|
||
|
||
PERF_INSTANCE_DEFINITION *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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
GetInstanceByNameUsingParentTitleIndex(
|
||
PERF_DATA_BLOCK *pDataBlock,
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
LPTSTR pInstanceName,
|
||
LPTSTR pParentName,
|
||
DWORD dwIndex
|
||
)
|
||
{
|
||
BOOL fHaveParent;
|
||
PERF_OBJECT_TYPE *pParentObj;
|
||
|
||
PERF_INSTANCE_DEFINITION *pParentInst,
|
||
*pInstanceDef;
|
||
|
||
LONG NumInstance;
|
||
TCHAR InstanceName[256];
|
||
DWORD dwLocalIndex;
|
||
|
||
|
||
fHaveParent = FALSE;
|
||
pInstanceDef = FirstInstance(pObjectDef);
|
||
dwLocalIndex = dwIndex;
|
||
|
||
for ( NumInstance = 0;
|
||
NumInstance < pObjectDef->NumInstances;
|
||
NumInstance++ ) {
|
||
|
||
GetInstanceNameStr(pInstanceDef,InstanceName);
|
||
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);
|
||
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
|
||
*
|
||
\***************************************************************************/
|
||
|
||
PERF_INSTANCE_DEFINITION *
|
||
GetInstanceByName(
|
||
PERF_DATA_BLOCK *pDataBlock,
|
||
PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
|
||
LPTSTR pInstanceName,
|
||
LPTSTR pParentName,
|
||
DWORD dwIndex
|
||
)
|
||
{
|
||
BOOL fHaveParent;
|
||
|
||
PERF_OBJECT_TYPE *pParentObj;
|
||
|
||
PERF_INSTANCE_DEFINITION *pParentInst,
|
||
*pInstanceDef;
|
||
|
||
LONG NumInstance;
|
||
TCHAR InstanceName[256];
|
||
DWORD dwLocalIndex;
|
||
|
||
fHaveParent = FALSE;
|
||
pInstanceDef = FirstInstance(pObjectDef);
|
||
dwLocalIndex = dwIndex;
|
||
|
||
for ( NumInstance = 0;
|
||
NumInstance < pObjectDef->NumInstances;
|
||
NumInstance++ ) {
|
||
|
||
GetInstanceNameStr(pInstanceDef,InstanceName);
|
||
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)
|
||
break;
|
||
|
||
pParentInst = GetInstance(pParentObj,
|
||
pInstanceDef->ParentObjectInstance);
|
||
|
||
if (pParentInst == NULL)
|
||
break;
|
||
GetInstanceNameStr(pParentInst,InstanceName);
|
||
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.
|
||
*/
|
||
|
||
{ // FailedLineData
|
||
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 ;
|
||
|
||
} // FailedLineData
|
||
|
||
|
||
BOOL
|
||
UpdateLineData (
|
||
PPERFDATA pPerfData,
|
||
PLINE pLine,
|
||
PPERFSYSTEM pSystem
|
||
)
|
||
/*
|
||
Assert: pPerfData holds the performance data for the same
|
||
system as pLine.
|
||
*/
|
||
{ // UpdateLineData
|
||
PERF_OBJECT_TYPE UNALIGNED *pObject ;
|
||
PPERFINSTANCEDEF pInstanceDef ;
|
||
PPERFCOUNTERDEF pCounterDef ;
|
||
PPERFCOUNTERDEF pCounterDef2 ;
|
||
PDWORD pCounterValue ;
|
||
PDWORD pCounterValue2 ;
|
||
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 ;
|
||
|
||
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].LowPart = liDummy[0].HighPart = 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].LowPart = liDummy[0].HighPart = 0;
|
||
liDummy[1].LowPart = liDummy[1].HighPart = 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].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].LowPart = *pCounterValue2;
|
||
} else
|
||
pLine->lnaCounterValue[1] =
|
||
*((LARGE_INTEGER UNALIGNED *) pCounterValue2);
|
||
}
|
||
return (TRUE) ;
|
||
} // UpdateLineData
|
||
|
||
|
||
|
||
BOOL
|
||
UpdateSystemData (
|
||
PPERFSYSTEM pSystem,
|
||
PPERFDATA *ppPerfData
|
||
)
|
||
{ // UpdateSystemData
|
||
#define PERF_SYSTEM_TIMEOUT (60L * 1000L)
|
||
long lError ;
|
||
DWORD Status ;
|
||
SIZE_T Size;
|
||
|
||
if (!ppPerfData)
|
||
return (FALSE) ;
|
||
|
||
while (TRUE) {
|
||
if (pSystem->FailureTime) {
|
||
if (GetTickCount() > pSystem->FailureTime + PERF_SYSTEM_TIMEOUT) {
|
||
// 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 (*ppPerfData);
|
||
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' )
|
||
return (TRUE) ;
|
||
|
||
if (lError == ERROR_MORE_DATA) {
|
||
*ppPerfData = MemoryResize (*ppPerfData,
|
||
MemorySize (*ppPerfData) +
|
||
dwPerfDataIncrease) ;
|
||
if (!*ppPerfData) {
|
||
pSystem->FailureTime = GetTickCount();
|
||
return (FALSE) ;
|
||
}
|
||
} else {
|
||
pSystem->FailureTime = GetTickCount();
|
||
return (FALSE) ;
|
||
} // else
|
||
} // if
|
||
} // while
|
||
} // UpdateSystemData
|
||
|
||
|
||
|
||
BOOL
|
||
FailedLinesForSystem (
|
||
LPTSTR lpszSystem,
|
||
PPERFDATA pPerfData,
|
||
PLINE pLineFirst
|
||
)
|
||
{ // FailedLinesForSystem
|
||
PLINE pLine ;
|
||
BOOL bMatchFound = FALSE ; // no line from this system
|
||
|
||
for (pLine = pLineFirst ;
|
||
pLine ;
|
||
pLine = pLine->pLineNext) { // for pLine
|
||
if (strsamei (lpszSystem, pLine->lnSystemName)) {
|
||
FailedLineData (pPerfData, pLine) ;
|
||
if (pLine->bFirstTime) {
|
||
pLine->bFirstTime-- ;
|
||
}
|
||
bMatchFound = TRUE ; // one or more lines from this system
|
||
}
|
||
} // for pLine
|
||
|
||
return (bMatchFound) ;
|
||
}
|
||
|
||
|
||
BOOL
|
||
UpdateLinesForSystem (
|
||
LPTSTR lpszSystem,
|
||
PPERFDATA pPerfData,
|
||
PLINE pLineFirst,
|
||
PPERFSYSTEM pSystem
|
||
)
|
||
{ // UpdateLinesForSystem
|
||
PLINE pLine ;
|
||
BOOL bMatchFound = FALSE ; // no line from this system
|
||
|
||
for (pLine = pLineFirst ;
|
||
pLine ;
|
||
pLine = pLine->pLineNext) { // for pLine
|
||
if (strsamei (lpszSystem, pLine->lnSystemName)) {
|
||
UpdateLineData (pPerfData, pLine, pSystem) ;
|
||
if (pLine->bFirstTime) {
|
||
pLine->bFirstTime-- ;
|
||
}
|
||
bMatchFound = TRUE ; // one or more lines from this system
|
||
}
|
||
} // for pLine
|
||
|
||
return (bMatchFound) ;
|
||
}
|
||
|
||
|
||
BOOL
|
||
PerfDataInitializeInstance (void)
|
||
{
|
||
// pPerfData = MemoryAllocate (STARTING_SYSINFO_SIZE) ;
|
||
// return (pPerfData != 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;
|
||
lpThisName += (lstrlen(lpThisName)+1) ) {
|
||
|
||
// 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
|
||
|
||
lpThisName += (lstrlen(lpThisName)+1);
|
||
|
||
if (dwThisCounter <= dwLastId) {
|
||
|
||
// and load array element;
|
||
|
||
lpCounterId[dwThisCounter] = 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) { // for
|
||
|
||
// 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);
|
||
}
|
||
}
|
||
|
||
// 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) { // for
|
||
|
||
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) ;
|
||
} // UpdateLines
|
||
|
||
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 (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
|
||
} // GetMessage Loop
|
||
|
||
ExitThread (TRUE) ;
|
||
} // PerfDataThread
|