Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

502 lines
14 KiB

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
perfgen.c
Abstract:
This is the main file of the WINMGMT perf library.
Created:
davj 17-May-2000
Revision History
--*/
#include <windows.h>
#include <string.h>
#include <winperf.h>
#include <math.h>
#include "genctrs.h" // error message definition
#include "perfmsg.h"
#include "perfutil.h"
#include "datagen.h"
DWORD dwDataSize[MAXVALUES];
// This is the shared data segment which allows wbemcore.dll to be able to set
// the counter values
#pragma data_seg(".shared")
DWORD dwCounterValues[MAXVALUES] = {0,0,0,0,0,0,0,0};
#pragma data_seg()
//
// References to constants which initialize the Object type definitions
//
extern REG_DATA_DEFINITION RegDataDefinition;
DWORD dwOpenCount = 0; // count of "Open" threads
BOOL bInitOK = FALSE; // true = DLL initialized OK
//
// Function Prototypes
//
// these are used to insure that the data collection functions
// accessed by Perflib will have the correct calling format.
//
PM_OPEN_PROC OpenWmiPerformanceData;
PM_COLLECT_PROC CollectWmiPerformanceData;
PM_CLOSE_PROC CloseWmiPerformanceData;
DWORD GetData(DWORD * pData, DWORD dwIndex)
{
*pData = dwCounterValues[dwIndex];
return 4;
}
DWORD APIENTRY
OpenWmiPerformanceData(
LPWSTR lpDeviceNames
)
/*++
Routine Description:
This routine will initialize the data structures used to pass
data back to perfmon
Arguments:
Pointer to object ID of each device to be opened (WMIPerf)
Return Value:
None.
--*/
{
LONG status;
HKEY hKeyDriverPerf;
DWORD size, x;
DWORD type;
DWORD dwFirstCounter;
DWORD dwFirstHelp;
//
// Since WINLOGON is multi-threaded and will call this routine in
// order to service remote performance queries, this library
// must keep track of how many times it has been opened (i.e.
// how many threads have accessed it). the registry routines will
// limit access to the initialization routine to only one thread
// at a time so synchronization (i.e. reentrancy) should not be
// a problem
//
if (!dwOpenCount) {
// open Eventlog interface
hEventLog = MonOpenEventLog();
// get counter and help index base values from registry
// Open key to registry entry
// read First Counter and First Help values
// update static data strucutures by adding base to
// offset value in structure.
status = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\Winmgmt\\Performance",
0L,
KEY_READ,
&hKeyDriverPerf);
if (status != ERROR_SUCCESS) {
REPORT_ERROR_DATA (GENPERF_UNABLE_OPEN_DRIVER_KEY, LOG_ERROR,
&status, sizeof(status));
// this is fatal, if we can't get the base values of the
// counter or help names, then the names won't be available
// to the requesting application so there's not much
// point in continuing.
goto OpenExitPoint;
}
size = sizeof (DWORD);
status = RegQueryValueEx(
hKeyDriverPerf,
"First Counter",
0L,
&type,
(LPBYTE)&dwFirstCounter,
&size);
if (status != ERROR_SUCCESS) {
REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_COUNTER, LOG_ERROR,
&status, sizeof(status));
// this is fatal, if we can't get the base values of the
// counter or help names, then the names won't be available
// to the requesting application so there's not much
// point in continuing.
goto OpenExitPoint;
}
size = sizeof (DWORD);
status = RegQueryValueEx(
hKeyDriverPerf,
"First Help",
0L,
&type,
(LPBYTE)&dwFirstHelp,
&size);
if (status != ERROR_SUCCESS) {
REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_HELP, LOG_ERROR,
&status, sizeof(status));
// this is fatal, if we can't get the base values of the
// counter or help names, then the names won't be available
// to the requesting application so there's not much
// point in continuing.
goto OpenExitPoint;
}
// Set some of the static information into the structure
RegDataDefinition.RegObjectType.ObjectNameTitleIndex += dwFirstCounter;
RegDataDefinition.RegObjectType.ObjectHelpTitleIndex += dwFirstHelp;
for (x=0; x<MAXVALUES; x++)
{
RegDataDefinition.Value[x].CounterNameTitleIndex += dwFirstCounter;
RegDataDefinition.Value[x].CounterHelpTitleIndex += dwFirstHelp;
}
RegCloseKey (hKeyDriverPerf); // close key to registry
bInitOK = TRUE; // ok to use this function
}
dwOpenCount++; // increment OPEN counter
status = ERROR_SUCCESS; // for successful exit
OpenExitPoint:
return status;
}
DWORD APIENTRY
CollectWmiPerformanceData(
IN LPWSTR lpValueName,
IN OUT LPVOID *lppData,
IN OUT LPDWORD lpcbTotalBytes,
IN OUT LPDWORD lpNumObjectTypes
)
/*++
Routine Description:
This routine will return the data for the WINMGMT counters.
Arguments:
IN LPWSTR lpValueName
pointer to a wide character string passed by registry.
IN OUT LPVOID *lppData
IN: pointer to the address of the buffer to receive the completed
PerfDataBlock and subordinate structures. This routine will
append its data to the buffer starting at the point referenced
by *lppData.
OUT: points to the first byte after the data structure added by this
routine. This routine updated the value at lppdata after appending
its data.
IN OUT LPDWORD lpcbTotalBytes
IN: the address of the DWORD that tells the size in bytes of the
buffer referenced by the lppData argument
OUT: the number of bytes added by this routine is writted to the
DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes
IN: the address of the DWORD to receive the number of objects added
by this routine
OUT: the number of objects added by this routine is writted to the
DWORD pointed to by this argument
Return Value:
ERROR_MORE_DATA if buffer passed is too small to hold data
any error conditions encountered are reported to the event log if
event logging is enabled.
ERROR_SUCCESS if success or any other error. Errors, however are
also reported to the event log.
--*/
{
// Variables for reformating the data
ULONG SpaceNeeded;
PERF_COUNTER_BLOCK *pPerfCounterBlock;
REG_DATA_DEFINITION *pRegDataDefinition;
PERF_COUNTER_DEFINITION *pRegCounterDefinition;
DWORD dwQueryType;
DWORD x;
DWORD dwTotSize;
DWORD dwDataOffset;
DWORD Data[MAXVALUES];
// before doing anything else, see if Open went OK
if (!bInitOK) {
// unable to continue because open failed
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
// see if this is a foreign (ie non-nt) computer data request
dwQueryType = GetQueryType (lpValueName);
// REPORT_INFORMATION_DATA (COLLECTION_CALLED, LOG_VERBOSE, lpValueName, wcslen(lpValueName) * 2);
if (dwQueryType == QUERY_FOREIGN) {
// this routine does not service requests for data from
// non-nt computers
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
// See if it is asking for our object.
if (dwQueryType == QUERY_ITEMS) {
if ( !(IsNumberInUnicodeList (RegDataDefinition.RegObjectType.ObjectNameTitleIndex,
lpValueName))) {
// request received for data object not provided by this routine
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_SUCCESS; // yes, this is a successful exit
}
}
// It is asking for our data. Currently, there are no instances and so that returned data has
// the following layout.
// PERF_OBJECT_TYPE describes object, in RegDataDefinition
// PERF_COUNTER_DESCRIPTION describes counter 0, also in RegDataDefinition
// .
// .
// PERF_COUNTER_DESCRIPTION describes counter n, also in RegDataDefinition
// PERF_COUNTER_BLOCK four bytes that has the size of the block and all counters
// counter 0
// .
// .
// counter n
// Format and collect the data
dwTotSize = sizeof(PERF_COUNTER_BLOCK);
for (x=0; x<MAXVALUES; x++) {
dwDataSize[x] = GetData(&Data[x], x);
dwTotSize += dwDataSize[x];
}
SpaceNeeded = sizeof(REG_DATA_DEFINITION) + dwTotSize;
if (*lpcbTotalBytes < SpaceNeeded ) {
*lpcbTotalBytes = (DWORD) 0;
*lpNumObjectTypes = (DWORD) 0;
return ERROR_MORE_DATA;
}
pRegDataDefinition = (REG_DATA_DEFINITION *) *lppData;
// Copy the (constant, initialized) Object type and counter definitions
// to the caller's data buffer
memset(pRegDataDefinition, '\0', SpaceNeeded);
memmove(pRegDataDefinition,
&RegDataDefinition,
sizeof(REG_DATA_DEFINITION));
// Position to header of performance data (just after counter definition)
pPerfCounterBlock = (PERF_COUNTER_BLOCK *) &pRegDataDefinition[1];
// Move the values in
// Set input parameter to point just after performance
// data (a requirement for collectdata routines)
// Total length of returned structure
// Set length of performance data
pRegDataDefinition->RegObjectType.TotalByteLength += dwTotSize;
pRegCounterDefinition = (PERF_COUNTER_DEFINITION *) (
((PBYTE) pRegDataDefinition) + pRegDataDefinition->RegObjectType.HeaderLength);
dwDataOffset = sizeof(PERF_COUNTER_BLOCK);
pPerfCounterBlock->ByteLength = dwTotSize;
for (x=0; x<MAXVALUES; x++) {
pRegCounterDefinition->CounterSize = dwDataSize[x];
pRegCounterDefinition->CounterOffset = dwDataOffset;
memcpy((PBYTE) pPerfCounterBlock + dwDataOffset, &Data[x], dwDataSize[x]);
dwDataOffset += dwDataSize[x];
pRegCounterDefinition++;
}
*lppData = (PBYTE) pRegDataDefinition + pRegDataDefinition->RegObjectType.TotalByteLength;
*lpcbTotalBytes = pRegDataDefinition->RegObjectType.TotalByteLength;
// update arguments for return
*lpNumObjectTypes = 1; // Number of objects returned (objects, not counters)
return ERROR_SUCCESS;
}
DWORD APIENTRY
CloseWmiPerformanceData(
)
/*++
Routine Description:
This routine closes the open handles.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
if (!(--dwOpenCount)) { // when this is the last thread...
MonCloseEventLog();
}
return ERROR_SUCCESS;
}
DWORD APIENTRY WriteCounter(DWORD dwCountNum, DWORD dwCountValue)
/*++
Routine Description:
This routine is where wbemcore.dll calls to set a counter value.
Arguments:
IN DWORD dwCountNum
Counter to be set.
IN DWORD dwCountValue
New counter value.
Return Value:
ERROR_SUCCESS
--*/
{
if(dwCountNum < MAXVALUES)
{
dwCounterValues[dwCountNum] = dwCountValue;
return 0;
}
else
return ERROR_INVALID_PARAMETER;
}
//***************************************************************************
//
// DllRegisterServer
//
// Standard OLE entry point for registering the server.
//
// RETURN VALUES:
//
// S_OK Registration was successful
// E_FAIL Registration failed.
//
//***************************************************************************
HRESULT APIENTRY DllRegisterServer(void)
{
HKEY hKey;
DWORD dw = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\winmgmt\\Performance", 0,
NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if(dw == ERROR_SUCCESS)
{
RegSetValueEx(hKey,"Library", 0, REG_SZ,"wmiperf.dll", 12);
RegSetValueEx(hKey,"Open", 0, REG_SZ, "OpenWmiPerformanceData", 23);
RegSetValueEx(hKey,"Collect", 0, REG_SZ,"CollectWmiPerformanceData", 26);
RegSetValueEx(hKey,"Close", 0, REG_SZ, "CloseWmiPerformanceData", 24);
RegCloseKey(hKey);
}
else
return E_FAIL;
dw = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\wmiperf", 0,
NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if(dw == ERROR_SUCCESS)
{
DWORD dwTemp = 7;
RegSetValueEx(hKey,"EventMessageFile", 0, REG_EXPAND_SZ,
"%systemroot%\\system32\\wmiperf.dll", 34);
RegSetValueEx(hKey,"TypesSupported", 0, REG_DWORD, (BYTE *)&dwTemp, 4);
RegCloseKey(hKey);
}
else
return E_FAIL;
return S_OK;
}
//***************************************************************************
//
// DllUnregisterServer
//
// Standard OLE entry point for unregistering the server.
//
// RETURN VALUES:
//
// S_OK Unregistration was successful
// E_FAIL Unregistration failed.
//
//***************************************************************************
HRESULT APIENTRY DllUnregisterServer(void)
{
DWORD dw = RegDeleteKey(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\winmgmt\\Performance");
if(dw != ERROR_SUCCESS)
return E_FAIL;
dw = RegDeleteKey(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\wmiperf");
if(dw != ERROR_SUCCESS)
return E_FAIL;
else
return S_OK;
}