503 lines
14 KiB
C
503 lines
14 KiB
C
/*++
|
||
|
||
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;
|
||
}
|