Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2275 lines
100 KiB

//***************************************************************************
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// PerfAcc.CPP
//
// Windows NT Performance Data Access helper functions
//
// bobw 8-Jub-98 Created for use with NT Perf counters
//
//***************************************************************************
//
#include "wpheader.h"
#include <stdlib.h>
#include "oahelp.inl"
//#include <malloc.h>
// NOTE: Consider reading this from the registry
LONG lExtCounterTestLevel = EXT_TEST_ALL;
LPCWSTR cszFirstCounter = L"First Counter";
LPCWSTR cszLastCounter = L"Last Counter";
//
//
// precompiled security descriptor
// System and NetworkService has full access
//
// since this is RELATIVE, it will work on both IA32 and IA64
//
DWORD g_PrecSD[] = {
0x80040001 , 0x00000044 , 0x00000050 , 0x00000000 ,
0x00000014 , 0x00300002 , 0x00000002 , 0x00140000 ,
0x001f0001 , 0x00000101 , 0x05000000 , 0x00000012 ,
0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 ,
0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 ,
0x00000101 , 0x05000000 , 0x00000014
};
DWORD g_SizeSD = 0;
DWORD g_RuntimeSD[(sizeof(ACL)+sizeof(ACCESS_ALLOWED_ACE)+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+4*(sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)))/sizeof(DWORD)];
typedef
BOOLEAN ( * fnRtlValidRelativeSecurityDescriptor)(
IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
IN ULONG SecurityDescriptorLength,
IN SECURITY_INFORMATION RequiredInformation
);
fnRtlValidRelativeSecurityDescriptor RtlValidRelativeSecurityDescriptor;
//
// Build a SD with owner == This
// group == This
// DACL
// ACE[0] MUTEX_ALL_ACCESS Owner
// ACE[1] MUTEX_ALL_ACCESS System
///////////////////////////////////////////////////////////////////
BOOL
CreateSD( )
{
TOKEN_USER * pToken_User = NULL;
SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = NULL;
PACL pDacl = NULL;
//
// Using GetProcAddress so that nt.h does not have to be included.
// Since WBEM and NT don't get along this function would need to
// be in a separate file.
//
if (! RtlValidRelativeSecurityDescriptor)
{
HMODULE hModule = GetModuleHandleW(L"ntdll.dll");
if (hModule)
{
RtlValidRelativeSecurityDescriptor = (fnRtlValidRelativeSecurityDescriptor)GetProcAddress(hModule,"RtlValidRelativeSecurityDescriptor");
if (! RtlValidRelativeSecurityDescriptor)
{
return FALSE;
}
}
}
HANDLE hToken;
BOOL bRet;
bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken);
if (bRet)
{
DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
pToken_User = (TOKEN_USER *)ALLOCMEM( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if( NULL == pToken_User ){
bRet = FALSE;
goto cleanup;
}
bRet = GetTokenInformation(hToken,TokenUser,pToken_User,dwSize,&dwSize);
if (bRet)
{
SID SystemSid = { SID_REVISION,
1,
SECURITY_NT_AUTHORITY,
SECURITY_LOCAL_SYSTEM_RID
};
PSID pSIDUser = pToken_User->User.Sid;
dwSize = GetLengthSid(pSIDUser);
DWORD dwSids = 2; // Owner and System
DWORD ACLLength = (ULONG) sizeof(ACL) +
(dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwSize + sizeof(SystemSid);
DWORD dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE) + dwSize + dwSize + ACLLength;
pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSizeSD);
if( NULL == pLocalSD ){
bRet = FALSE;
goto cleanup;
}
memset(pLocalSD,0,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION;
pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE;
//SetSecurityDescriptorOwner(pLocalSD,pSIDUser,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE),pSIDUser,dwSize);
pLocalSD->Owner = (DWORD)sizeof(SECURITY_DESCRIPTOR_RELATIVE);
//SetSecurityDescriptorGroup(pLocalSD,pSIDUser,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize,pSIDUser,dwSize);
pLocalSD->Group = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize);
pDacl = (PACL)ALLOCMEM(GetProcessHeap(), HEAP_ZERO_MEMORY, ACLLength);
if( NULL == pDacl ){
bRet = FALSE;
goto cleanup;
}
bRet = InitializeAcl( pDacl,
ACLLength,
ACL_REVISION);
if (bRet)
{
bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&SystemSid);
if (bRet)
{
bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,pSIDUser);
if (bRet)
{
//bRet = SetSecurityDescriptorDacl(pLocalSD,TRUE,pDacl,FALSE);
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize,pDacl,ACLLength);
pLocalSD->Dacl = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize);
if (RtlValidRelativeSecurityDescriptor(pLocalSD,
dwSizeSD,
OWNER_SECURITY_INFORMATION|
GROUP_SECURITY_INFORMATION|
DACL_SECURITY_INFORMATION))
{
g_SizeSD = dwSizeSD;
memcpy(g_RuntimeSD,pLocalSD,dwSizeSD);
}
else
{
bRet = FALSE;
}
}
}
}
}
CloseHandle(hToken);
}
cleanup:
if( NULL != pToken_User ){
FREEMEM(GetProcessHeap(), 0, pToken_User );
}
if( NULL != pLocalSD ){
FREEMEM(GetProcessHeap(), 0, pLocalSD );
}
if( NULL != pDacl ){
FREEMEM(GetProcessHeap(), 0, pDacl );
}
return bRet;
};
//***************************************************************************
//
// HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
//
// This function will create a mutex using the process' security context
//
//***************************************************************************
//
HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
{
BOOL bImpersonating = FALSE;
HANDLE hThreadToken = NULL;
// Determine if we are impersonating
bImpersonating = OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE,
&hThreadToken);
if(bImpersonating)
{
// Determine if we are impersonating
bImpersonating = RevertToSelf();
}
// Create the mutex as using the process token.
HANDLE hRet = OpenMutexW(MUTEX_ALL_ACCESS,FALSE,pwszName);
if (NULL == hRet)
{
SECURITY_ATTRIBUTES sa;
if (0 == g_SizeSD)
{
if (CreateSD())
{
sa.nLength = g_SizeSD;
sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
sa.bInheritHandle = FALSE;
}
else
{
sa.nLength = sizeof(g_PrecSD);
sa.lpSecurityDescriptor = (LPVOID)g_PrecSD;
sa.bInheritHandle = FALSE;
}
}
else
{
sa.nLength = g_SizeSD;
sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
sa.bInheritHandle = FALSE;
}
hRet = CreateMutexW(&sa, FALSE, pwszName);
}
// If code was oringinally impersonating, resume impersonation
if(bImpersonating){
BOOL bRes = SetThreadToken(NULL, hThreadToken);
}
if(hThreadToken)
CloseHandle(hThreadToken);
return hRet;
}
//***************************************************************************
//
// CPerfDataLibrary ::CPerfDataLibrary
//
// This object is used to abstract the perf data library
//
//***************************************************************************
//
CPerfDataLibrary::CPerfDataLibrary (void)
{
pLibInfo = NULL;
memset ((LPVOID)szQueryString, 0, sizeof(szQueryString));
dwRefCount = 0; // number of classes referencing this object
}
CPerfDataLibrary::~CPerfDataLibrary (void)
{
// all libraries should be closed before this is
// destructed
assert (dwRefCount == 0);
assert (pLibInfo == NULL);
}
//***************************************************************************
//
// CPerfObjectAccess::CPerfObjectAccess
//
// This object is used to abstract a data object within a perf library
//
//***************************************************************************
//
CPerfObjectAccess::CPerfObjectAccess ()
{
m_hObjectHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0);
if (m_hObjectHeap == NULL) {
// then just use the process heap
m_hObjectHeap = GetProcessHeap();
}
m_aLibraries.Empty();
lEventLogLevel = LOG_UNDEFINED;
hEventLog = NULL;
}
CPerfObjectAccess::~CPerfObjectAccess ()
{
int nNumLibraries;
int nIdx;
CPerfDataLibrary *pThisLibrary;
// close any lingering libraries
nNumLibraries = m_aLibraries.Size();
for (nIdx = 0; nIdx < nNumLibraries; nIdx++) {
pThisLibrary = (CPerfDataLibrary *)m_aLibraries[nIdx];
CloseLibrary (pThisLibrary);
FREEMEM(m_hObjectHeap, 0, pThisLibrary->pLibInfo);
pThisLibrary->pLibInfo = NULL;
delete pThisLibrary;
}
m_aLibraries.Empty();
if ((m_hObjectHeap != NULL) && (m_hObjectHeap != GetProcessHeap())) {
HeapDestroy (m_hObjectHeap);
}
}
//***************************************************************************
//
// CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
//
// removes a reference to the library that contains this object and closes
// the library when the last reference is removed
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
{
pExtObject pInfo;
LONG lStatus;
assert (pLib != NULL);
assert (pLib->pLibInfo != NULL);
pInfo = pLib->pLibInfo;
assert (pLib->dwRefCount > 0);
if (pLib->dwRefCount > 0) {
pLib->dwRefCount--;
if (pLib->dwRefCount == 0) {
// if there's a close proc to call, then
// call close procedure to close anything that may have
// been allocated by the library
if (pInfo->hMutex != NULL){
lStatus = WaitForSingleObject (
pInfo->hMutex,
pInfo->dwOpenTimeout);
if ( lStatus != WAIT_TIMEOUT ){
if( pInfo->CloseProc != NULL ){
__try{
lStatus = (*pInfo->CloseProc) ();
} __except (EXCEPTION_EXECUTE_HANDLER) {
lStatus = ERROR_INVALID_FUNCTION;
}
}
ReleaseMutex(pInfo->hMutex);
} else {
pInfo->dwLockoutCount++;
}
} else {
lStatus = ERROR_LOCK_FAILED;
}
// then close everything
if (pInfo->hMutex != NULL) {
CloseHandle (pInfo->hMutex);
pInfo->hMutex = NULL;
}
if (pInfo->hLibrary != NULL) {
FreeLibrary (pInfo->hLibrary);
pInfo->hLibrary = NULL;
}
if (pInfo->hPerfKey != NULL) {
RegCloseKey (pInfo->hPerfKey);
pInfo->hPerfKey = NULL;
}
}
}
return pLib->dwRefCount; // returns remaining references
}
//***************************************************************************
//
// CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
//
// OpenExtObjectLibrary
//
// Opens the specified library and looks up the functions used by
// the performance library. If the library is successfully
// loaded and opened then the open procedure is called to initialize
// the object.
//
// This function expects locked and exclusive access to the object while
// it is opening. This must be provided by the calling function.
//
// Arguments:
//
// pObj -- pointer to the object information structure of the
// perf object to close
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
{
DWORD Status = ERROR_SUCCESS;
DWORD dwOpenEvent = 0;
DWORD dwType;
DWORD dwSize;
DWORD dwValue;
// variables used for event logging
DWORD dwDataIndex;
WORD wStringIndex;
DWORD dwRawDataDwords[8];
LPWSTR szMessageArray[8];
UINT nErrorMode;
// check to see if the library has already been opened
if (pObj->hLibrary == NULL) {
// library isn't loaded yet, so
// check to see if this function is enabled
dwType = 0;
dwSize = sizeof (dwValue);
dwValue = 0;
Status = RegQueryValueExW (
pObj->hPerfKey,
cszDisablePerformanceCounters,
NULL,
&dwType,
(LPBYTE)&dwValue,
&dwSize);
if ((Status == ERROR_SUCCESS) &&
(dwType == REG_DWORD) &&
(dwValue == 1)) {
// then DON'T Load this library
Status = ERROR_SERVICE_DISABLED;
} else {
Status = ERROR_SUCCESS;
// go ahead and load it
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
// then load library & look up functions
pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (pObj->hLibrary != NULL) {
const size_t cchSize = 512;
WCHAR buffer[cchSize];
// lookup function names
pObj->OpenProc = (OPENPROC)GetProcAddress(
pObj->hLibrary, pObj->szOpenProcName);
if (pObj->OpenProc == NULL) {
if (lEventLogLevel >= LOG_USER) {
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)Status;
szMessageArray[wStringIndex++] =
ConvertProcName(pObj->szOpenProcName, buffer, cchSize);
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_OPEN_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
if (Status == ERROR_SUCCESS) {
if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
pObj->QueryProc = (QUERYPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
} else {
pObj->CollectProc = (COLLECTPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
}
if (pObj->CollectProc == NULL) {
if (lEventLogLevel >= LOG_USER) {
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)Status;
szMessageArray[wStringIndex++] =
ConvertProcName(pObj->szCollectProcName, buffer, cchSize );
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_COLLECT_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
}
if (Status == ERROR_SUCCESS) {
pObj->CloseProc = (CLOSEPROC)GetProcAddress (
pObj->hLibrary, pObj->szCloseProcName);
if (pObj->CloseProc == NULL) {
if (lEventLogLevel >= LOG_USER) {
Status = GetLastError();
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)Status;
szMessageArray[wStringIndex++] =
ConvertProcName(pObj->szCloseProcName, buffer, cchSize);
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_CLOSE_PROC_NOT_FOUND, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
}
if (Status == ERROR_SUCCESS) {
__try {
// call open procedure to initialize DLL
if (pObj->hMutex != NULL) {
Status = WaitForSingleObject (
pObj->hMutex,
pObj->dwOpenTimeout);
if (Status != WAIT_TIMEOUT){
if( pObj->OpenProc != NULL ) {
Status = (*pObj->OpenProc)(pObj->szLinkageString);
}
ReleaseMutex(pObj->hMutex);
}
else {
pObj->dwLockoutCount++;
}
} else {
Status = ERROR_LOCK_FAILED;
}
// check the result.
if (Status != ERROR_SUCCESS) {
dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
} else {
InterlockedIncrement((LONG *)&pObj->dwOpenCount);
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION;
}
if (Status != ERROR_SUCCESS) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)Status;
szMessageArray[wStringIndex++] =
pObj->szServiceName;
szMessageArray[wStringIndex++] =
pObj->szLibraryName;
ReportEventW (hEventLog,
(WORD)EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
dwOpenEvent, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
if (Status != ERROR_SUCCESS) {
// clear fields
pObj->OpenProc = NULL;
pObj->CollectProc = NULL;
pObj->QueryProc = NULL;
pObj->CloseProc = NULL;
if (pObj->hLibrary != NULL) {
FreeLibrary (pObj->hLibrary);
pObj->hLibrary = NULL;
}
} else {
pObj->llLastUsedTime = GetTimeAsLongLong();
}
} else {
Status = GetLastError();
}
SetErrorMode (nErrorMode);
}
} else {
// else already open so bump the ref count
pObj->llLastUsedTime = GetTimeAsLongLong();
}
if( ERROR_SUCCESS != Status ){
if( ERROR_ACCESS_DENIED == Status ){
InterlockedExchange( (LONG*)&(pObj->ADThreadId),
GetCurrentThreadId() );
}else{
InterlockedIncrement( (LONG*)&(pObj->dwOpenFail) );
}
}else{
InterlockedExchange( (LONG*)&(pObj->dwOpenFail), 0 );
InterlockedExchange( (LONG*)&(pObj->ADThreadId), 0 );
}
return Status;
}
//***************************************************************************
//
// CPerfObjectAccess::AddLibrary (
// IWbemClassObject *pClass,
// IWbemQualifierSet *pClassQualifiers,
// LPCWSTR szRegistryKey,
// DWORD dwPerfIndex)
//
// Adds the library referenced by the class object to the list of
// libraries to call
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::AddLibrary (
IWbemClassObject *pClass,
IWbemQualifierSet *pClassQualifiers,
LPCWSTR szRegistryKey,
DWORD dwPerfIndex)
{
CPerfDataLibrary *pLibEntry = NULL;
LONG Status = ERROR_SUCCESS;
HKEY hServicesKey = NULL;
HKEY hPerfKey = NULL;
LPWSTR szServiceName = NULL;
HKEY hKeyLinkage;
BOOL bUseQueryFn = FALSE;
pExtObject pReturnObject = NULL;
DWORD dwType = 0;
DWORD dwSize = 0;
DWORD dwFlags = 0;
DWORD dwKeep;
DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
DWORD dwObjIndex = 0;
DWORD dwMemBlockSize = sizeof(ExtObject);
DWORD dwLinkageStringLen = 0;
DWORD dwFirstCounter = 2;
DWORD dwLastCounter = 1846;
const size_t cchSize = WBEMPERF_STRING_SIZE;
size_t StorageSizeA = cchSize * 3 * sizeof(CHAR);
size_t StorageSizeW = cchSize * 9 * sizeof(WCHAR);
LPSTR szStorageA = NULL;
LPWSTR szStorageW = NULL;
LPSTR szOpenProcName;
LPSTR szCollectProcName;
LPSTR szCloseProcName;
LPWSTR szLibraryString;
LPWSTR szLibraryExpPath;
LPWSTR mszObjectList;
LPWSTR szLinkageKeyPath;
LPWSTR szLinkageString;
DWORD dwOpenTimeout = 0;
DWORD dwCollectTimeout = 0;
LPWSTR szThisObject;
LPWSTR szThisChar;
LPSTR pNextStringA;
LPWSTR pNextStringW;
LPWSTR szServicePath;
LPWSTR szMutexName;
WCHAR szPID[32];
szStorageW = (LPWSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeW );
szStorageA = (LPSTR)ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, StorageSizeA );
if( NULL == szStorageA || NULL == szStorageW ){
Status = ERROR_OUTOFMEMORY;
goto cleanup;
}else{
pNextStringA = szStorageA;
pNextStringW = szStorageW;
szOpenProcName = pNextStringA;
pNextStringA += cchSize;
szCollectProcName = pNextStringA;
pNextStringA += cchSize;
szCloseProcName = pNextStringA;
szLibraryString = pNextStringW;
pNextStringW += cchSize;
szLibraryExpPath = pNextStringW;
pNextStringW += cchSize;
mszObjectList = pNextStringW;
pNextStringW += cchSize;
szLinkageKeyPath = pNextStringW;
pNextStringW += cchSize;
szLinkageString = pNextStringW;
pNextStringW += cchSize;
szServicePath = pNextStringW;
pNextStringW += cchSize;
szMutexName = pNextStringW;
}
assert(pClass != NULL);
assert(pClassQualifiers != NULL);
UNREFERENCED_PARAMETER(pClassQualifiers);
UNREFERENCED_PARAMETER(pClass);
pLibEntry = new CPerfDataLibrary;
if ((pLibEntry != NULL) && (szRegistryKey != NULL)) {
StringCchCopyW(szServicePath, cchSize, cszHklmServicesKey);
Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
0, KEY_READ, &hServicesKey);
if (Status == ERROR_SUCCESS) {
StringCchCopyW(szServicePath, cchSize, szRegistryKey);
StringCchCatW(szServicePath, cchSize, cszPerformance);
Status = RegOpenKeyExW (hServicesKey, szServicePath,
0, KEY_READ, &hPerfKey);
if (Status == ERROR_SUCCESS) {
szServiceName = (LPWSTR)szRegistryKey;
// read the performance DLL name
dwType = 0;
dwSize = cchSize * sizeof(WCHAR);
Status = RegQueryValueExW (hPerfKey,
cszDLLValue,
NULL,
&dwType,
(LPBYTE)szLibraryString,
&dwSize);
}
}
if (Status == ERROR_SUCCESS) {
if (dwType == REG_EXPAND_SZ) {
// expand any environment vars
dwSize = ExpandEnvironmentStringsW(
szLibraryString,
szLibraryExpPath,
cchSize);
if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_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,
WBEMPERF_STRING_SIZE,
szLibraryExpPath,
NULL);
if ((dwSize > WBEMPERF_STRING_SIZE) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
} else {
Status = ERROR_INVALID_DLL;
}
if (Status == ERROR_SUCCESS) {
// we have the DLL name so get the procedure names
dwType = 0;
dwSize = cchSize * sizeof(CHAR);
Status = RegQueryValueExA (hPerfKey,
caszOpenValue,
NULL,
&dwType,
(LPBYTE)szOpenProcName,
&dwSize);
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = cchSize * sizeof(WCHAR);
Status = RegQueryValueExW (hPerfKey,
cszOpenTimeout,
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) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwFirstCounter);
Status = RegQueryValueExW (hPerfKey,
cszFirstCounter,
NULL,
& dwType,
(LPBYTE) & dwFirstCounter,
& dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwFirstCounter = 2; // assume this is for system base counters
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwLastCounter);
Status = RegQueryValueExW (hPerfKey,
cszLastCounter,
NULL,
& dwType,
(LPBYTE) & dwLastCounter,
& dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwLastCounter = 1846; // assume this is for system base counters
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// get next string
dwType = 0;
dwSize = cchSize * sizeof(CHAR);
Status = RegQueryValueExA (hPerfKey,
caszCloseValue,
NULL,
&dwType,
(LPBYTE)szCloseProcName,
&dwSize);
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_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 = cchSize * sizeof(CHAR);
Status = RegQueryValueExA (hPerfKey,
caszQueryValue,
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 += DWORD_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 = cchSize * sizeof(CHAR);
Status = RegQueryValueExA (hPerfKey,
caszCollectValue,
NULL,
&dwType,
(LPBYTE)szCollectProcName,
&dwSize);
if (Status == ERROR_SUCCESS) {
// add in size of Collect Function Name
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
}
if (Status == ERROR_SUCCESS) {
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwCollectTimeout);
Status = RegQueryValueExW (hPerfKey,
cszCollectTimeout,
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 = cchSize * sizeof(WCHAR);
Status = RegQueryValueExW (hPerfKey,
cszObjListValue,
NULL,
&dwType,
(LPBYTE)mszObjectList,
&dwSize);
if (Status == ERROR_SUCCESS) {
if (dwType != REG_MULTI_SZ) {
size_t cch;
// convert space delimited list to msz
for (szThisChar = mszObjectList, cch = 0;
*szThisChar != 0 && cch < cchSize;
szThisChar++, cch++) {
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) {
DWORD dwDataIndex = 0;
WORD wStringIndex = 0;
DWORD dwRawDataDwords[8];
LPWSTR szMessageArray[8];
dwRawDataDwords[dwDataIndex++] = (DWORD) ERROR_SUCCESS;
szMessageArray[wStringIndex++] = (LPWSTR) cszObjListValue;
szMessageArray[wStringIndex++] = szLibraryString;
szMessageArray[wStringIndex++] = szServicePath;
ReportEventW(hEventLog,
EVENTLOG_WARNING_TYPE,
0,
(DWORD) WBEMPERF_TOO_MANY_OBJECT_IDS,
NULL,
wStringIndex,
dwDataIndex * sizeof(DWORD),
(LPCWSTR *) szMessageArray,
(LPVOID) & dwRawDataDwords[0]);
}
} 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 = RegQueryValueExW (hPerfKey,
cszKeepResident,
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) {
StringCchCopyW( szLinkageKeyPath, cchSize, szServiceName);
StringCchCatW( szLinkageKeyPath, cchSize, cszLinkageKey);
Status = RegOpenKeyExW (
hServicesKey,
szLinkageKeyPath,
0L,
KEY_READ,
&hKeyLinkage);
if (Status == ERROR_SUCCESS) {
// look up export value string
dwSize = sizeof(szLinkageString);
dwType = 0;
Status = RegQueryValueExW (
hKeyLinkage,
cszExportValue,
NULL,
&dwType,
(LPBYTE)&szLinkageString,
&dwSize);
if ((Status != ERROR_SUCCESS) ||
((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
// clear buffer
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 += DWORD_MULTIPLE(dwSize);
}
RegCloseKey (hKeyLinkage);
} else {
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
size_t cbDestSize;
// add in size of service name
dwSize = lstrlenW (szServiceName);
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
cbDestSize = dwMemBlockSize - sizeof(pExtObject);
// allocate and initialize a new ext. object block
pReturnObject = (pExtObject)ALLOCMEM(m_hObjectHeap,
HEAP_ZERO_MEMORY, dwMemBlockSize);
if (pReturnObject != NULL) {
// copy values to new buffer (all others are NULL)
pNextStringA = (LPSTR)&pReturnObject[1];
// copy Open Procedure Name
pReturnObject->szOpenProcName = pNextStringA;
StringCbCopyA( pNextStringA, cbDestSize, szOpenProcName );
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
pReturnObject->dwOpenTimeout = dwOpenTimeout;
// copy collect function or query function, depending
pReturnObject->szCollectProcName = pNextStringA;
StringCbCopyA(pNextStringA, cbDestSize, szCollectProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
pReturnObject->dwCollectTimeout = dwCollectTimeout;
// copy Close Procedure Name
pReturnObject->szCloseProcName = pNextStringA;
StringCbCopyA(pNextStringA, cbDestSize, szCloseProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringA - (PUCHAR)pReturnObject);
// copy Library path
pNextStringW = (LPWSTR)pNextStringA;
pReturnObject->szLibraryName = pNextStringW;
StringCbCopyW(pNextStringW, cbDestSize, szLibraryExpPath);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
// copy Linkage String if there is one
if (*szLinkageString != 0) {
pReturnObject->szLinkageString = pNextStringW;
if( cbDestSize > dwLinkageStringLen ){
memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
// length includes extra NULL char and is in BYTES
pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
}
}
// copy Service name
pReturnObject->szServiceName = pNextStringW;
StringCbCopyW(pNextStringW, cbDestSize, szServiceName);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
cbDestSize = dwMemBlockSize - ((PUCHAR)pNextStringW - (PUCHAR)pReturnObject);
// load flags
if (bUseQueryFn) {
dwFlags |= PERF_EO_QUERY_FUNC;
}
pReturnObject->dwFlags = dwFlags;
pReturnObject->hPerfKey = hPerfKey;
hPerfKey = NULL;
// load Object array
if (dwObjIndex > 0) {
pReturnObject->dwNumObjects = dwObjIndex;
memcpy (pReturnObject->dwObjList,
dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
}
pReturnObject->dwFirstCounter = dwFirstCounter;
pReturnObject->dwLastCounter = dwLastCounter;
pReturnObject->llLastUsedTime = 0;
// create Mutex name
StringCchCopyW(szMutexName, cchSize, szRegistryKey);
StringCchCatW( szMutexName, cchSize, (LPCWSTR)L"_Perf_Library_Lock_PID_");
_ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
StringCchCatW( szMutexName, cchSize, szPID);
// pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
pReturnObject->hMutex = CreateMutexAsProcess(szMutexName);
} else {
Status = ERROR_OUTOFMEMORY;
}
}
if (Status != ERROR_SUCCESS) {
SetLastError (Status);
if (pReturnObject != NULL) {
// release the new block
hPerfKey = pReturnObject->hPerfKey;
FREEMEM (m_hObjectHeap, 0, pReturnObject);
}
} else {
if (pReturnObject != NULL) {
Status = OpenExtObjectLibrary (pReturnObject);
if (Status == ERROR_SUCCESS) {
if (dwPerfIndex != 0) {
// initialize the perf index string
_ultow (dwPerfIndex, pLibEntry->szQueryString, 10);
} else {
StringCchCopyW(pLibEntry->szQueryString,
MAX_PERF_OBJECTS_IN_QUERY_FUNCTION * 10, cszGlobal);
}
// save the pointer to the initialize structure
pLibEntry->pLibInfo = pReturnObject;
m_aLibraries.Add(pLibEntry);
pLibEntry->dwRefCount++;
assert(pLibEntry->dwRefCount == 1);
} else {
// release the new block
hPerfKey = pReturnObject->hPerfKey;
FREEMEM (m_hObjectHeap, 0, pReturnObject);
}
}
}
if (hServicesKey != NULL) RegCloseKey (hServicesKey);
} else { // gets here if pLibEntry == NULL and/or szRegistryKey == NULL
if (pLibEntry == NULL) {
Status = ERROR_OUTOFMEMORY;
}
if (szRegistryKey == NULL) {
Status = ERROR_INVALID_PARAMETER;
}
}
if ((Status != ERROR_SUCCESS) && (pLibEntry != NULL))
delete pLibEntry;
cleanup:
if( hPerfKey != NULL ){
RegCloseKey( hPerfKey );
}
FREEMEM (m_hObjectHeap, 0, szStorageA );
FREEMEM (m_hObjectHeap, 0, szStorageW );
return Status;
}
//***************************************************************************
//
// CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
//
// Adds the specified WBEM performance object class and any required library
// entries to the access object.
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
{
CPerfDataLibrary *pLibEntry = NULL;
CPerfDataLibrary *pThisLibEntry = NULL;
DWORD dwIndex, dwEnd;
LPWSTR szRegistryKey = NULL;
IWbemQualifierSet *pClassQualifiers = NULL;
VARIANT vRegistryKey;
HRESULT hRes;
DWORD dwReturn = ERROR_SUCCESS;
DWORD dwPerfIndex = 0;
CBSTR cbPerfIndex(cszPerfIndex);
CBSTR cbRegistryKey(cszRegistryKey);
if( NULL == (BSTR)cbPerfIndex ||
NULL == (BSTR)cbRegistryKey ){
return ERROR_OUTOFMEMORY;
}
VariantInit (&vRegistryKey);
// get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers);
if( NULL == pClassQualifiers ){
return hRes;
}
// now get the library and procedure names
hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0);
if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
if (szRegistryKey == NULL) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
else {
// now also get the perf index
if (bCatalogQuery) {
// then insert 0 for the perf index to indicate a "GLOBAL"
// query
dwPerfIndex = 0;
} else {
VariantClear (&vRegistryKey);
hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0);
if (hRes == 0) {
dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
} else {
// unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND;
}
}
}
} else {
// unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND;
}
if (pClassQualifiers != NULL) pClassQualifiers->Release();
if (dwReturn == ERROR_SUCCESS) {
// find matching library in the array
dwEnd = m_aLibraries.Size();
if (dwEnd > 0) {
// walk down the list of libraries
for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
// see if this library entry is good enough to keep
// The library is assumed to be a match if the
// lib. name and all proc's are the same.
pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
assert (pThisLibEntry != NULL); // it should have been removed!
// make sure it's complete
assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
pLibEntry = pThisLibEntry;
break;
} else {
// wrong library
// so continue
}
}
}
if (pLibEntry == NULL) {
// add this class & it's library to the list
dwReturn = AddLibrary (pClass, pClassQualifiers, szRegistryKey, dwPerfIndex);
} else {
WCHAR wszNewIndex[WBEMPERF_STRING_SIZE];
pLibEntry->dwRefCount++;
_ultow (dwPerfIndex, wszNewIndex, 10);
if (!IsNumberInUnicodeList (dwPerfIndex, pLibEntry->szQueryString)) {
// then add it to the list
StringCchCatW(pLibEntry->szQueryString,
MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, cszSpace);
StringCchCatW(pLibEntry->szQueryString,
MAX_PERF_OBJECTS_IN_QUERY_FUNCTION*10, wszNewIndex);
}
}
}
if (szRegistryKey != NULL) delete szRegistryKey;
VariantClear(&vRegistryKey);
return dwReturn;
}
//***************************************************************************
//
// CPerfObjectAccess::CollectData (LPBYTE pBuffer,
// LPDWORD pdwBufferSize, LPWSTR pszItemList)
//
// Collects data from the perf objects and libraries added to the access
// object
//
// Inputs:
//
// pBuffer - pointer to start of data block
// where data is being collected
//
// pdwBufferSize - pointer to size of data buffer
//
// pszItemList - string to pass to ext DLL
//
// Outputs:
//
// *lppDataDefinition - set to location for next Type
// Definition if successful
//
// Returns:
//
// 0 if successful, else Win 32 error code of failure
//
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::CollectData (LPBYTE pBuffer, LPDWORD pdwBufferSize, LPWSTR pszItemList)
{
LPWSTR lpValueName = NULL;
LPBYTE lpData = pBuffer;
LPDWORD lpcbData = pdwBufferSize;
LPVOID lpDataDefinition = NULL;
DWORD Win32Error=ERROR_SUCCESS; // Failure code
DWORD BytesLeft;
DWORD NumObjectTypes;
LPVOID lpExtDataBuffer = NULL;
LPVOID lpCallBuffer = NULL;
LPVOID lpLowGuardPage = NULL;
LPVOID lpHiGuardPage = NULL;
LPVOID lpEndPointer = NULL;
LPVOID lpBufferBefore = NULL;
LPVOID lpBufferAfter = NULL;
LPDWORD lpCheckPointer;
LARGE_INTEGER liStartTime, liEndTime, liWaitTime;
pExtObject pThisExtObj = NULL;
BOOL bGuardPageOK;
BOOL bBufferOK;
BOOL bException;
BOOL bUseSafeBuffer;
BOOL bUnlockObjData = FALSE;
LPWSTR szMessageArray[8];
DWORD dwRawDataDwords[8]; // raw data buffer
DWORD dwDataIndex;
WORD wStringIndex;
LONG lReturnValue = ERROR_SUCCESS;
LONG lInstIndex;
PERF_OBJECT_TYPE *pObject, *pNextObject;
PERF_INSTANCE_DEFINITION *pInstance;
PERF_DATA_BLOCK *pPerfData;
BOOL bForeignDataBuffer;
BOOL bCheckThisService;
DWORD dwItemsInList = 0;
DWORD dwIndex, dwEntry;
CPerfDataLibrary *pThisLib;
liStartTime.QuadPart = 0;
liEndTime.QuadPart = 0;
if (lExtCounterTestLevel < EXT_TEST_NOMEMALLOC) {
bUseSafeBuffer = TRUE;
} else {
bUseSafeBuffer = FALSE;
}
if (lReturnValue == ERROR_SUCCESS) {
if (*pdwBufferSize > (sizeof(PERF_DATA_BLOCK) *2)) {
MonBuildPerfDataBlock(
(PERF_DATA_BLOCK *)pBuffer,
&lpDataDefinition,
0,0);
dwItemsInList = m_aLibraries.Size();
} else {
lReturnValue = ERROR_MORE_DATA;
dwItemsInList = 0;
}
if (dwItemsInList > 0) {
for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
pThisLib = (CPerfDataLibrary *)m_aLibraries[dwEntry];
assert (pThisLib != NULL);
bCheckThisService = FALSE;
pThisExtObj = pThisLib->pLibInfo;
if (pszItemList == NULL) {
// use the one for this library
lpValueName = pThisLib->szQueryString;
} else {
// use the one passed by the caller
lpValueName = pszItemList;
}
if (lpValueName == NULL) {
lpValueName = (LPWSTR) cszGlobal;
}
// convert timeout value
liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
// initialize values to pass to the extensible counter function
NumObjectTypes = 0;
BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData));
bException = FALSE;
if (lstrcmpiW(lpValueName, cszGlobal) == 0 || lstrcmpiW(lpValueName, cszCostly) == 0) {
bCheckThisService = TRUE;
}
else {
LPWSTR szThisChar;
LPWSTR szThisObject = NULL;
DWORD dwThisObject;
DWORD dwIndex;
for (szThisChar = lpValueName; * szThisChar != L'\0'; szThisChar ++) {
if (* szThisChar == L' ') {
if (szThisObject == NULL) {
continue;
}
else {
* szThisChar = L'\0';
dwThisObject = wcstoul(szThisObject, NULL, 0);
szThisObject = NULL;
* szThisChar = L' ';
for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) {
if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) {
bCheckThisService = TRUE;
break;
}
}
if (! bCheckThisService) {
if (dwThisObject >= pThisExtObj->dwFirstCounter
&& dwThisObject <= pThisExtObj->dwLastCounter) {
bCheckThisService = TRUE;
}
}
if (bCheckThisService) break;
}
}
else if (szThisObject == NULL) {
szThisObject = szThisChar;
}
}
if (! bCheckThisService && szThisObject != NULL) {
dwThisObject = wcstoul(szThisObject, NULL, 0);
szThisObject = NULL;
for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex ++) {
if (pThisExtObj->dwObjList[dwIndex] == dwThisObject) {
bCheckThisService = TRUE;
break;
}
}
if (! bCheckThisService) {
if (dwThisObject >= pThisExtObj->dwFirstCounter
&& dwThisObject <= pThisExtObj->dwLastCounter) {
bCheckThisService = TRUE;
}
}
}
}
if (! bCheckThisService) continue;
if (pThisExtObj->hLibrary == NULL) {
// lock library object
if (pThisExtObj->hMutex != NULL) {
Win32Error = WaitForSingleObject (
pThisExtObj->hMutex,
pThisExtObj->dwCollectTimeout);
if (Win32Error != WAIT_TIMEOUT) {
Win32Error = ERROR_INVALID_ACCESS;
// if necessary, open the library
if (pThisExtObj->hLibrary == NULL) {
// make sure the library is open
if( pThisExtObj->dwOpenFail == 0 &&
GetCurrentThreadId() != pThisExtObj->ADThreadId ){
Win32Error = OpenExtObjectLibrary(pThisExtObj);
}
}
ReleaseMutex (pThisExtObj->hMutex);
if( ERROR_SUCCESS != Win32Error ){
// assume error has been posted
continue;
}
} else {
pThisExtObj->dwLockoutCount++;
}
} else {
Win32Error = ERROR_LOCK_FAILED;
}
} else {
// library should be ready to use
}
// allocate a local block of memory to pass to the
// extensible counter function.
if (bUseSafeBuffer) {
lpExtDataBuffer = ALLOCMEM (m_hObjectHeap,
HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE));
} else {
lpExtDataBuffer =
lpCallBuffer = lpDataDefinition;
}
if (lpExtDataBuffer != NULL) {
if (bUseSafeBuffer) {
// set buffer pointers
lpLowGuardPage = lpExtDataBuffer;
lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
lpBufferBefore = lpCallBuffer;
lpBufferAfter = NULL;
// initialize GuardPage Data
memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
}
__try {
//
// Collect data from extesible objects
//
bUnlockObjData = FALSE;
if (pThisExtObj->hMutex != NULL) {
Win32Error = WaitForSingleObject (
pThisExtObj->hMutex,
pThisExtObj->dwCollectTimeout);
if ( Win32Error != WAIT_TIMEOUT ){
if( pThisExtObj->CollectProc != NULL) {
bUnlockObjData = TRUE;
QueryPerformanceCounter (&liStartTime);
Win32Error = (*pThisExtObj->CollectProc) (
lpValueName,
&lpCallBuffer,
&BytesLeft,
&NumObjectTypes);
QueryPerformanceCounter (&liEndTime);
pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
}
ReleaseMutex (pThisExtObj->hMutex);
bUnlockObjData = FALSE;
} else {
pThisExtObj->dwLockoutCount++;
}
} else {
Win32Error = ERROR_LOCK_FAILED;
}
if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
// increment perf counters
InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
pThisExtObj->llElapsedTime +=
liEndTime.QuadPart - liStartTime.QuadPart;
if (bUseSafeBuffer) {
// a data buffer was returned and
// the function returned OK so see how things
// turned out...
//
lpBufferAfter = lpCallBuffer;
//
// check for buffer corruption here
//
bBufferOK = TRUE; // assume it's ok until a check fails
//
if (lExtCounterTestLevel <= EXT_TEST_BASIC) {
//
// check 1: bytes left should be the same as
// new data buffer ptr - orig data buffer ptr
//
if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
if (lEventLogLevel >= LOG_DEBUG) {
// issue WARNING, that bytes left param is incorrect
// load data for eventlog message
// since this error is correctable (though with
// some risk) this won't be reported at LOG_USER
// level
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] = BytesLeft;
dwRawDataDwords[dwDataIndex++] =
(DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
ReportEventW (hEventLog,
EVENTLOG_WARNING_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_BUFFER_POINTER_MISMATCH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
// we'll keep the buffer, since the returned bytes left
// value is ignored anyway, in order to make the
// rest of this function work, we'll fix it here
BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
}
//
// check 2: buffer after ptr should be < hi Guard page ptr
//
if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) {
// see if they exceeded the allocated memory
if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
// this is very serious since they've probably trashed
// the heap by overwriting the heap sig. block
// issue ERROR, buffer overrun
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_HEAP_ERROR, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
} else {
// issue ERROR, buffer overrun
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] =
(DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_BUFFER_OVERFLOW, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
bBufferOK = FALSE;
// since the DLL overran the buffer, the buffer
// must be too small (no comments about the DLL
// will be made here) so the status will be
// changed to ERROR_MORE_DATA and the function
// will return.
Win32Error = ERROR_MORE_DATA;
}
//
// check 3: check lo guard page for corruption
//
if (bBufferOK) {
bGuardPageOK = TRUE;
for (lpCheckPointer = (LPDWORD)lpLowGuardPage;
lpCheckPointer < (LPDWORD)lpBufferBefore;
lpCheckPointer++) {
if (*lpCheckPointer != GUARD_PAGE_DWORD) {
bGuardPageOK = FALSE;
break;
}
}
if (!bGuardPageOK) {
// issue ERROR, Lo Guard Page corrupted
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
bBufferOK = FALSE;
}
}
//
// check 4: check hi guard page for corruption
//
if (bBufferOK) {
bGuardPageOK = TRUE;
for (lpCheckPointer = (LPDWORD)lpHiGuardPage;
lpCheckPointer < (LPDWORD)lpEndPointer;
lpCheckPointer++) {
if (*lpCheckPointer != GUARD_PAGE_DWORD) {
bGuardPageOK = FALSE;
break;
}
}
if (!bGuardPageOK) {
// issue ERROR, Hi Guard Page corrupted
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
bBufferOK = FALSE;
}
}
//
if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) {
//
// Internal consistency checks
//
//
// Check 5: Check object length field values
//
// first test to see if this is a foreign
// computer data block or not
//
pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
if ((pPerfData->Signature[0] == (WCHAR)'P') &&
(pPerfData->Signature[1] == (WCHAR)'E') &&
(pPerfData->Signature[2] == (WCHAR)'R') &&
(pPerfData->Signature[3] == (WCHAR)'F')) {
// if this is a foreign computer data block, then the
// first object is after the header
pObject = (PERF_OBJECT_TYPE *) (
(LPBYTE)pPerfData + pPerfData->HeaderLength);
bForeignDataBuffer = TRUE;
} else {
// otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
bForeignDataBuffer = FALSE;
}
// go to where the pointers say the end of the
// buffer is and then see if it's where it
// should be
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
pObject->TotalByteLength);
}
if ((LPBYTE)pObject != (LPBYTE)lpCallBuffer) {
// then a length field is incorrect. This is FATAL
// since it can corrupt the rest of the buffer
// and render the buffer unusable.
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_INCORRECT_OBJECT_LENGTH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
bBufferOK = FALSE;
}
//
// Test 6: Test instance field size values
//
if (bBufferOK) {
// set object pointer
if (bForeignDataBuffer) {
pObject = (PERF_OBJECT_TYPE *) (
(LPBYTE)pPerfData + pPerfData->HeaderLength);
} else {
// otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
}
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
pObject->TotalByteLength);
if (pObject->NumInstances != PERF_NO_INSTANCES) {
pInstance = (PERF_INSTANCE_DEFINITION *)
((LPBYTE)pObject + pObject->DefinitionLength);
lInstIndex = 0;
while (lInstIndex < pObject->NumInstances) {
PERF_COUNTER_BLOCK *pCounterBlock;
pCounterBlock = (PERF_COUNTER_BLOCK *)
((PCHAR) pInstance + pInstance->ByteLength);
pInstance = (PERF_INSTANCE_DEFINITION *)
((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
lInstIndex++;
}
if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
bBufferOK = FALSE;
}
}
if (!bBufferOK) {
break;
} else {
pObject = pNextObject;
}
}
if (!bBufferOK) {
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_INCORRECT_INSTANCE_LENGTH, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
}
}
}
}
}
//
// if all the tests pass,then copy the data to the
// original buffer and update the pointers
if (bBufferOK) {
RtlMoveMemory (lpDataDefinition,
lpBufferBefore,
BytesLeft); // returned buffer size
} else {
NumObjectTypes = 0; // since this buffer was tossed
BytesLeft = 0; // reset the size value since the buffer wasn't used
}
} else {
// function already copied data to caller's buffer
// so no further action is necessary
}
lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
} else {
if (Win32Error != ERROR_SUCCESS) {
InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
}
if (bUnlockObjData) {
ReleaseMutex (pThisExtObj->hMutex);
}
NumObjectTypes = 0; // clear counter
}// end if function returned successfully
} __except (EXCEPTION_EXECUTE_HANDLER) {
Win32Error = GetExceptionCode();
InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
bException = TRUE;
if (bUnlockObjData) {
ReleaseMutex (pThisExtObj->hMutex);
bUnlockObjData = FALSE;
}
}
if (bUseSafeBuffer) {
FREEMEM (m_hObjectHeap, 0, lpExtDataBuffer);
}
} else {
// unable to allocate memory so set error value
Win32Error = ERROR_OUTOFMEMORY;
} // end if temp buffer allocated successfully
//
// Update the count of the number of object types
//
((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
if ( Win32Error != ERROR_SUCCESS) {
if (bException ||
!((Win32Error == ERROR_MORE_DATA) ||
(Win32Error == WAIT_TIMEOUT))) {
// inform on exceptions & illegal error status only
if (lEventLogLevel >= LOG_USER) {
// load data for eventlog message
dwDataIndex = wStringIndex = 0;
dwRawDataDwords[dwDataIndex++] = Win32Error;
szMessageArray[wStringIndex++] =
pThisExtObj->szServiceName;
szMessageArray[wStringIndex++] =
pThisExtObj->szLibraryName;
ReportEventW (hEventLog,
EVENTLOG_ERROR_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_COLLECT_PROC_EXCEPTION, // event,
NULL, // SID (not used),
wStringIndex, // number of strings
dwDataIndex*sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPVOID)&dwRawDataDwords[0]); // raw data
} else {
// don't report
}
}
// the ext. dll is only supposed to return:
// ERROR_SUCCESS even if it encountered a problem, OR
// ERROR_MODE_DATA if the buffer was too small.
// if it's ERROR_MORE_DATA, then break and return the
// error now, since it'll just be returned again and again.
if (Win32Error == ERROR_MORE_DATA) {
lReturnValue = Win32Error;
break;
}
}
} // end for each object
} // else an error occurred so unable to call functions
((PPERF_DATA_BLOCK) lpData)->TotalByteLength = (DWORD)
((LPBYTE)lpDataDefinition - (LPBYTE)lpData);
}
return lReturnValue;
}
//***************************************************************************
//
// CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
//
// removes the class from the access object
//
//***************************************************************************
//
DWORD
CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
{
CPerfDataLibrary *pLibEntry = NULL;
CPerfDataLibrary *pThisLibEntry = NULL;
DWORD dwIndex = 0;
DWORD dwEnd;
LPWSTR szRegistryKey = NULL;
IWbemQualifierSet *pClassQualifiers = NULL;
VARIANT vRegistryKey;
HRESULT hRes;
DWORD dwReturn = ERROR_SUCCESS;
DWORD dwPerfIndex;
CBSTR cbPerfIndex(cszPerfIndex);
CBSTR cbRegistryKey(cszRegistryKey);
if( NULL == (BSTR)cbPerfIndex ||
NULL == (BSTR)cbRegistryKey ){
return ERROR_OUTOFMEMORY;
}
VariantInit (&vRegistryKey);
// get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers);
if( hRes == 0){
// now get the library and procedure names
hRes = pClassQualifiers->Get( cbRegistryKey, 0, &vRegistryKey, 0);
if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
if (szRegistryKey == NULL) {
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
}
else {
// now also get the perf index
VariantClear (&vRegistryKey);
hRes = pClassQualifiers->Get( cbPerfIndex, 0, &vRegistryKey, 0);
if (hRes == 0) {
dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
} else {
// unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND;
}
}
} else {
// unable to find NtPerfLibrary entry
dwReturn = ERROR_FILE_NOT_FOUND;
}
if (pClassQualifiers != NULL) pClassQualifiers->Release();
if (dwReturn == ERROR_SUCCESS) {
// find matching library in the array
dwEnd = m_aLibraries.Size();
if (dwEnd > 0) {
// walk down the list of libraries
for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
// see if this library entry is good enough to keep
// The library is assumed to be a match if the
// lib. name and all proc's are the same.
pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
assert (pThisLibEntry != NULL); // it should have been removed!
// make sure it's complete
assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
pLibEntry = pThisLibEntry;
break;
} else {
// wrong library
// so continue
}
}
}
if (pLibEntry != NULL) {
// close this class & it's library
dwReturn = CloseLibrary(pLibEntry);
if (dwReturn == 0) {
// then no one wants it
FREEMEM(m_hObjectHeap, 0, pLibEntry->pLibInfo);
pLibEntry->pLibInfo = NULL;
m_aLibraries.RemoveAt(dwIndex);
m_aLibraries.Compress();
delete pLibEntry;
}
dwReturn = ERROR_SUCCESS;
} else {
dwReturn = ERROR_FILE_NOT_FOUND;
}
}
if (szRegistryKey != NULL) delete szRegistryKey;
VariantClear(&vRegistryKey);
}
return dwReturn;
}
BOOL
CPerfObjectAccess::CheckClassExist(LPWSTR wszClassName, IWbemClassObject * pClass)
{
BOOL bExist = TRUE;
HRESULT hRes = S_OK;
IWbemQualifierSet * pClassQualifiers = NULL;
SYSTEMTIME LocalTime;
VARIANT vRegistry;
LPWSTR szRegistry = NULL;
LPWSTR szKey = NULL;
DWORD dwKey;
DWORD dwType;
DWORD dwSize;
DWORD Status;
HKEY hKey = NULL;
ZeroMemory(& LocalTime, sizeof(SYSTEMTIME));
GetLocalTime(& LocalTime);
hRes = pClass->GetQualifierSet(& pClassQualifiers);
if (hRes != S_OK || pClassQualifiers == NULL) {
bExist = FALSE;
goto Cleanup;
}
hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 0, & vRegistry, 0);
if (hRes != S_OK || vRegistry.vt != VT_BSTR) {
bExist = FALSE;
goto Cleanup;
}
dwKey = lstrlenW(V_BSTR(& vRegistry)) + 1;
szRegistry = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, sizeof(WCHAR) * dwKey);
if (szRegistry != NULL) {
StringCchCopyW(szRegistry, dwKey, V_BSTR(& vRegistry));
VariantClear(& vRegistry);
}
else {
VariantClear(& vRegistry);
goto Cleanup;
}
dwKey = lstrlenW(cszHklmServicesKey) + 1 + lstrlenW(szRegistry) + lstrlenW(cszPerformance) + 1;
szKey = (LPWSTR) ALLOCMEM(m_hObjectHeap, HEAP_ZERO_MEMORY, dwKey * sizeof(WCHAR));
if (szKey == NULL) {
goto Cleanup;
}
StringCchPrintfW(szKey, dwKey, L"%ws\\%ws%ws", cszHklmServicesKey, szRegistry, cszPerformance);
Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, & hKey);
if (Status != ERROR_SUCCESS || hKey == NULL || hKey == INVALID_HANDLE_VALUE) {
bExist = FALSE;
goto Cleanup;
}
dwType = 0;
dwSize = sizeof(dwKey);
Status = RegQueryValueExW(hKey, cszFirstCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize);
if (Status != ERROR_SUCCESS || dwType != REG_DWORD) {
bExist = FALSE;
goto Cleanup;
}
dwType = 0;
dwSize = sizeof(dwKey);
Status = RegQueryValueExW(hKey, cszLastCounter, NULL, & dwType, (LPBYTE) & dwKey, & dwSize);
if (Status != ERROR_SUCCESS || dwType != REG_DWORD) {
bExist = FALSE;
goto Cleanup;
}
Cleanup:
if (pClassQualifiers != NULL) pClassQualifiers->Release();
if (szRegistry != NULL) FREEMEM(m_hObjectHeap, 0, szRegistry);
if (szKey != NULL) FREEMEM(m_hObjectHeap, 0, szKey);
if (hKey != NULL && hKey != INVALID_HANDLE_VALUE) RegCloseKey(hKey);
return bExist;
}