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.
 
 
 
 
 
 

1121 lines
42 KiB

/*++ BUILD Version: 0001 // Increment this if a change has global effects
Copyright (c) 2000 Microsoft Corporation
Module Name:
extinit.c
Abstract:
This file implements all the initialization library routines operating on
extensible performance libraries.
Author:
JeePang
Revision History:
09/27/2000 - JeePang - Moved from perflib.c
--*/
#define UNICODE
//
// Include files
//
#pragma warning(disable:4306)
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntregapi.h>
#include <ntprfctr.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <winperf.h>
#include <rpc.h>
#include "regrpc.h"
#include "ntconreg.h"
#include "prflbmsg.h" // event log messages
#include "perflib.h"
#pragma warning(default:4306)
//
// used for error logging control
#define DEFAULT_ERROR_LIMIT 1000
DWORD dwExtCtrOpenProcWaitMs = OPEN_PROC_WAIT_TIME;
LONG lExtCounterTestLevel = EXT_TEST_UNDEFINED;
PEXT_OBJECT
AllocateAndInitializeExtObject (
HKEY hServicesKey,
HKEY hPerfKey,
PUNICODE_STRING usServiceName
)
/*++
AllocateAndInitializeExtObject
allocates and initializes an extensible object information entry
for use by the performance library.
a pointer to the initialized block is returned if all goes well,
otherwise no memory is allocated and a null pointer is returned.
The calling function must close the open handles and free this
memory block when it is no longer needed.
Arguments:
hServicesKey -- open registry handle to the
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services hey
hPerfKey -- the open registry key to the Performance sub-key under
the selected service
szServiceName -- The name of the service
--*/
{
LONG Status;
HKEY hKeyLinkage;
BOOL bUseQueryFn = FALSE;
PEXT_OBJECT pReturnObject = NULL;
DWORD dwType;
DWORD dwSize;
DWORD dwFlags = 0;
DWORD dwKeep;
DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
DWORD dwObjIndex = 0;
DWORD dwMemBlockSize = sizeof(EXT_OBJECT);
DWORD dwLinkageStringLen = 0;
DWORD dwErrorLimit;
CHAR szOpenProcName[MAX_PATH];
CHAR szCollectProcName[MAX_PATH];
CHAR szCloseProcName[MAX_PATH];
WCHAR szLibraryString[MAX_PATH];
WCHAR szLibraryExpPath[MAX_PATH];
WCHAR mszObjectList[MAX_PATH];
WCHAR szLinkageKeyPath[MAX_PATH];
LPWSTR szLinkageString = NULL; // max path wasn't enough for some paths
DLL_VALIDATION_DATA DllVD;
FILETIME LocalftLastGoodDllFileDate;
DWORD dwOpenTimeout;
DWORD dwCollectTimeout;
LPWSTR szThisObject;
LPWSTR szThisChar;
LPSTR pNextStringA;
LPWSTR pNextStringW;
WCHAR szMutexName[MAX_PATH];
WCHAR szPID[32];
WORD wStringIndex;
LPWSTR szMessageArray[2];
BOOL bDisable = FALSE;
LPWSTR szServiceName;
// read the performance DLL name
szServiceName = (LPWSTR) usServiceName->Buffer;
dwType = 0;
dwSize = sizeof(szLibraryString);
memset (szLibraryString, 0, sizeof(szLibraryString));
memset (szLibraryString, 0, sizeof(szLibraryExpPath));
LocalftLastGoodDllFileDate.dwLowDateTime = 0;
LocalftLastGoodDllFileDate.dwHighDateTime = 0;
memset (&DllVD, 0, sizeof(DllVD));
dwErrorLimit = DEFAULT_ERROR_LIMIT;
dwCollectTimeout = dwExtCtrOpenProcWaitMs;
dwOpenTimeout = dwExtCtrOpenProcWaitMs;
Status = PrivateRegQueryValueExW (hPerfKey,
DLLValue,
NULL,
&dwType,
(LPBYTE)szLibraryString,
&dwSize);
if (Status == ERROR_SUCCESS) {
if (dwType == REG_EXPAND_SZ) {
// expand any environment vars
dwSize = ExpandEnvironmentStringsW(
szLibraryString,
szLibraryExpPath,
MAX_PATH);
if ((dwSize > MAX_PATH) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
}
} else if (dwType == REG_SZ) {
// look for dll and save full file Path
dwSize = SearchPathW (
NULL, // use standard system search path
szLibraryString,
NULL,
MAX_PATH,
szLibraryExpPath,
NULL);
if ((dwSize > MAX_PATH) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
}
} else {
Status = ERROR_INVALID_DLL;
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
}
if (Status == ERROR_SUCCESS) {
// we have the DLL name so get the procedure names
dwType = 0;
dwSize = sizeof(szOpenProcName);
memset (szOpenProcName, 0, sizeof(szOpenProcName));
Status = PrivateRegQueryValueExA (hPerfKey,
OpenValue,
NULL,
&dwType,
(LPBYTE)szOpenProcName,
&dwSize);
if (((Status != ERROR_SUCCESS) || (szOpenProcName[0] == 0)) &&
(lEventLogLevel >= LOG_USER)) {
if (szServiceName != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
ARG_TYPE_WSTR, Status,
szServiceName, usServiceName->MaximumLength, NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
}
// DebugPrint((1, "No open procedure for %ws %d\n",
// szServiceName, Status));
bDisable = TRUE;
wStringIndex = 0;
szMessageArray[wStringIndex++] = (LPWSTR) L"Open";
szMessageArray[wStringIndex++] = szServiceName;
ReportEvent(hEventLog,
EVENTLOG_ERROR_TYPE,
0,
(DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
NULL,
wStringIndex,
0,
szMessageArray,
NULL);
}
#ifdef DBG
else {
DebugPrint((2, "Found %s for %ws\n",
szOpenProcName, szServiceName));
}
#endif
}
#ifdef DBG
else {
DebugPrint((1, "Invalid DLL found for %ws\n",
szServiceName));
}
#endif
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwOpenTimeout);
Status = PrivateRegQueryValueExW (hPerfKey,
OpenTimeout,
NULL,
&dwType,
(LPBYTE)&dwOpenTimeout,
&dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwOpenTimeout = dwExtCtrOpenProcWaitMs;
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// get next string
dwType = 0;
dwSize = sizeof(szCloseProcName);
memset (szCloseProcName, 0, sizeof(szCloseProcName));
Status = PrivateRegQueryValueExA (hPerfKey,
CloseValue,
NULL,
&dwType,
(LPBYTE)szCloseProcName,
&dwSize);
if (((Status != ERROR_SUCCESS) || (szCloseProcName[0] == 0)) &&
(lEventLogLevel >= LOG_USER)) {
if (szServiceName != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
ARG_TYPE_WSTR, Status,
szServiceName, usServiceName->MaximumLength, NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
}
// DebugPrint((1, "No close procedure for %ws\n",
// szServiceName));
wStringIndex = 0;
szMessageArray[wStringIndex++] = (LPWSTR) L"Close";
szMessageArray[wStringIndex++] = szServiceName;
ReportEvent(hEventLog,
EVENTLOG_ERROR_TYPE,
0,
(DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
NULL,
wStringIndex,
0,
szMessageArray,
NULL);
bDisable = TRUE;
}
#ifdef DBG
else {
DebugPrint((2, "Found %s for %ws\n",
szCloseProcName, szServiceName));
}
#endif
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
// try to look up the query function which is the
// preferred interface if it's not found, then
// try the collect function name. If that's not found,
// then bail
dwType = 0;
dwSize = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
Status = PrivateRegQueryValueExA (hPerfKey,
QueryValue,
NULL,
&dwType,
(LPBYTE)szCollectProcName,
&dwSize);
if (Status == ERROR_SUCCESS) {
// add in size of the Query Function Name
// the size value includes the Term. NULL
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
// get next string
bUseQueryFn = TRUE;
// the query function can support a static object list
// so look it up
} else {
// the QueryFunction wasn't found so look up the
// Collect Function name instead
dwType = 0;
dwSize = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
Status = PrivateRegQueryValueExA (hPerfKey,
CollectValue,
NULL,
&dwType,
(LPBYTE)szCollectProcName,
&dwSize);
if (Status == ERROR_SUCCESS) {
// add in size of Collect Function Name
// the size value includes the Term. NULL
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
}
}
if (((Status != ERROR_SUCCESS) || (szCollectProcName[0] == 0)) &&
(lEventLogLevel >= LOG_USER)) {
if (szServiceName != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
ARG_TYPE_WSTR, Status,
szServiceName, usServiceName->MaximumLength, NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
}
DebugPrint((1, "No collect procedure for %ws\n",
szServiceName));
wStringIndex = 0;
bDisable = TRUE;
szMessageArray[wStringIndex++] = (LPWSTR) L"Collect";
szMessageArray[wStringIndex++] = szServiceName;
ReportEvent(hEventLog,
EVENTLOG_ERROR_TYPE,
0,
(DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
NULL,
wStringIndex,
0,
szMessageArray,
NULL);
}
#ifdef DBG
else {
DebugPrint((2, "Found %s for %ws\n",
szCollectProcName, szServiceName));
}
#endif
if (Status == ERROR_SUCCESS) {
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwCollectTimeout);
Status = PrivateRegQueryValueExW (hPerfKey,
CollectTimeout,
NULL,
&dwType,
(LPBYTE)&dwCollectTimeout,
&dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwCollectTimeout = dwExtCtrOpenProcWaitMs;
Status = ERROR_SUCCESS;
}
}
// get the list of supported objects if provided by the registry
dwType = 0;
dwSize = sizeof(mszObjectList);
memset (mszObjectList, 0, sizeof(mszObjectList));
Status = PrivateRegQueryValueExW (hPerfKey,
ObjListValue,
NULL,
&dwType,
(LPBYTE)mszObjectList,
&dwSize);
if (Status == ERROR_SUCCESS) {
if (dwType != REG_MULTI_SZ) {
// convert space delimited list to msz
for (szThisChar = mszObjectList; *szThisChar != 0; szThisChar++) {
if (*szThisChar == L' ') *szThisChar = L'\0';
}
++szThisChar;
*szThisChar = 0; // add MSZ term Null
}
for (szThisObject = mszObjectList, dwObjIndex = 0;
(*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
szThisObject += lstrlenW(szThisObject) + 1) {
dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
dwObjIndex++;
}
if ((*szThisObject != 0) &&
(lEventLogLevel >= LOG_USER)) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, 0, NULL));
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used
(DWORD)PERFLIB_TOO_MANY_OBJECTS, // event,
NULL, // SID (not used),
0, // number of strings
0, // sizeof raw data
NULL, // message text array
NULL); // raw data
}
} else {
// reset status since not having this is
// not a showstopper
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS) {
dwType = 0;
dwKeep = 0;
dwSize = sizeof(dwKeep);
Status = PrivateRegQueryValueExW (hPerfKey,
KeepResident,
NULL,
&dwType,
(LPBYTE)&dwKeep,
&dwSize);
if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
if (dwKeep == 1) {
dwFlags |= PERF_EO_KEEP_RESIDENT;
} else {
// no change.
}
} else {
// not fatal, just use the defaults.
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
dwType = REG_DWORD;
dwSize = sizeof(DWORD);
PrivateRegQueryValueExW(
hPerfKey,
cszFailureLimit,
NULL,
&dwType,
(LPBYTE)&dwErrorLimit,
&dwSize);
}
}
}
else {
if (szLibraryString != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
ARG_TYPE_WSTR, Status,
szLibraryString, WSTRSIZE(szLibraryString), NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
}
// DebugPrint((1, "Cannot key for %ws. Error=%d\n",
// szLibraryString, Status));
}
if (Status == ERROR_SUCCESS) {
// get Library validation time
dwType = 0;
dwSize = sizeof(DllVD);
Status = PrivateRegQueryValueExW (hPerfKey,
cszLibraryValidationData,
NULL,
&dwType,
(LPBYTE)&DllVD,
&dwSize);
if ((Status != ERROR_SUCCESS) ||
(dwType != REG_BINARY) ||
(dwSize != sizeof (DllVD))){
// then set this entry to be 0
TRACE((WINPERF_DBG_TRACE_INFO),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
&dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
memset (&DllVD, 0, sizeof(DllVD));
// and clear the error
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// get the file timestamp of the last successfully accessed file
dwType = 0;
dwSize = sizeof(LocalftLastGoodDllFileDate);
memset (&LocalftLastGoodDllFileDate, 0, sizeof(LocalftLastGoodDllFileDate));
Status = PrivateRegQueryValueExW (hPerfKey,
cszSuccessfulFileData,
NULL,
&dwType,
(LPBYTE)&LocalftLastGoodDllFileDate,
&dwSize);
if ((Status != ERROR_SUCCESS) ||
(dwType != REG_BINARY) ||
(dwSize != sizeof (LocalftLastGoodDllFileDate))) {
// then set this entry to be Invalid
memset (&LocalftLastGoodDllFileDate, 0xFF, sizeof(LocalftLastGoodDllFileDate));
// and clear the error
TRACE((WINPERF_DBG_TRACE_INFO),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
&dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
lstrcpyW (szLinkageKeyPath, szServiceName);
lstrcatW (szLinkageKeyPath, LinkageKey);
Status = RegOpenKeyExW (
hServicesKey,
szLinkageKeyPath,
0L,
KEY_READ,
&hKeyLinkage);
if (Status == ERROR_SUCCESS) {
// look up export value string
dwSize = 0;
dwType = 0;
Status = PrivateRegQueryValueExW (
hKeyLinkage,
ExportValue,
NULL,
&dwType,
NULL,
&dwSize);
// get size of string
if (((Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA)) ||
((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
dwLinkageStringLen = 0;
szLinkageString = NULL;
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS;
} else {
// allocate buffer
szLinkageString = (LPWSTR)ALLOCMEM(dwSize);
if (szLinkageString != NULL) {
// read string into buffer
dwType = 0;
Status = PrivateRegQueryValueExW (
hKeyLinkage,
ExportValue,
NULL,
&dwType,
(LPBYTE)szLinkageString,
&dwSize);
if ((Status != ERROR_SUCCESS) ||
((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
// clear & release buffer
FREEMEM (szLinkageString);
szLinkageString = NULL;
dwLinkageStringLen = 0;
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS;
} else {
// add size of linkage string to buffer
// the size value includes the Term. NULL
dwLinkageStringLen = dwSize;
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
}
} else {
// clear & release buffer
FREEMEM (szLinkageString);
szLinkageString = NULL;
dwLinkageStringLen = 0;
Status = ERROR_OUTOFMEMORY;
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
&dwSize, sizeof(dwSize), NULL));
}
}
RegCloseKey (hKeyLinkage);
} else {
// not finding a linkage key is not fatal so correct
// status
// clear & release buffer
szLinkageString = NULL;
dwLinkageStringLen = 0;
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// add in size of service name
/* dwSize = lstrlenW (szServiceName);
dwSize += 1;
dwSize *= sizeof(WCHAR);
*/
dwSize = usServiceName->MaximumLength;
dwMemBlockSize += QWORD_MULTIPLE(dwSize);
// allocate and initialize a new ext. object block
pReturnObject = ALLOCMEM (dwMemBlockSize);
if (pReturnObject != NULL) {
// copy values to new buffer (all others are NULL)
pNextStringA = (LPSTR)&pReturnObject[1];
// copy Open Procedure Name
pReturnObject->szOpenProcName = pNextStringA;
lstrcpyA (pNextStringA, szOpenProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = ALIGN_ON_QWORD(pNextStringA);
pReturnObject->dwOpenTimeout = dwOpenTimeout;
// copy collect function or query function, depending
pReturnObject->szCollectProcName = pNextStringA;
lstrcpyA (pNextStringA, szCollectProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = ALIGN_ON_QWORD(pNextStringA);
pReturnObject->dwCollectTimeout = dwCollectTimeout;
// copy Close Procedure Name
pReturnObject->szCloseProcName = pNextStringA;
lstrcpyA (pNextStringA, szCloseProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = ALIGN_ON_QWORD(pNextStringA);
// copy Library path
pNextStringW = (LPWSTR)pNextStringA;
pReturnObject->szLibraryName = pNextStringW;
lstrcpyW (pNextStringW, szLibraryExpPath);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = ALIGN_ON_QWORD(pNextStringW);
// copy Linkage String if there is one
if (szLinkageString != NULL) {
pReturnObject->szLinkageString = pNextStringW;
memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
// length includes extra NULL char and is in BYTES
pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
pNextStringW = ALIGN_ON_QWORD(pNextStringW);
// release the buffer now that it's been copied
FREEMEM (szLinkageString);
szLinkageString = NULL;
}
// copy Service name
pReturnObject->szServiceName = pNextStringW;
lstrcpyW (pNextStringW, szServiceName);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = ALIGN_ON_QWORD(pNextStringW);
// load flags
if (bUseQueryFn) {
dwFlags |= PERF_EO_QUERY_FUNC;
}
pReturnObject->dwFlags = dwFlags;
pReturnObject->hPerfKey = hPerfKey;
pReturnObject->LibData = DllVD; // validation data
pReturnObject->ftLastGoodDllFileDate = LocalftLastGoodDllFileDate;
// the default test level is "all tests"
// if the file and timestamp work out OK, this can
// be reset to the system test level
pReturnObject->dwValidationLevel = EXT_TEST_ALL;
// load Object array
if (dwObjIndex > 0) {
pReturnObject->dwNumObjects = dwObjIndex;
memcpy (pReturnObject->dwObjList,
dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
}
pReturnObject->llLastUsedTime = 0;
// create Mutex name
lstrcpyW (szMutexName, szServiceName);
lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
_ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
lstrcatW (szMutexName, szPID);
pReturnObject->hMutex = CreateMutexW(NULL, FALSE, szMutexName);
pReturnObject->dwErrorLimit = dwErrorLimit;
if ( pReturnObject->hMutex != NULL
&& GetLastError() == ERROR_ALREADY_EXISTS) {
Status = ERROR_SUCCESS;
}
else {
Status = GetLastError();
}
} else {
Status = ERROR_OUTOFMEMORY;
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, dwMemBlockSize, NULL));
}
}
if ((Status == ERROR_SUCCESS) && (lpPerflibSectionAddr != NULL)) {
PPERFDATA_SECTION_HEADER pHead;
DWORD dwEntry;
PPERFDATA_SECTION_RECORD pEntry;
// init perf data section
pHead = (PPERFDATA_SECTION_HEADER)lpPerflibSectionAddr;
pEntry = (PPERFDATA_SECTION_RECORD)lpPerflibSectionAddr;
// get the entry first
// the "0" entry is the header
if (pHead->dwEntriesInUse < pHead->dwMaxEntries) {
dwEntry = ++pHead->dwEntriesInUse;
pReturnObject->pPerfSectionEntry = &pEntry[dwEntry];
lstrcpynW (pReturnObject->pPerfSectionEntry->szServiceName,
pReturnObject->szServiceName, PDSR_SERVICE_NAME_LEN);
} else {
// the list is full so bump the missing entry count
pHead->dwMissingEntries++;
pReturnObject->pPerfSectionEntry = NULL;
}
}
if (Status != ERROR_SUCCESS) {
SetLastError (Status);
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
if (bDisable) {
DisableLibrary(hPerfKey, szServiceName);
}
if (pReturnObject) {
FREEMEM(pReturnObject);
pReturnObject = NULL;
}
if (szLinkageString) {
FREEMEM(szLinkageString);
}
}
return pReturnObject;
}
void
OpenExtensibleObjects (
)
/*++
Routine Description:
This routine will search the Configuration Registry for modules
which will return data at data collection time. If any are found,
and successfully opened, data structures are allocated to hold
handles to them.
The global data access in this section is protected by the
hGlobalDataMutex acquired by the calling function.
Arguments:
None.
successful open.
Return Value:
None.
--*/
{
DWORD dwIndex; // index for enumerating services
ULONG KeyBufferLength; // length of buffer for reading key data
ULONG ValueBufferLength; // length of buffer for reading value data
ULONG ResultLength; // length of data returned by Query call
HANDLE hPerfKey; // Root of queries for performance info
HANDLE hServicesKey; // Root of services
REGSAM samDesired; // access needed to query
NTSTATUS Status; // generally used for Nt call result status
ANSI_STRING AnsiValueData; // Ansi version of returned strings
UNICODE_STRING ServiceName; // name of service returned by enumeration
UNICODE_STRING PathName; // path name to services
UNICODE_STRING PerformanceName; // name of key holding performance data
UNICODE_STRING ValueDataName; // result of query of value is this name
OBJECT_ATTRIBUTES ObjectAttributes; // general use for opening keys
PKEY_BASIC_INFORMATION KeyInformation; // data from query key goes here
WCHAR szServiceName[MAX_PATH];
UNICODE_STRING usServiceName;
LPTSTR szMessageArray[8];
DWORD dwRawDataDwords[8]; // raw data buffer
DWORD dwDataIndex;
WORD wStringIndex;
DWORD dwDefaultValue;
HANDLE hTimeOutEvent;
PEXT_OBJECT pLastObject = NULL;
PEXT_OBJECT pThisObject = NULL;
// Initialize do failure can deallocate if allocated
ServiceName.Buffer = NULL;
KeyInformation = NULL;
ValueDataName.Buffer = NULL;
AnsiValueData.Buffer = NULL;
dwIndex = 0;
RtlInitUnicodeString(&PathName, ExtPath);
RtlInitUnicodeString(&PerformanceName, PerfSubKey);
try {
// get current event log level
dwDefaultValue = LOG_NONE;
Status = GetPerflibKeyValue (
EventLogLevel,
REG_DWORD,
sizeof(DWORD),
(LPVOID)&lEventLogLevel,
sizeof(DWORD),
(LPVOID)&dwDefaultValue);
dwDefaultValue = EXT_TEST_ALL;
Status = GetPerflibKeyValue (
ExtCounterTestLevel,
REG_DWORD,
sizeof(DWORD),
(LPVOID)&lExtCounterTestLevel,
sizeof(DWORD),
(LPVOID)&dwDefaultValue);
dwDefaultValue = OPEN_PROC_WAIT_TIME;
Status = GetPerflibKeyValue (
OpenProcedureWaitTime,
REG_DWORD,
sizeof(DWORD),
(LPVOID)&dwExtCtrOpenProcWaitMs,
sizeof(DWORD),
(LPVOID)&dwDefaultValue);
dwDefaultValue = PERFLIB_TIMING_THREAD_TIMEOUT;
Status = GetPerflibKeyValue (
LibraryUnloadTime,
REG_DWORD,
sizeof(DWORD),
(LPVOID)&dwThreadAndLibraryTimeout,
sizeof(DWORD),
(LPVOID)&dwDefaultValue);
// register as an event log source if not already done.
if (hEventLog == NULL) {
hEventLog = RegisterEventSource (NULL, (LPCWSTR)TEXT("Perflib"));
}
if (ExtensibleObjects == NULL) {
// create a list of the known performance data objects
ServiceName.Length =
ServiceName.MaximumLength = (WORD)(MAX_KEY_NAME_LENGTH +
PerformanceName.MaximumLength +
sizeof(UNICODE_NULL));
ServiceName.Buffer = ALLOCMEM(ServiceName.MaximumLength);
InitializeObjectAttributes(&ObjectAttributes,
&PathName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
samDesired = KEY_READ;
Status = NtOpenKey(&hServicesKey,
samDesired,
&ObjectAttributes);
KeyBufferLength = sizeof(KEY_BASIC_INFORMATION) + MAX_KEY_NAME_LENGTH;
KeyInformation = ALLOCMEM(KeyBufferLength);
ValueBufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
MAX_VALUE_NAME_LENGTH +
MAX_VALUE_DATA_LENGTH;
ValueDataName.MaximumLength = MAX_VALUE_DATA_LENGTH;
ValueDataName.Buffer = ALLOCMEM(ValueDataName.MaximumLength);
AnsiValueData.MaximumLength = MAX_VALUE_DATA_LENGTH/sizeof(WCHAR);
AnsiValueData.Buffer = ALLOCMEM(AnsiValueData.MaximumLength);
//
// Check for successful NtOpenKey and allocation of dynamic buffers
//
if ( NT_SUCCESS(Status) &&
ServiceName.Buffer != NULL &&
KeyInformation != NULL &&
ValueDataName.Buffer != NULL &&
AnsiValueData.Buffer != NULL ) {
dwIndex = 0;
hTimeOutEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
// wait longer than the thread to give the timing thread
// a chance to finish on it's own. This is really just a
// failsafe step.
while (NT_SUCCESS(Status)) {
Status = NtEnumerateKey(hServicesKey,
dwIndex,
KeyBasicInformation,
KeyInformation,
KeyBufferLength,
&ResultLength);
dwIndex++; // next time, get the next key
if( !NT_SUCCESS(Status) ) {
// This is the normal exit: Status should be
// STATUS_NO_MORE_VALUES
break;
}
// Concatenate Service name with "\\Performance" to form Subkey
if ( ServiceName.MaximumLength >=
(USHORT)( KeyInformation->NameLength + sizeof(UNICODE_NULL) ) ) {
ServiceName.Length = (USHORT) KeyInformation->NameLength;
RtlMoveMemory(ServiceName.Buffer,
KeyInformation->Name,
ServiceName.Length);
ServiceName.Buffer[(ServiceName.Length/sizeof(WCHAR))] = 0; // null term
lstrcpyW (szServiceName, ServiceName.Buffer);
RtlInitUnicodeString(&usServiceName, szServiceName);
// zero terminate the buffer if space allows
RtlAppendUnicodeStringToString(&ServiceName,
&PerformanceName);
// Open Service\Performance Subkey
InitializeObjectAttributes(&ObjectAttributes,
&ServiceName,
OBJ_CASE_INSENSITIVE,
hServicesKey,
NULL);
samDesired = KEY_WRITE | KEY_READ; // to be able to disable perf DLL's
Status = NtOpenKey(&hPerfKey,
samDesired,
&ObjectAttributes);
if(! NT_SUCCESS(Status) ) {
samDesired = KEY_READ; // try read only access
Status = NtOpenKey(&hPerfKey,
samDesired,
&ObjectAttributes);
}
if( NT_SUCCESS(Status) ) {
// this has a performance key so read the info
// and add the entry to the list
pThisObject = AllocateAndInitializeExtObject (
hServicesKey, hPerfKey, &usServiceName);
if (pThisObject != NULL) {
if (ExtensibleObjects == NULL) {
// set head pointer
pLastObject =
ExtensibleObjects = pThisObject;
NumExtensibleObjects = 1;
} else {
pLastObject->pNext = pThisObject;
pLastObject = pThisObject;
NumExtensibleObjects++;
}
} else {
if (szServiceName != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, 0,
szServiceName, usServiceName.MaximumLength, NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, 0, 0, NULL));
}
// the object wasn't initialized so toss
// the perf subkey handle.
// otherwise keep it open for later
// use and it will be closed when
// this extensible object is closed
NtClose (hPerfKey);
}
} else {
if (szServiceName != NULL) {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, Status,
szServiceName, usServiceName.MaximumLength, NULL));
}
else {
TRACE((WINPERF_DBG_TRACE_FATAL),
(&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, 0, Status, NULL));
}
// *** NEW FEATURE CODE ***
// unable to open the performance subkey
if (((Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
(lEventLogLevel >= LOG_USER)) ||
(lEventLogLevel >= LOG_DEBUG)) {
// an error other than OBJECT_NOT_FOUND should be
// displayed if error logging is enabled
// if DEBUG level is selected, then write all
// non-success status returns to the event log
//
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] = PerfpDosError(Status);
if (lEventLogLevel >= LOG_DEBUG) {
// if this is DEBUG mode, then log
// the NT status as well.
dwRawDataDwords[dwDataIndex++] =
(DWORD)Status;
}
szMessageArray[wStringIndex++] =
szServiceName;
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE, // error type
0, // category (not used)
(DWORD)PERFLIB_NO_PERFORMANCE_SUBKEY, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
}
Status = STATUS_SUCCESS; // allow loop to continue
}
if (hTimeOutEvent != NULL) NtClose (hTimeOutEvent);
NtClose (hServicesKey);
}
}
} finally {
if ( ServiceName.Buffer )
FREEMEM(ServiceName.Buffer);
if ( KeyInformation )
FREEMEM(KeyInformation);
if ( ValueDataName.Buffer )
FREEMEM(ValueDataName.Buffer);
if ( AnsiValueData.Buffer )
FREEMEM(AnsiValueData.Buffer);
}
}