562 lines
15 KiB
C
562 lines
15 KiB
C
/*++ BUILD Version: 0001 // Increment this if a change has global effects
|
||
|
||
Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
utils.c
|
||
|
||
Abstract:
|
||
|
||
Utility functions used by the performance library functions
|
||
|
||
Author:
|
||
|
||
Russ Blake 11/15/91
|
||
|
||
Revision History:
|
||
8-Jun-98 bobw revised for use with WBEM functions
|
||
|
||
--*/
|
||
#define UNICODE
|
||
//
|
||
// Include files
|
||
//
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <winperf.h>
|
||
//#include <prflbmsg.h>
|
||
//#include <regrpc.h>
|
||
#include "PerfAcc.h"
|
||
#include "strings.h"
|
||
#include "utils.h"
|
||
#include "wbprfmsg.h"
|
||
// test for delimiter, end of line and non-digit characters
|
||
// used by IsNumberInUnicodeList routine
|
||
//
|
||
#define DIGIT 1
|
||
#define DELIMITER 2
|
||
#define INVALID 3
|
||
|
||
#define EvalThisChar(c,d) ( \
|
||
(c == d) ? DELIMITER : \
|
||
(c == 0) ? DELIMITER : \
|
||
(c < '0') ? INVALID : \
|
||
(c > '9') ? INVALID : \
|
||
DIGIT)
|
||
|
||
// the length of "ADDEXPLAIN" in chars
|
||
#define MAX_KEYWORD_LEN 10
|
||
|
||
// minimum length to hold a value name understood by Perflib
|
||
// "foreign" is the longest "string" value understood
|
||
|
||
const DWORD VALUE_NAME_LENGTH = ((7 + 1) * sizeof(WCHAR));
|
||
|
||
HANDLE hEventLog = NULL;
|
||
|
||
static WCHAR LocalComputerName[MAX_PATH];
|
||
static LPWSTR pComputerName = &LocalComputerName[0];
|
||
static DWORD ComputerNameLength = 0;
|
||
|
||
BOOL
|
||
MonBuildPerfDataBlock(
|
||
PERF_DATA_BLOCK *pBuffer,
|
||
PVOID *pBufferNext,
|
||
DWORD NumObjectTypes,
|
||
DWORD DefaultObject
|
||
)
|
||
/*++
|
||
|
||
MonBuildPerfDataBlock - build the PERF_DATA_BLOCK structure
|
||
|
||
Inputs:
|
||
|
||
pBuffer - where the data block should be placed
|
||
|
||
pBufferNext - where pointer to next byte of data block
|
||
is to begin; DWORD aligned
|
||
|
||
NumObjectTypes - number of types of objects being reported
|
||
|
||
DefaultObject - object to display by default when
|
||
this system is selected; this is the
|
||
object type title index
|
||
--*/
|
||
|
||
{
|
||
|
||
LARGE_INTEGER Time, TimeX10000;
|
||
|
||
// Initialize Signature and version ID for this data structure
|
||
|
||
pBuffer->Signature[0] = wc_P;
|
||
pBuffer->Signature[1] = wc_E;
|
||
pBuffer->Signature[2] = wc_R;
|
||
pBuffer->Signature[3] = wc_F;
|
||
|
||
pBuffer->LittleEndian = 1;
|
||
|
||
pBuffer->Version = PERF_DATA_VERSION;
|
||
pBuffer->Revision = PERF_DATA_REVISION;
|
||
|
||
//
|
||
// The next field will be filled in at the end when the length
|
||
// of the return data is known
|
||
//
|
||
|
||
pBuffer->TotalByteLength = 0;
|
||
|
||
pBuffer->NumObjectTypes = NumObjectTypes;
|
||
pBuffer->DefaultObject = DefaultObject;
|
||
GetSystemTime(&pBuffer->SystemTime);
|
||
NtQueryPerformanceCounter(&pBuffer->PerfTime,&pBuffer->PerfFreq);
|
||
|
||
TimeX10000.QuadPart = pBuffer->PerfTime.QuadPart * 10000L;
|
||
Time.QuadPart = TimeX10000.QuadPart / pBuffer->PerfFreq.LowPart;
|
||
pBuffer->PerfTime100nSec.QuadPart = Time.QuadPart * 1000L;
|
||
|
||
if ( ComputerNameLength == 0) {
|
||
// load the name
|
||
ComputerNameLength = sizeof (LocalComputerName) / sizeof(LocalComputerName[0]);
|
||
if (!GetComputerNameW(pComputerName, &ComputerNameLength)) {
|
||
// name look up failed so reset length
|
||
ComputerNameLength = 0;
|
||
}
|
||
assert (ComputerNameLength > 0);
|
||
}
|
||
|
||
// There is a Computer name: i.e., the network is installed
|
||
|
||
pBuffer->SystemNameLength = ComputerNameLength;
|
||
pBuffer->SystemNameOffset = sizeof(PERF_DATA_BLOCK);
|
||
RtlMoveMemory(&pBuffer[1],
|
||
pComputerName,
|
||
ComputerNameLength);
|
||
*pBufferNext = (PVOID) ((PCHAR) &pBuffer[1] +
|
||
QWORD_MULTIPLE(ComputerNameLength));
|
||
pBuffer->HeaderLength = (DWORD)((PCHAR) *pBufferNext - (PCHAR) pBuffer);
|
||
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Perflib functions:
|
||
//
|
||
LONG
|
||
GetPerflibKeyValue (
|
||
LPCWSTR szItem,
|
||
DWORD dwRegType,
|
||
DWORD dwMaxSize, // ... of pReturnBuffer in bytes
|
||
LPVOID pReturnBuffer,
|
||
DWORD dwDefaultSize, // ... of pDefault in bytes
|
||
LPVOID pDefault
|
||
)
|
||
/*++
|
||
|
||
read and return the current value of the specified value
|
||
under the Perflib registry key. If unable to read the value
|
||
return the default value from the argument list.
|
||
|
||
the value is returned in the pReturnBuffer.
|
||
|
||
--*/
|
||
{
|
||
|
||
HKEY hPerflibKey;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
NTSTATUS Status;
|
||
UNICODE_STRING PerflibSubKeyString;
|
||
UNICODE_STRING ValueNameString;
|
||
LONG lReturn = STATUS_SUCCESS;
|
||
PKEY_VALUE_PARTIAL_INFORMATION pValueInformation;
|
||
ULONG ValueBufferLength;
|
||
ULONG ResultLength;
|
||
BOOL bUseDefault = TRUE;
|
||
|
||
// initialize UNICODE_STRING structures used in this function
|
||
|
||
RtlInitUnicodeString (
|
||
&PerflibSubKeyString,
|
||
cszPerflibKey);
|
||
|
||
RtlInitUnicodeString (
|
||
&ValueNameString,
|
||
(LPWSTR)szItem);
|
||
|
||
//
|
||
// Initialize the OBJECT_ATTRIBUTES structure and open the key.
|
||
//
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&PerflibSubKeyString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenKey(
|
||
&hPerflibKey,
|
||
KEY_READ,
|
||
&Obja
|
||
);
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
// read value of desired entry
|
||
|
||
ValueBufferLength = ResultLength = 1024;
|
||
pValueInformation = ALLOCMEM(RtlProcessHeap(), 0, ResultLength);
|
||
|
||
if (pValueInformation != NULL) {
|
||
while ( (Status = NtQueryValueKey(hPerflibKey,
|
||
&ValueNameString,
|
||
KeyValuePartialInformation,
|
||
pValueInformation,
|
||
ValueBufferLength,
|
||
&ResultLength))
|
||
== STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
pValueInformation = REALLOCMEM(RtlProcessHeap(), 0,
|
||
pValueInformation,
|
||
ResultLength);
|
||
if ( pValueInformation == NULL) {
|
||
break;
|
||
} else {
|
||
ValueBufferLength = ResultLength;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
// check to see if it's the desired type
|
||
if (pValueInformation->Type == dwRegType) {
|
||
// see if it will fit
|
||
if (pValueInformation->DataLength <= dwMaxSize) {
|
||
memcpy (pReturnBuffer, &pValueInformation->Data[0],
|
||
pValueInformation->DataLength);
|
||
bUseDefault = FALSE;
|
||
lReturn = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
} else {
|
||
// return the default value
|
||
lReturn = Status;
|
||
}
|
||
// release temp buffer
|
||
if (pValueInformation) {
|
||
FREEMEM (RtlProcessHeap(), 0, pValueInformation);
|
||
}
|
||
} else {
|
||
// unable to allocate memory for this operation so
|
||
// just return the default value
|
||
}
|
||
// close the registry key
|
||
NtClose(hPerflibKey);
|
||
} else {
|
||
// return default value
|
||
}
|
||
|
||
if (bUseDefault) {
|
||
memcpy (pReturnBuffer, pDefault, dwDefaultSize);
|
||
lReturn = STATUS_SUCCESS;
|
||
}
|
||
|
||
return lReturn;
|
||
}
|
||
|
||
#pragma warning ( disable : 4127) // while (TRUE) error
|
||
BOOL
|
||
MatchString (
|
||
IN LPCWSTR lpValueArg,
|
||
IN LPCWSTR lpNameArg
|
||
)
|
||
/*++
|
||
|
||
MatchString
|
||
|
||
return TRUE if lpName is in lpValue. Otherwise return FALSE
|
||
|
||
Arguments
|
||
|
||
IN lpValue
|
||
string passed to PerfRegQuery Value for processing
|
||
|
||
IN lpName
|
||
string for one of the keyword names
|
||
|
||
Return TRUE | FALSE
|
||
|
||
--*/
|
||
{
|
||
BOOL bFound = TRUE; // assume found until contradicted
|
||
LPWSTR lpValue = (LPWSTR)lpValueArg;
|
||
LPWSTR lpName = (LPWSTR)lpNameArg;
|
||
|
||
// check to the length of the shortest string
|
||
|
||
while (1) {
|
||
if (*lpValue != 0) {
|
||
if (*lpName != 0) {
|
||
if (*lpValue++ != *lpName++) {
|
||
bFound = FALSE; // no match
|
||
break; // bail out now
|
||
}
|
||
} else {
|
||
// the value still has characters, but the name is out
|
||
// so this is no match
|
||
bFound = FALSE;
|
||
break;
|
||
}
|
||
} else {
|
||
if (*lpName != 0) {
|
||
// then the value is out of characters, but the name
|
||
// is out so no match
|
||
bFound = FALSE;
|
||
break;
|
||
} else {
|
||
// both strings are at the end so it must be a match
|
||
}
|
||
}
|
||
}
|
||
|
||
return (bFound);
|
||
}
|
||
#pragma warning ( default : 4127) // while (TRUE) error
|
||
|
||
DWORD
|
||
GetQueryType (
|
||
IN LPWSTR lpValue
|
||
)
|
||
/*++
|
||
|
||
GetQueryType
|
||
|
||
returns the type of query described in the lpValue string so that
|
||
the appropriate processing method may be used
|
||
|
||
Arguments
|
||
|
||
IN lpValue
|
||
string passed to PerfRegQuery Value for processing
|
||
|
||
Return Value
|
||
|
||
QUERY_GLOBAL
|
||
if lpValue == 0 (null pointer)
|
||
lpValue == pointer to Null string
|
||
lpValue == pointer to "Global" string
|
||
|
||
QUERY_FOREIGN
|
||
if lpValue == pointer to "Foriegn" string
|
||
|
||
QUERY_COSTLY
|
||
if lpValue == pointer to "Costly" string
|
||
|
||
QUERY_COUNTER
|
||
if lpValue == pointer to "Counter" string
|
||
|
||
QUERY_HELP
|
||
if lpValue == pointer to "Explain" string
|
||
|
||
QUERY_ADDCOUNTER
|
||
if lpValue == pointer to "Addcounter" string
|
||
|
||
QUERY_ADDHELP
|
||
if lpValue == pointer to "Addexplain" string
|
||
|
||
otherwise:
|
||
|
||
QUERY_ITEMS
|
||
|
||
--*/
|
||
{
|
||
WCHAR LocalBuff[MAX_KEYWORD_LEN+1];
|
||
int i;
|
||
|
||
if ((lpValue == 0 || *lpValue == 0))
|
||
return QUERY_GLOBAL;
|
||
|
||
// convert the input string to Upper case before matching
|
||
for (i=0; i < MAX_KEYWORD_LEN; i++) {
|
||
if ((*lpValue == wcSpace) || (*lpValue == 0)) {
|
||
break;
|
||
}
|
||
LocalBuff[i] = *lpValue ;
|
||
if (*lpValue >= wc_a && *lpValue <= wc_z) {
|
||
LocalBuff[i] = (WCHAR)(LocalBuff[i] - (WCHAR)wc_a + (WCHAR)wc_A);
|
||
}
|
||
lpValue++ ;
|
||
}
|
||
LocalBuff[i] = 0;
|
||
|
||
// check for "Global" request
|
||
if (MatchString (LocalBuff, cszGlobal))
|
||
return QUERY_GLOBAL ;
|
||
|
||
// check for "Foreign" request
|
||
if (MatchString (LocalBuff, cszForeign))
|
||
return QUERY_FOREIGN ;
|
||
|
||
// check for "Costly" request
|
||
if (MatchString (LocalBuff, cszCostly))
|
||
return QUERY_COSTLY;
|
||
|
||
// check for "Counter" request
|
||
if (MatchString (LocalBuff, cszCounter))
|
||
return QUERY_COUNTER;
|
||
|
||
// check for "Help" request
|
||
if (MatchString (LocalBuff, cszHelp))
|
||
return QUERY_HELP;
|
||
|
||
if (MatchString (LocalBuff, cszExplain))
|
||
return QUERY_HELP;
|
||
|
||
// check for "AddCounter" request
|
||
if (MatchString (LocalBuff, cszAddCounter))
|
||
return QUERY_ADDCOUNTER;
|
||
|
||
// check for "AddHelp" request
|
||
if (MatchString (LocalBuff, cszAddHelp))
|
||
return QUERY_ADDHELP;
|
||
|
||
// None of the above, then it must be an item list
|
||
return QUERY_ITEMS;
|
||
|
||
}
|
||
|
||
#pragma warning ( disable : 4127) // while (TRUE) error
|
||
DWORD
|
||
GetNextNumberFromList (
|
||
IN LPWSTR szStartChar,
|
||
IN LPWSTR *szNextChar
|
||
)
|
||
/*++
|
||
|
||
Reads a character string from the szStartChar to the next
|
||
delimiting space character or the end of the string and returns
|
||
the value of the decimal number found. If no valid number is found
|
||
then 0 is returned. The pointer to the next character in the
|
||
string is returned in the szNextChar parameter. If the character
|
||
referenced by this pointer is 0, then the end of the string has
|
||
been reached.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwThisNumber = 0;
|
||
WCHAR *pwcThisChar = szStartChar;
|
||
WCHAR wcDelimiter = wcSpace;
|
||
BOOL bValidNumber = FALSE;
|
||
|
||
if (szStartChar != 0) {
|
||
while (TRUE) {
|
||
switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
|
||
case DIGIT:
|
||
// if this is the first digit after a delimiter, then
|
||
// set flags to start computing the new number
|
||
bValidNumber = TRUE;
|
||
dwThisNumber *= 10;
|
||
dwThisNumber += (*pwcThisChar - wc_0);
|
||
break;
|
||
|
||
case DELIMITER:
|
||
// a delimter is either the delimiter character or the
|
||
// end of the string ('\0') if when the delimiter has been
|
||
// reached a valid number was found, then return it
|
||
//
|
||
if (bValidNumber || (*pwcThisChar == 0)) {
|
||
*szNextChar = pwcThisChar;
|
||
return dwThisNumber;
|
||
} else {
|
||
// continue until a non-delimiter char or the
|
||
// end of the file is found
|
||
}
|
||
break;
|
||
|
||
case INVALID:
|
||
// if an invalid character was encountered, ignore all
|
||
// characters up to the next delimiter and then start fresh.
|
||
// the invalid number is not compared.
|
||
bValidNumber = FALSE;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
|
||
}
|
||
pwcThisChar++;
|
||
}
|
||
} else {
|
||
*szNextChar = szStartChar;
|
||
return 0;
|
||
}
|
||
}
|
||
#pragma warning ( default : 4127) // while (TRUE) error
|
||
|
||
BOOL
|
||
IsNumberInUnicodeList (
|
||
IN DWORD dwNumber,
|
||
IN LPWSTR lpwszUnicodeList
|
||
)
|
||
/*++
|
||
|
||
IsNumberInUnicodeList
|
||
|
||
Arguments:
|
||
|
||
IN dwNumber
|
||
DWORD number to find in list
|
||
|
||
IN lpwszUnicodeList
|
||
Null terminated, Space delimited list of decimal numbers
|
||
|
||
Return Value:
|
||
|
||
TRUE:
|
||
dwNumber was found in the list of unicode number strings
|
||
|
||
FALSE:
|
||
dwNumber was not found in the list.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwThisNumber;
|
||
WCHAR *pwcThisChar;
|
||
|
||
if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
|
||
|
||
pwcThisChar = lpwszUnicodeList;
|
||
dwThisNumber = 0;
|
||
|
||
while (*pwcThisChar != 0) {
|
||
dwThisNumber = GetNextNumberFromList (
|
||
pwcThisChar, &pwcThisChar);
|
||
if (dwNumber == dwThisNumber) return TRUE;
|
||
}
|
||
// if here, then the number wasn't found
|
||
return FALSE;
|
||
|
||
} // IsNumberInUnicodeList
|
||
|
||
LPWSTR
|
||
ConvertProcName(LPSTR strProcName)
|
||
{
|
||
static WCHAR wstrProcName[MAX_PATH];
|
||
ULONG lenProcName = (strProcName == NULL) ? (0) : (lstrlenA(strProcName));
|
||
ULONG i;
|
||
PUCHAR AnsiChar;
|
||
|
||
if ((lenProcName == 0) || (lenProcName >= MAX_PATH)) {
|
||
return (LPWSTR) cszSpace;
|
||
}
|
||
|
||
for (i = 0; i < lenProcName; i ++) {
|
||
AnsiChar = (PUCHAR) & strProcName[i];
|
||
wstrProcName[i] = (WCHAR) RtlAnsiCharToUnicodeChar(& AnsiChar);
|
||
}
|
||
wstrProcName[lenProcName] = L'\0';
|
||
return wstrProcName;
|
||
}
|
||
|