windows-nt/Source/XPSP1/NT/sdktools/pdh/wbemperf/utils.c
2020-09-26 16:20:57 +08:00

562 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++ 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;
}