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;
|
|||
|
}
|