//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #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