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.
 
 
 
 
 
 

2422 lines
100 KiB

//***************************************************************************
//
// (c) 1998-1999 by Microsoft Corp.
//
// 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;
//
//
// 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( )
{
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)
{
TOKEN_USER * pToken_User;
DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
pToken_User = (TOKEN_USER *)_alloca(dwSize);
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;
SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)_alloca(dwSizeSD);
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);
PACL pDacl = (PACL)_alloca(ACLLength);
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);
}
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)
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();
}
for (DWORD n=0; n < PL_TIMER_NUM_OBJECTS; n++) {
hTimerHandles[n] = NULL;
}
hTimerDataMutex = NULL;
hPerflibTimingThread = NULL;
pTimerItemListHead = NULL;
m_aLibraries.Empty();
lEventLogLevel = LOG_UNDEFINED;
hEventLog = NULL;
}
CPerfObjectAccess::~CPerfObjectAccess ()
{
int nNumLibraries;
int nIdx;
CPerfDataLibrary *pThisLibrary;
if (pTimerItemListHead != NULL) {
DestroyPerflibFunctionTimer();
pTimerItemListHead = NULL;
}
// the DestroyPerflibFunctionTimer should take care of these
// but just in case....
if (hTimerDataMutex != NULL) {
CloseHandle (hTimerDataMutex);
hTimerDataMutex = NULL;
}
if (hPerflibTimingThread != NULL) {
CloseHandle (hPerflibTimingThread);
hPerflibTimingThread = NULL;
}
for (DWORD n=0; n < PL_TIMER_NUM_OBJECTS; n++) {
if (hTimerHandles[n] != NULL) {
CloseHandle (hTimerHandles[n]);
hTimerHandles[n] = NULL;
}
}
// 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);
}
}
//
// Timer functions
//
DWORD
__stdcall
PerflibTimerFunction (
LPVOID pArg
)
/*++
PerflibTimerFunction
Timing thread used to write an event log message if the timer expires.
This thread runs until the Exit event is set or the wait for the
Exit event times out.
While the start event is set, then the timer checks the current events
to be timed and reports on any that have expired. It then sleeps for
the duration of the timing interval after which it checks the status
of the start & exit events to begin the next cycle.
The timing events are added and deleted from the list only by the
StartPerflibFunctionTimer and KillPerflibFunctionTimer functions.
Arguments
pArg -- parent class object
--*/
{
CPerfObjectAccess *pObj = (CPerfObjectAccess *)pArg;
LONG lStatus = ERROR_SUCCESS;
BOOL bKeepTiming = TRUE;
LPOPEN_PROC_WAIT_INFO pLocalInfo;
LPWSTR szMessageArray[2];
DWORD dwData;
if (lStatus == ERROR_SUCCESS) {
while (bKeepTiming) {
// wait for either the start or exit event flags to be set
lStatus = WaitForMultipleObjects (
PL_TIMER_NUM_OBJECTS,
&pObj->hTimerHandles[0],
FALSE, //wait for either one to be set
PERFLIB_TIMING_THREAD_TIMEOUT);
if (lStatus != WAIT_TIMEOUT) {
if ((lStatus - WAIT_OBJECT_0) == PL_TIMER_EXIT_EVENT ) {
// then that's all
bKeepTiming = FALSE;
break;
} else if ((lStatus - WAIT_OBJECT_0) == PL_TIMER_START_EVENT) {
// then the timer is running so wait the interval period
// wait on exit event here to prevent hanging
lStatus = WaitForSingleObject (
pObj->hTimerHandles[PL_TIMER_EXIT_EVENT],
PERFLIB_TIMING_THREAD_TIMEOUT);
if (lStatus == WAIT_TIMEOUT) {
// then the wait time expired without being told
// to terminate the thread so
// now evaluate the list of timed events
// lock the data mutex
lStatus = WaitForSingleObject (
pObj->hTimerDataMutex,
(PERFLIB_TIMER_INTERVAL * 2));
for (pLocalInfo = pObj->pTimerItemListHead;
pLocalInfo != NULL;
pLocalInfo = pLocalInfo->pNext) {
if (pLocalInfo->dwWaitTime != 0) {
if (pLocalInfo->dwWaitTime == 1) {
// then this is the last interval so log error
szMessageArray[0] = pLocalInfo->szServiceName;
szMessageArray[1] = pLocalInfo->szLibraryName;
dwData = pLocalInfo->dwWaitTime * 1000;
ReportEventW (hEventLog,
EVENTLOG_WARNING_TYPE, // error type
0, // category (not used)
(DWORD)WBEMPERF_OPEN_PROC_TIMEOUT, // event,
NULL, // SID (not used),
2, // number of strings
sizeof(DWORD), // sizeof raw data
(LPCWSTR *)szMessageArray, // message text array
(LPBYTE)&dwData); // raw data
}
pLocalInfo->dwWaitTime--;
}
}
ReleaseMutex (pObj->hTimerDataMutex);
} else {
// we've been told to exit so
lStatus = ERROR_SUCCESS;
bKeepTiming = FALSE;
break;
}
} else {
// some unexpected error was returned
assert (FALSE);
}
} else {
// the wait timed out so it's time to go
lStatus = ERROR_SUCCESS;
bKeepTiming = FALSE;
break;
}
}
}
return lStatus;
}
HANDLE
CPerfObjectAccess::StartPerflibFunctionTimer (
IN LPOPEN_PROC_WAIT_INFO pInfo
)
/*++
Starts a timing event by adding it to the list of timing events.
If the timer thread is not running, then the is started as well.
If this is the first event in the list then the Start Event is
set indicating that the timing thread can begin processing timing
event(s).
--*/
{
LONG Status = ERROR_SUCCESS;
LPOPEN_PROC_WAIT_INFO pLocalInfo;
DWORD dwLibNameLen;
DWORD dwBufferLength = sizeof (OPEN_PROC_WAIT_INFO);
HANDLE hReturn = NULL;
if (pInfo == NULL) {
// no required argument
Status = ERROR_INVALID_PARAMETER;
} else {
// check on or create sync objects
// allocate timing events for the timing thread
if (hTimerHandles[PL_TIMER_START_EVENT] == NULL) {
// create the event as NOT signaled since we're not ready to start
hTimerHandles[PL_TIMER_START_EVENT] = CreateEvent (NULL, TRUE, FALSE, NULL);
if (hTimerHandles[PL_TIMER_START_EVENT] == NULL) {
Status = GetLastError();
}
}
if (hTimerHandles[PL_TIMER_EXIT_EVENT] == NULL) {
hTimerHandles[PL_TIMER_EXIT_EVENT] = CreateEvent (NULL, TRUE, FALSE, NULL);
if (hTimerHandles[PL_TIMER_EXIT_EVENT] == NULL) {
Status = GetLastError();
}
}
// create data sync mutex if it hasn't already been created
if (hTimerDataMutex == NULL) {
hTimerDataMutex = CreateMutex (NULL, FALSE, NULL);
if (hTimerDataMutex == NULL) {
Status = GetLastError();
}
}
}
if (Status == ERROR_SUCCESS) {
// continue creating timer entry
if (hPerflibTimingThread != NULL) {
// see if the handle is valid (i.e the thread is alive)
Status = WaitForSingleObject (hPerflibTimingThread, 0);
if (Status == WAIT_OBJECT_0) {
// the thread has terminated so close the handle
CloseHandle (hPerflibTimingThread);
hPerflibTimingThread = NULL;
Status = ERROR_SUCCESS;
} else if (Status == WAIT_TIMEOUT) {
// the thread is still running so continue
Status = ERROR_SUCCESS;
} else {
// some other, probably serious, error
// so pass it on through
}
} else {
// the thread has never been created yet so continue
}
if (hPerflibTimingThread == NULL) {
DWORD hThreadID;
// create the timing thread
assert (pTimerItemListHead == NULL); // there should be no entries, yet
// everything is ready for the timer thread
hPerflibTimingThread = CreateThread (
NULL, 0,
(LPTHREAD_START_ROUTINE)PerflibTimerFunction,
(LPVOID)this, 0, &hThreadID);
assert (hPerflibTimingThread != NULL);
if (hPerflibTimingThread == NULL) {
Status = GetLastError();
}
}
if (Status == ERROR_SUCCESS) {
// compute the length of the required buffer;
dwLibNameLen = (lstrlenW (pInfo->szLibraryName) + 1) * sizeof(WCHAR);
dwBufferLength += dwLibNameLen;
dwBufferLength += (lstrlenW (pInfo->szServiceName) + 1) * sizeof(WCHAR);
dwBufferLength = DWORD_MULTIPLE (dwBufferLength);
pLocalInfo = (LPOPEN_PROC_WAIT_INFO)ALLOCMEM (
m_hObjectHeap, HEAP_ZERO_MEMORY, dwBufferLength);
if (pLocalInfo) {
// copy the arg buffer to the local list
pLocalInfo->szLibraryName = (LPWSTR)&pLocalInfo[1];
lstrcpyW (pLocalInfo->szLibraryName, pInfo->szLibraryName);
pLocalInfo->szServiceName = (LPWSTR)
((LPBYTE)pLocalInfo->szLibraryName + dwLibNameLen);
lstrcpyW (pLocalInfo->szServiceName, pInfo->szServiceName);
// convert wait time in milliseconds to the number of "loops"
pLocalInfo->dwWaitTime = pInfo->dwWaitTime / PERFLIB_TIMER_INTERVAL;
// wait for access to the data
if (hTimerDataMutex != NULL) {
Status = WaitForSingleObject (
hTimerDataMutex,
(PERFLIB_TIMER_INTERVAL * 2));
} else {
Status = ERROR_NOT_READY;
}
if (Status == WAIT_OBJECT_0) {
// we have access to the data so add this item to the front of the list
pLocalInfo->pNext = pTimerItemListHead;
pTimerItemListHead = pLocalInfo;
ReleaseMutex (hTimerDataMutex);
if (pLocalInfo->pNext == NULL) {
// then the list was empty before this call so start the timer
// going
SetEvent (hTimerHandles[PL_TIMER_START_EVENT]);
}
hReturn = (HANDLE)pLocalInfo;
} else {
SetLastError (Status);
}
}
else {
Status = ERROR_NOT_ENOUGH_MEMORY;
SetLastError (Status);
}
} else {
// unable to create thread
SetLastError (Status);
}
} else {
// unable to start timer
SetLastError (Status);
}
return hReturn;
}
DWORD
CPerfObjectAccess::KillPerflibFunctionTimer (
IN HANDLE hPerflibTimer
)
/*++
Terminates a timing event by removing it from the list. When the last
item is removed from the list the Start event is reset so the timing
thread will wait for either the next start event, exit event or it's
timeout to expire.
--*/
{
DWORD Status;
LPOPEN_PROC_WAIT_INFO pArg = (LPOPEN_PROC_WAIT_INFO)hPerflibTimer;
LPOPEN_PROC_WAIT_INFO pLocalInfo;
BOOL bFound = FALSE;
DWORD dwReturn = ERROR_SUCCESS;
if (hTimerDataMutex == NULL) {
dwReturn = ERROR_NOT_READY;
} else if (pArg == NULL) {
dwReturn = ERROR_INVALID_HANDLE;
} else {
// so far so good
// wait for access to the data
Status = WaitForSingleObject (
hTimerDataMutex,
(PERFLIB_TIMER_INTERVAL * 2));
if (Status == WAIT_OBJECT_0) {
// we have access to the list so walk down the list and remove the
// specified item
// see if it's the first one in the list
if (pArg == pTimerItemListHead) {
// then remove it
pTimerItemListHead = pArg->pNext;
bFound = TRUE;
} else {
for (pLocalInfo = pTimerItemListHead;
pLocalInfo != NULL;
pLocalInfo = pLocalInfo->pNext) {
if (pLocalInfo->pNext == pArg) {
pLocalInfo->pNext = pArg->pNext;
bFound = TRUE;
break;
}
}
}
assert (bFound);
if (bFound) {
// it's out of the list so release the lock
ReleaseMutex (hTimerDataMutex);
if (pTimerItemListHead == NULL) {
// then the list is empty now so stop timing
// going
ResetEvent (hTimerHandles[PL_TIMER_START_EVENT]);
}
// free memory
FREEMEM (m_hObjectHeap, 0, pArg);
dwReturn = ERROR_SUCCESS;
} else {
dwReturn = ERROR_NOT_FOUND;
}
} else {
dwReturn = ERROR_TIMEOUT;
}
}
return dwReturn;
}
DWORD
CPerfObjectAccess::DestroyPerflibFunctionTimer (
)
/*++
Terminates the timing thread and cancels any current timer events.
--*/
{
LONG Status;
LPOPEN_PROC_WAIT_INFO pThisItem;
LPOPEN_PROC_WAIT_INFO pNextItem;
// wait for data mutex
Status = WaitForSingleObject (
hTimerDataMutex,
(PERFLIB_TIMER_INTERVAL * 2));
assert (Status != WAIT_TIMEOUT);
// free all entries in the list
for (pNextItem = pTimerItemListHead;
pNextItem != NULL;) {
pThisItem = pNextItem;
pNextItem = pThisItem->pNext;
FREEMEM (m_hObjectHeap, 0, pThisItem);
}
// set exit event
SetEvent (hTimerHandles[PL_TIMER_EXIT_EVENT]);
// wait for thread to terminate
Status = WaitForSingleObject (
hPerflibTimingThread,
(PERFLIB_TIMER_INTERVAL * 5));
assert (Status != WAIT_TIMEOUT);
if (hPerflibTimingThread != NULL) {
CloseHandle (hPerflibTimingThread);
hPerflibTimingThread = NULL;
}
if (hTimerDataMutex != NULL) {
// cloes handles and leave
ReleaseMutex (hTimerDataMutex);
CloseHandle (hTimerDataMutex);
hTimerDataMutex = NULL;
}
if (hTimerHandles[PL_TIMER_START_EVENT] != NULL) {
CloseHandle (hTimerHandles[PL_TIMER_START_EVENT]);
hTimerHandles[PL_TIMER_START_EVENT] = NULL;
}
if (hTimerHandles[PL_TIMER_EXIT_EVENT] != NULL) {
CloseHandle (hTimerHandles[PL_TIMER_EXIT_EVENT]);
hTimerHandles[PL_TIMER_EXIT_EVENT] = NULL;
}
return ERROR_SUCCESS;
}
//***************************************************************************
//
// 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);
// BUG!!A-DCREWS: If CloseProc is uninitialized, then the condition will
// result in the lockoutcount being incremented
if ((lStatus != WAIT_TIMEOUT) &&
(pInfo->CloseProc != NULL)) {
lStatus = (*pInfo->CloseProc) ();
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];
HANDLE hPerflibFuncTimer = NULL;
OPEN_PROC_WAIT_INFO opwInfo;
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) {
// 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);
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);
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);
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 {
// start timer
opwInfo.pNext = NULL;
opwInfo.szLibraryName = pObj->szLibraryName;
opwInfo.szServiceName = pObj->szServiceName;
opwInfo.dwWaitTime = pObj->dwOpenTimeout;
#if 0 // disabled for testing
hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
// if no timer, continue anyway, even though things may
// hang, it's better than not loading the DLL since they
// usually load OK
//
if (hPerflibFuncTimer == NULL) {
// unable to get a timer entry
DebugPrint (("\nPERFLIB: Unable to acquire timer for Open Proc"));
}
#endif //test section
// call open procedure to initialize DLL
if (pObj->hMutex != NULL) {
Status = WaitForSingleObject (
pObj->hMutex,
pObj->dwOpenTimeout);
// BUG!!A-DCREWS: If OpenProc is uninitialized, then the condition will
// result in the lockoutcount being incremented
if ((Status != WAIT_TIMEOUT) &&
(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);
}
if (hPerflibFuncTimer != NULL) {
// kill timer
Status = KillPerflibFunctionTimer (hPerflibFuncTimer);
}
else
dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
} __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();
}
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;
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];
WCHAR szLinkageString[MAX_PATH];
DWORD dwOpenTimeout = 0;
DWORD dwCollectTimeout = 0;
LPWSTR szThisObject;
LPWSTR szThisChar;
LPSTR pNextStringA;
LPWSTR pNextStringW;
WCHAR szServicePath[MAX_PATH];
WCHAR szMutexName[MAX_PATH];
WCHAR szPID[32];
assert(pClass != NULL);
assert(pClassQualifiers != NULL);
UNREFERENCED_PARAMETER(pClassQualifiers);
UNREFERENCED_PARAMETER(pClass);
pLibEntry = new CPerfDataLibrary;
if ((pLibEntry != NULL) && (szRegistryKey != NULL)) {
lstrcpyW (szServicePath, cszHklmServicesKey);
Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
0, KEY_READ, &hServicesKey);
if (Status == ERROR_SUCCESS) {
lstrcpyW (szServicePath, szRegistryKey);
lstrcatW (szServicePath, cszPerformance);
Status = RegOpenKeyExW (hServicesKey, szServicePath,
0, KEY_READ, &hPerfKey);
if (Status == ERROR_SUCCESS) {
szServiceName = (LPWSTR)szRegistryKey;
// read the performance DLL name
dwType = 0;
dwSize = sizeof(szLibraryString);
memset (szLibraryString, 0, sizeof(szLibraryString));
memset (szLibraryString, 0, sizeof(szLibraryExpPath));
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,
MAX_PATH);
if ((dwSize > MAX_PATH) || (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,
MAX_PATH,
szLibraryExpPath,
NULL);
if ((dwSize > MAX_PATH) || (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 = sizeof(szOpenProcName);
memset (szOpenProcName, 0, sizeof(szOpenProcName));
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 = sizeof(dwOpenTimeout);
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) {
// get next string
dwType = 0;
dwSize = sizeof(szCloseProcName);
memset (szCloseProcName, 0, sizeof(szCloseProcName));
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 = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
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 = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
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 = sizeof(mszObjectList);
memset (mszObjectList, 0, sizeof(mszObjectList));
Status = RegQueryValueExW (hPerfKey,
cszObjListValue,
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) {
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) {
memset (szLinkageString, 0, sizeof(szLinkageString));
lstrcpyW (szLinkageKeyPath, szServiceName);
lstrcatW (szLinkageKeyPath, 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
memset (szLinkageString, 0, sizeof(szLinkageString));
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) {
// add in size of service name
dwSize = lstrlenW (szServiceName);
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// 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;
lstrcpyA (pNextStringA, szOpenProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
pReturnObject->dwOpenTimeout = dwOpenTimeout;
// copy collect function or query function, depending
pReturnObject->szCollectProcName = pNextStringA;
lstrcpyA (pNextStringA, szCollectProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
pReturnObject->dwCollectTimeout = dwCollectTimeout;
// copy Close Procedure Name
pReturnObject->szCloseProcName = pNextStringA;
lstrcpyA (pNextStringA, szCloseProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
// copy Library path
pNextStringW = (LPWSTR)pNextStringA;
pReturnObject->szLibraryName = pNextStringW;
lstrcpyW (pNextStringW, szLibraryExpPath);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
// copy Linkage String if there is one
if (*szLinkageString != 0) {
pReturnObject->szLinkageString = pNextStringW;
memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
// length includes extra NULL char and is in BYTES
pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
}
// copy Service name
pReturnObject->szServiceName = pNextStringW;
lstrcpyW (pNextStringW, szServiceName);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
// load flags
if (bUseQueryFn) {
dwFlags |= PERF_EO_QUERY_FUNC;
}
pReturnObject->dwFlags = dwFlags;
pReturnObject->hPerfKey = hPerfKey;
// 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, szRegistryKey);
lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
_ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
lstrcatW (szMutexName, 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
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 {
lstrcpyW (pLibEntry->szQueryString, 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
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;
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;
VariantInit (&vRegistryKey);
// get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers);
assert (hRes == 0);
// now get the library and procedure names
hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 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(CBSTR(cszPerfIndex), 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[MAX_PATH];
pLibEntry->dwRefCount++;
_ultow (dwPerfIndex, wszNewIndex, 10);
if (!IsNumberInUnicodeList (dwPerfIndex, pLibEntry->szQueryString)) {
// then add it to the list
lstrcatW (pLibEntry->szQueryString, cszSpace);
lstrcatW (pLibEntry->szQueryString, 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;
DWORD dwItemsInList = 0;
DWORD dwIndex, dwEntry;
CPerfDataLibrary *pThisLib;
liStartTime.QuadPart = 0;
liEndTime.QuadPart = 0;
if (lExtCounterTestLevel < EXT_TEST_NOMEMALLOC) {
bUseSafeBuffer = TRUE;
} else {
bUseSafeBuffer = FALSE;
}
lReturnValue = RegisterExtObjListAccess();
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);
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;
}
// 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 (pThisExtObj->hLibrary == NULL) {
// lock library object
if (pThisExtObj->hMutex != NULL) {
Win32Error = WaitForSingleObject (
pThisExtObj->hMutex,
pThisExtObj->dwCollectTimeout);
if (Win32Error != WAIT_TIMEOUT) {
// if necessary, open the library
if (pThisExtObj->hLibrary == NULL) {
// make sure the library is open
Win32Error = OpenExtObjectLibrary(pThisExtObj);
if (Win32Error != ERROR_SUCCESS) {
// assume error has been posted
ReleaseMutex (pThisExtObj->hMutex);
continue; // to next entry
}
}
ReleaseMutex (pThisExtObj->hMutex);
} 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);
// BUG!!A-DCREWS: If CollectProc is uninitialized, then the condition will
// result in the lockoutcount being incremented
if ((Win32Error != WAIT_TIMEOUT) &&
(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
Win32Error = DeRegisterExtObjListAccess();
((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;
VariantInit (&vRegistryKey);
// get the Qualifier Set for this class
hRes = pClass->GetQualifierSet(&pClassQualifiers);
assert (hRes == 0);
// now get the library and procedure names
hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 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(CBSTR(cszPerfIndex), 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;
}