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.
1070 lines
32 KiB
1070 lines
32 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 2002.
|
|
//
|
|
// File: perfCI.cxx
|
|
//
|
|
// Contents: Functions for collecting data to Performance Monitor
|
|
//
|
|
// History: 23-March-94 t-joshh Created
|
|
// 10-May-99 dlee Cleanup
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <perfci.hxx>
|
|
|
|
#include "prfutil.hxx"
|
|
#include "perfobj2.hxx"
|
|
|
|
extern FILTER_DATA_DEFINITION FILTERDataDefinition;
|
|
extern CI_DATA_DEFINITION CIDataDefinition;
|
|
|
|
extern BOOL g_fPerfmonCounterHackIsProcessDetached;
|
|
|
|
CReadUserPerfData * g_pReadUserPerfData = 0;
|
|
CReadKernelPerfData * g_pReadKernelPerfData = 0;
|
|
|
|
WCHAR FILTERPerformanceKeyName[] =
|
|
TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentFilter\\Performance");
|
|
WCHAR CIPerformanceKeyName[] =
|
|
TEXT("SYSTEM\\CurrentControlSet\\Services\\ContentIndex\\Performance");
|
|
|
|
WCHAR FirstCounterKeyName [] = TEXT("First Counter");
|
|
WCHAR FirstHelpKeyName [] = TEXT("First Help");
|
|
|
|
const CI_DATA_DEFINITION CIDataDefinitionFixed = {
|
|
{ sizeof(CI_DATA_DEFINITION)+
|
|
CI_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
|
|
// and the size of the actual counter data )
|
|
sizeof(CI_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
|
|
sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
|
|
CIOBJECT, // Object Name Title Index
|
|
0, // Object Name Title
|
|
CIOBJECT, // Object Help Title Index
|
|
0, // Object Help Title
|
|
PERF_DETAIL_NOVICE, // Detail Level
|
|
CI_TOTAL_NUM_COUNTERS, // Number of Counters
|
|
0, // Default Counters
|
|
0, // Num Instances
|
|
0, // Code Page
|
|
{0,0}, // Perf Time
|
|
{0,0} // Perf Freq
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Wordlist
|
|
NUM_WORDLIST,
|
|
0,
|
|
NUM_WORDLIST,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
NUM_WORDLIST_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // PersistentIndex
|
|
NUM_PERSISTENT_INDEX,
|
|
0,
|
|
NUM_PERSISTENT_INDEX,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
NUM_PERSISTENT_INDEX_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Index Size
|
|
INDEX_SIZE,
|
|
0,
|
|
INDEX_SIZE,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
INDEX_SIZE_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Files to-be-filtered
|
|
FILES_TO_BE_FILTERED,
|
|
0,
|
|
FILES_TO_BE_FILTERED,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
FILES_TO_BE_FILTERED_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Number of unique keys
|
|
NUM_UNIQUE_KEY,
|
|
0,
|
|
NUM_UNIQUE_KEY,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
NUM_UNIQUE_KEY_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Running Queries
|
|
RUNNING_QUERIES,
|
|
0,
|
|
RUNNING_QUERIES,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
RUNNING_QUERIES_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Merge Progress
|
|
MERGE_PROGRESS,
|
|
0,
|
|
MERGE_PROGRESS,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
MERGE_PROGRESS_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Number of documents filtered
|
|
DOCUMENTS_FILTERED,
|
|
0,
|
|
DOCUMENTS_FILTERED,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
DOCUMENTS_FILTERED_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Number of unique documents
|
|
NUM_DOCUMENTS,
|
|
0,
|
|
NUM_DOCUMENTS,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
NUM_DOCUMENTS_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Total queries
|
|
TOTAL_QUERIES,
|
|
0,
|
|
TOTAL_QUERIES,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
TOTAL_QUERIES_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Files deferred for filtering (Secondary Q)
|
|
DEFERRED_FILTER_FILES,
|
|
0,
|
|
DEFERRED_FILTER_FILES,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
DEFERRED_FILTER_FILES_OFF
|
|
}
|
|
};
|
|
|
|
const FILTER_DATA_DEFINITION FILTERDataDefinitionFixed = {
|
|
{ sizeof(FILTER_DATA_DEFINITION)+
|
|
FILTER_SIZE_OF_COUNTER_BLOCK, // Total Bytes ( Size of this header, the counter definitions
|
|
// and the size of the actual counter data )
|
|
sizeof(FILTER_DATA_DEFINITION), // Definition length ( This header and the counter definitions )
|
|
sizeof(PERF_OBJECT_TYPE), // Header Length ( This header )
|
|
FILTEROBJECT, // Object Name Title Index
|
|
0, // Object Name Title
|
|
FILTEROBJECT, // Object Help Title Index
|
|
0, // Object Help Title
|
|
PERF_DETAIL_NOVICE, // Detail Level
|
|
FILTER_TOTAL_NUM_COUNTERS, // Number of Counters
|
|
0, // Default Counters
|
|
0, // Num Instances
|
|
0, // Code Page
|
|
{0,0}, // Perf Time
|
|
{0,0} // Perf Freq
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Total Filter Time
|
|
FILTER_TIME_TOTAL,
|
|
0,
|
|
FILTER_TIME_TOTAL,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
FILTER_TIME_TOTAL_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Binding Time for one file
|
|
BIND_TIME,
|
|
0,
|
|
BIND_TIME,
|
|
0,
|
|
-1,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
BIND_TIME_OFF
|
|
},
|
|
{ sizeof(PERF_COUNTER_DEFINITION), // Filter Time
|
|
FILTER_TIME,
|
|
0,
|
|
FILTER_TIME,
|
|
0,
|
|
0,
|
|
PERF_DETAIL_NOVICE,
|
|
PERF_COUNTER_RAWCOUNT,
|
|
sizeof(DWORD),
|
|
FILTER_TIME_OFF
|
|
}
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CloseKey
|
|
//
|
|
// Synopsis: Close the registry key handle
|
|
//
|
|
// Arguments: [hOpenKey] -- Key. NULL if closed.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline void CloseKey ( HKEY hOpenKey )
|
|
{
|
|
if ( 0 != hOpenKey )
|
|
RegCloseKey (hOpenKey); // close key to registry
|
|
}
|
|
|
|
CStaticMutexSem g_mtxQPerf; // Serialization during "ReadUser/KernelPerfData"
|
|
LONG g_cKernelRefs = 0;
|
|
LONG g_cUserRefs = 0;
|
|
UINT g_KernSeqNo; // "CI" sequence number
|
|
UINT g_UserSeqNo; // "Filter" sequence number
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : InitializeFILTERPerformanceData
|
|
//
|
|
// Purpose : Build and initialize the performance data structure and create
|
|
// perfCI.ini file
|
|
//
|
|
// Arguments :
|
|
// [pInstance] -- dummy variable
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
// Note : Must start cidaemon before executing this function
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD InitializeFILTERPerformanceData( LPWSTR pInstance )
|
|
{
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
g_cUserRefs++;
|
|
|
|
if ( g_cUserRefs > 1 )
|
|
return NO_ERROR;
|
|
|
|
//
|
|
// Start with a clean slate. Note that in some cases the final Done() may
|
|
// have been called but the dll wasn't unloaded.
|
|
//
|
|
|
|
RtlCopyMemory( &FILTERDataDefinition,
|
|
&FILTERDataDefinitionFixed,
|
|
sizeof FILTERDataDefinition );
|
|
|
|
//
|
|
// Open the registry which contain the last key's index
|
|
//
|
|
|
|
HKEY hKeyPerf = 0;
|
|
LONG status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
FILTERPerformanceKeyName,
|
|
0L, KEY_READ,
|
|
&hKeyPerf );
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
CloseKey( hKeyPerf );
|
|
PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get the index of the first counter
|
|
//
|
|
|
|
DWORD dwFirstCounter;
|
|
DWORD size = sizeof dwFirstCounter;
|
|
DWORD type;
|
|
status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
|
|
(LPBYTE)&dwFirstCounter, &size);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
|
|
CloseKey( hKeyPerf );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get the index of the first help
|
|
//
|
|
|
|
DWORD dwFirstHelp;
|
|
size = sizeof dwFirstHelp;
|
|
status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
|
|
0L, &type, (LPBYTE)&dwFirstHelp, &size );
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n"));
|
|
CloseKey( hKeyPerf );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Update the index of both title and help of each counter
|
|
//
|
|
|
|
FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex += dwFirstCounter;
|
|
FILTERDataDefinition.FILTERObjectType.ObjectHelpTitleIndex += dwFirstHelp;
|
|
|
|
PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&FILTERDataDefinition
|
|
+ sizeof(PERF_OBJECT_TYPE) );
|
|
|
|
for ( unsigned i = 0;
|
|
i < FILTERDataDefinition.FILTERObjectType.NumCounters;
|
|
i++)
|
|
{
|
|
pTmp->CounterNameTitleIndex += dwFirstCounter;
|
|
pTmp->CounterHelpTitleIndex += dwFirstHelp;
|
|
pTmp++;
|
|
}
|
|
|
|
//
|
|
// Close the registry key
|
|
//
|
|
|
|
CloseKey( hKeyPerf );
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL fNoServer = FALSE;
|
|
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
if ( 0 == g_pReadUserPerfData )
|
|
g_pReadUserPerfData = new CReadUserPerfData;
|
|
|
|
if ( g_pReadUserPerfData->InitForRead() )
|
|
g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
|
|
else
|
|
{
|
|
fNoServer = TRUE;
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
PerfDebugOut((DEB_ITRACE, "InitializeFilterPerformanceData : Done\n" ));
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
|
|
}
|
|
END_CATCH;
|
|
|
|
if ( NO_ERROR != dwErr )
|
|
{
|
|
delete g_pReadUserPerfData;
|
|
g_pReadUserPerfData = 0;
|
|
|
|
// Lie if cisvc isn't running, and Collect() will return no data
|
|
|
|
if ( fNoServer )
|
|
dwErr = NO_ERROR;
|
|
}
|
|
|
|
return dwErr;
|
|
} //InitializeFILTERPerformanceData
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : CollectFILTERPerformanceData
|
|
//
|
|
// Purpose : Collect Performance Data of Content Index to PerfMon
|
|
//
|
|
// Arguments:
|
|
// [lpValueName] -- pointer to a wide character string passed by registry
|
|
//
|
|
// [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.
|
|
//
|
|
// [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 written
|
|
// to the DWORD pointed to by this argument
|
|
//
|
|
// [lpNumObjectTypes] -- 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 written
|
|
// to the DWORD pointed to by this argument
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
// Return : ERROR_MORE_DATA if the size of the input buffer is too small
|
|
// ERROR_SUCCESS if success
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CollectFILTERPerformanceData( LPWSTR lpValueName,
|
|
LPVOID *lppData,
|
|
LPDWORD lpcbTotalBytes,
|
|
LPDWORD lpNumObjectTypes)
|
|
{
|
|
//
|
|
// if initial procedure failed, exit
|
|
//
|
|
if ( 0 == g_pReadUserPerfData || !g_pReadUserPerfData->InitOK())
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS; // yes, this is a successful exit
|
|
}
|
|
|
|
if ( g_pReadUserPerfData->GetSeqNo() != g_UserSeqNo )
|
|
{
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
g_UserSeqNo = g_pReadUserPerfData->GetSeqNo();
|
|
if (!g_pReadUserPerfData->InitForRead())
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS; // yes, this is a successful exit
|
|
}
|
|
}
|
|
|
|
//
|
|
// see if this is a foreign (i.e. non-NT) computer data request
|
|
//
|
|
|
|
DWORD dwQueryType = GetQueryType (lpValueName);
|
|
|
|
if (dwQueryType == QUERY_FOREIGN)
|
|
{
|
|
//
|
|
// this routine does not service requests for data from
|
|
// Non-NT computers
|
|
//
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If the caller only wanted some counter, check if we have them
|
|
//
|
|
|
|
if (dwQueryType == QUERY_ITEMS)
|
|
{
|
|
if ( !(IsNumberInUnicodeList (
|
|
FILTERDataDefinition.FILTERObjectType.ObjectNameTitleIndex,
|
|
lpValueName)))
|
|
{
|
|
//
|
|
// request received for data object not provided by this routine
|
|
//
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether there is enough space allocated in the lppData
|
|
//
|
|
|
|
ULONG ulSpaceNeeded = sizeof(FILTER_DATA_DEFINITION);
|
|
|
|
if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the Data Definition to the buffer first
|
|
//
|
|
|
|
FILTER_DATA_DEFINITION * pFILTERDataDefinition = (FILTER_DATA_DEFINITION *) *lppData;
|
|
|
|
RtlCopyMemory(pFILTERDataDefinition,
|
|
&FILTERDataDefinition,
|
|
sizeof(FILTER_DATA_DEFINITION));
|
|
|
|
PERF_INSTANCE_DEFINITION * pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
|
|
+ sizeof(FILTER_DATA_DEFINITION));
|
|
|
|
PerfDebugOut(( DEB_ITRACE, "No. of Instance %d\n", g_pReadUserPerfData->NumberOfInstance() ));
|
|
|
|
//
|
|
// Check how many instance exist (how many OFS drive have cidaemon running on)
|
|
//
|
|
for ( int i = 0;
|
|
i < g_pReadUserPerfData->NumberOfInstance();
|
|
i++ )
|
|
{
|
|
//
|
|
// Check whether there is enough space
|
|
//
|
|
|
|
UINT uiLen = wcslen(g_pReadUserPerfData->GetInstanceName(i));
|
|
ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
|
|
FILTER_SIZE_OF_COUNTER_BLOCK +
|
|
(4+1+uiLen) * sizeof(WCHAR) );
|
|
|
|
if ( *lpcbTotalBytes < ulSpaceNeeded )
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the instance name with UNICODE_STRING type
|
|
//
|
|
|
|
UNICODE_STRING usName;
|
|
|
|
usName.Length = (USHORT) uiLen * sizeof(WCHAR);
|
|
usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
|
|
usName.Buffer = g_pReadUserPerfData->GetInstanceName(i);
|
|
|
|
PERF_COUNTER_BLOCK * pCounterBlock;
|
|
|
|
MonBuildInstanceDefinition ( pFILTERInstanceDefinition,
|
|
(PVOID *) &pCounterBlock,
|
|
0,
|
|
0,
|
|
PERF_NO_UNIQUE_ID, // use name, not index
|
|
&usName );
|
|
|
|
pCounterBlock->ByteLength = FILTER_SIZE_OF_COUNTER_BLOCK;
|
|
|
|
//
|
|
// Put each counter value into the buffer
|
|
//
|
|
|
|
DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
|
|
|
|
for ( UINT j = 0 ;
|
|
j < FILTERDataDefinition.FILTERObjectType.NumCounters;
|
|
j++)
|
|
{
|
|
*pdwCounter = g_pReadUserPerfData->GetCounterValue( (int)i, (int)j );
|
|
pdwCounter++;
|
|
}
|
|
|
|
//
|
|
// Point to the next location of instance definition
|
|
//
|
|
|
|
pFILTERInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
|
|
}
|
|
|
|
*lppData = (LPVOID) pFILTERInstanceDefinition;
|
|
|
|
//
|
|
// Fill in the number of instances
|
|
//
|
|
|
|
pFILTERDataDefinition->FILTERObjectType.NumInstances = g_pReadUserPerfData->NumberOfInstance();
|
|
|
|
//
|
|
// Number of Object are always 1
|
|
//
|
|
|
|
*lpNumObjectTypes = 1;
|
|
|
|
//
|
|
// Fill in the number of bytes copied including object and counter
|
|
// definition and counter data
|
|
//
|
|
|
|
*lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pFILTERDataDefinition);
|
|
|
|
pFILTERDataDefinition->FILTERObjectType.TotalByteLength = *lpcbTotalBytes;
|
|
|
|
PerfDebugOut((DEB_ITRACE, "CollectFilterPerformanceData : Done\n"));
|
|
|
|
return ERROR_SUCCESS;
|
|
} //CollectFILTERPerformanceData
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : DoneFILTERPerformanceData
|
|
//
|
|
// Purpose : dummy function
|
|
//
|
|
// Argument : none
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD DoneFILTERPerformanceData( void )
|
|
{
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
//
|
|
// A bug in a perfmon dll makes them call this function after we've
|
|
// been process detached! They call us in their process detach, which
|
|
// is well after we've been detached and destroyed our heap.
|
|
//
|
|
|
|
if ( g_fPerfmonCounterHackIsProcessDetached )
|
|
return ERROR_SUCCESS;
|
|
|
|
g_cUserRefs--;
|
|
|
|
if ( 0 == g_cUserRefs )
|
|
{
|
|
delete g_pReadUserPerfData;
|
|
g_pReadUserPerfData = 0;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
} //DoneFILTERPerformanceData
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : InitializeCIPerformanceData
|
|
//
|
|
// Purpose : Build and initialize the performance data structure and create
|
|
// perfCI.ini file
|
|
//
|
|
// Arguments :
|
|
// [pInstance] -- dummy variable
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD InitializeCIPerformanceData( LPWSTR pInstance )
|
|
{
|
|
LONG status;
|
|
HKEY hKeyPerf = 0;
|
|
DWORD size;
|
|
DWORD type;
|
|
DWORD dwFirstCounter;
|
|
DWORD dwFirstHelp;
|
|
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
g_cKernelRefs++;
|
|
|
|
if ( g_cKernelRefs > 1 )
|
|
return NO_ERROR;
|
|
|
|
//
|
|
// Start with a clean slate. Note that in some cases the final Done() may
|
|
// have been called but the dll wasn't unloaded.
|
|
//
|
|
|
|
RtlCopyMemory( &CIDataDefinition,
|
|
&CIDataDefinitionFixed,
|
|
sizeof CIDataDefinition );
|
|
|
|
//
|
|
// Open the registry which contain the last key's index
|
|
//
|
|
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
CIPerformanceKeyName,
|
|
0L, KEY_READ,
|
|
&hKeyPerf );
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
CloseKey( hKeyPerf );
|
|
PerfDebugOut(( DEB_ERROR, "Error in RegOpenKeyEx\n"));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get the index of the first counter
|
|
//
|
|
size = sizeof (dwFirstCounter);
|
|
status = RegQueryValueEx( hKeyPerf, FirstCounterKeyName, 0L, &type,
|
|
(LPBYTE)&dwFirstCounter, &size);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
PerfDebugOut(( DEB_ERROR, "Error in Query First Counter\n"));
|
|
CloseKey( hKeyPerf );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get the index of the first help
|
|
//
|
|
size = sizeof (dwFirstHelp);
|
|
status = RegQueryValueEx( hKeyPerf, FirstHelpKeyName,
|
|
0L, &type, (LPBYTE)&dwFirstHelp, &size );
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
PerfDebugOut(( DEB_ERROR, "Error in Query First Help Key\n" ));
|
|
CloseKey( hKeyPerf );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Update the index of both title and help of each counter
|
|
//
|
|
|
|
CIDataDefinition.CIObjectType.ObjectNameTitleIndex += dwFirstCounter;
|
|
CIDataDefinition.CIObjectType.ObjectHelpTitleIndex += dwFirstHelp;
|
|
|
|
PERF_COUNTER_DEFINITION * pTmp = (PERF_COUNTER_DEFINITION *) ((BYTE *)&CIDataDefinition
|
|
+ sizeof(PERF_OBJECT_TYPE) );
|
|
|
|
for ( unsigned i = 0;
|
|
i < CIDataDefinition.CIObjectType.NumCounters;
|
|
i++)
|
|
{
|
|
pTmp->CounterNameTitleIndex += dwFirstCounter;
|
|
pTmp->CounterHelpTitleIndex += dwFirstHelp;
|
|
pTmp += 1;
|
|
}
|
|
|
|
//
|
|
// Close the registry key
|
|
//
|
|
CloseKey( hKeyPerf );
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL fNoServer = FALSE;
|
|
|
|
CTranslateSystemExceptions translate;
|
|
TRY
|
|
{
|
|
if ( 0 == g_pReadKernelPerfData )
|
|
g_pReadKernelPerfData = new CReadKernelPerfData;
|
|
|
|
BOOL fOK = g_pReadKernelPerfData->InitForRead();
|
|
|
|
if ( fOK )
|
|
g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
|
|
else
|
|
{
|
|
fNoServer = TRUE;
|
|
dwErr = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
PerfDebugOut(( DEB_ITRACE, "InitialCIPerformanceData : Finish\n" ));
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
dwErr = ERROR_CAN_NOT_COMPLETE; // lie here
|
|
}
|
|
END_CATCH;
|
|
|
|
if ( NO_ERROR != dwErr )
|
|
{
|
|
delete g_pReadKernelPerfData;
|
|
g_pReadKernelPerfData = 0;
|
|
|
|
// Lie if cisvc isn't running, and Collect() will return no data
|
|
|
|
if ( fNoServer )
|
|
dwErr = NO_ERROR;
|
|
}
|
|
|
|
return dwErr;
|
|
} //InitializeCIPerformanceData
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : CollectCIPerformanceData
|
|
//
|
|
// Purpose : Collect Performance Data of Content Index to PerfMon
|
|
//
|
|
// Arguments:
|
|
// [lpValueName] -- pointer to a wide character string passed by registry
|
|
//
|
|
// [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.
|
|
//
|
|
// [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 written
|
|
// to the DWORD pointed to by this argument
|
|
//
|
|
// [lpNumObjectTypes] -- 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 written
|
|
// to the DWORD pointed to by this argument
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
// Return : ERROR_MORE_DATA if the size of the input buffer is too small
|
|
// ERROR_SUCCESS if success
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CollectCIPerformanceData( LPWSTR lpValueName,
|
|
LPVOID *lppData,
|
|
LPDWORD lpcbTotalBytes,
|
|
LPDWORD lpNumObjectTypes)
|
|
{
|
|
ULONG ulSpaceNeeded = 0;
|
|
DWORD dwQueryType;
|
|
|
|
//
|
|
// if initial procedure failed, exit
|
|
//
|
|
if ( 0 == g_pReadKernelPerfData || !g_pReadKernelPerfData->InitOK())
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS; // yes, this is a successful exit
|
|
}
|
|
|
|
if ( g_pReadKernelPerfData->GetSeqNo() != g_KernSeqNo )
|
|
{
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
g_pReadKernelPerfData->InitForRead();
|
|
|
|
if (!g_pReadKernelPerfData->InitOK())
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS; // yes, this is a successful exit
|
|
}
|
|
|
|
g_KernSeqNo = g_pReadKernelPerfData->GetSeqNo();
|
|
}
|
|
|
|
//
|
|
// see if this is a foreign (i.e. non-NT) computer data request
|
|
//
|
|
dwQueryType = GetQueryType (lpValueName);
|
|
|
|
if (dwQueryType == QUERY_FOREIGN)
|
|
{
|
|
//
|
|
// this routine does not service requests for data from
|
|
// Non-NT computers
|
|
//
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If the caller only wanted some counter, check if we have them
|
|
//
|
|
if (dwQueryType == QUERY_ITEMS)
|
|
{
|
|
if ( !(IsNumberInUnicodeList(
|
|
CIDataDefinition.CIObjectType.ObjectNameTitleIndex,
|
|
lpValueName)) )
|
|
{
|
|
//
|
|
// request received for data object not provided by this routine
|
|
//
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether there is enough space allocated in the lppData
|
|
//
|
|
|
|
ulSpaceNeeded = sizeof(CI_DATA_DEFINITION);
|
|
|
|
if ( *lpcbTotalBytes < (DWORD) ulSpaceNeeded)
|
|
{
|
|
*lpcbTotalBytes = 0;
|
|
*lpNumObjectTypes = 0;
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the Data Definition to the buffer first
|
|
//
|
|
CI_DATA_DEFINITION * pCIDataDefinition = (CI_DATA_DEFINITION *) *lppData;
|
|
|
|
RtlCopyMemory(pCIDataDefinition,
|
|
&CIDataDefinition,
|
|
sizeof(CI_DATA_DEFINITION));
|
|
|
|
PERF_INSTANCE_DEFINITION * pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)( (BYTE *)*lppData
|
|
+ sizeof(CI_DATA_DEFINITION));
|
|
|
|
PerfDebugOut(( DEB_ITRACE, "*lppData: %#x\n", *lppData ));
|
|
PerfDebugOut(( DEB_ITRACE, "pCIInstanceDefinition: %#x\n", pCIInstanceDefinition ));
|
|
|
|
//
|
|
// Check how many instance exist (how many OFS drive have cidaemon running on)
|
|
//
|
|
for ( int i = 0;
|
|
i < g_pReadKernelPerfData->NumberOfInstance();
|
|
i++ )
|
|
{
|
|
//
|
|
// Check whether there is enough space
|
|
//
|
|
|
|
UINT uiLen = wcslen(g_pReadKernelPerfData->GetInstanceName(i));
|
|
ulSpaceNeeded += ( sizeof(PERF_INSTANCE_DEFINITION) +
|
|
CI_SIZE_OF_COUNTER_BLOCK +
|
|
(4+1+uiLen) * sizeof(WCHAR) );
|
|
|
|
if ( *lpcbTotalBytes < ulSpaceNeeded )
|
|
{
|
|
*lpcbTotalBytes = (DWORD) 0;
|
|
*lpNumObjectTypes = (DWORD) 0;
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the instance name with UNICODE_STRING type
|
|
//
|
|
|
|
UNICODE_STRING usName;
|
|
|
|
usName.Length = (USHORT) uiLen * sizeof(WCHAR);
|
|
usName.MaximumLength = (USHORT) (uiLen+1)*sizeof(WCHAR);
|
|
usName.Buffer = g_pReadKernelPerfData->GetInstanceName(i);
|
|
|
|
PERF_COUNTER_BLOCK * pCounterBlock;
|
|
|
|
MonBuildInstanceDefinition ( pCIInstanceDefinition,
|
|
(PVOID *) &pCounterBlock,
|
|
0,
|
|
0,
|
|
PERF_NO_UNIQUE_ID, // use name, not index
|
|
&usName );
|
|
|
|
pCounterBlock->ByteLength = CI_SIZE_OF_COUNTER_BLOCK;
|
|
|
|
//
|
|
// Refresh the buffer
|
|
//
|
|
g_pReadKernelPerfData->Refresh( i );
|
|
|
|
//
|
|
// Put each counter value into the buffer
|
|
//
|
|
DWORD * pdwCounter = (DWORD *) ((BYTE *)pCounterBlock + sizeof(PERF_COUNTER_BLOCK));
|
|
|
|
for ( UINT j = 0 ;
|
|
j < CIDataDefinition.CIObjectType.NumCounters;
|
|
j++)
|
|
{
|
|
*pdwCounter = g_pReadKernelPerfData->GetCounterValue( (int)j );
|
|
pdwCounter++;
|
|
}
|
|
|
|
//
|
|
// Point to the next location of instance definition
|
|
//
|
|
pCIInstanceDefinition = (PERF_INSTANCE_DEFINITION *)pdwCounter;
|
|
}
|
|
|
|
*lppData = (LPVOID) pCIInstanceDefinition;
|
|
|
|
//
|
|
// Fill in the number of instances
|
|
//
|
|
pCIDataDefinition->CIObjectType.NumInstances = g_pReadKernelPerfData->NumberOfInstance();
|
|
|
|
//
|
|
// Number of Object are always 1
|
|
//
|
|
*lpNumObjectTypes = 1;
|
|
|
|
//
|
|
// Fill in the number of bytes copied including object and counter
|
|
// definition and counter data
|
|
//
|
|
*lpcbTotalBytes = (DWORD) ((BYTE *) *lppData - (BYTE *) pCIDataDefinition);
|
|
|
|
pCIDataDefinition->CIObjectType.TotalByteLength = *lpcbTotalBytes;
|
|
|
|
PerfDebugOut(( DEB_ITRACE, "CollectCIPerformanceData : Done\n" ));
|
|
|
|
Win4Assert( *lpcbTotalBytes == EIGHT_BYTE_MULTIPLE(*lpcbTotalBytes) );
|
|
return ERROR_SUCCESS;
|
|
} //CollectCIPerformanceData
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function : DoneCIPerformanceData
|
|
//
|
|
// Purpose : dummy function
|
|
//
|
|
// Argument : none
|
|
//
|
|
// History : 23-March-94 t-joshh Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD DoneCIPerformanceData( void )
|
|
{
|
|
CLock lock( g_mtxQPerf );
|
|
|
|
//
|
|
// A bug in a perfmon dll makes them call this function after we've
|
|
// been process detached! They call us in their process detach, which
|
|
// is well after we've been detached and destroyed our heap.
|
|
//
|
|
|
|
if ( g_fPerfmonCounterHackIsProcessDetached )
|
|
return ERROR_SUCCESS;
|
|
|
|
g_cKernelRefs--;
|
|
|
|
if ( 0 == g_cKernelRefs )
|
|
{
|
|
delete g_pReadKernelPerfData;
|
|
g_pReadKernelPerfData = 0;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
} //DoneCIPerformanceData
|
|
|