2007 lines
62 KiB
C
2007 lines
62 KiB
C
/*++
|
|
|
|
Copyright (C) 1995-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
query.c
|
|
|
|
Abstract:
|
|
|
|
Query management functions exposed in pdh.dll
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <pdh.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include "mbctype.h"
|
|
#include "pdhitype.h"
|
|
#include "pdhidef.h"
|
|
#include "pdhmsg.h"
|
|
#include "strings.h"
|
|
|
|
STATIC_BOOL IsValidLogHandle(IN HLOG hLog);
|
|
PDH_FUNCTION PdhiRewindWmiLog(IN PPDHI_LOG pLog);
|
|
|
|
// query link list head pointer
|
|
PPDHI_QUERY PdhiDllHeadQueryPtr = NULL;
|
|
|
|
STATIC_BOOL
|
|
PdhiFreeQuery (
|
|
IN PPDHI_QUERY pThisQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
removes the query from the list of queries and updates the list
|
|
linkages
|
|
|
|
Arguments:
|
|
|
|
IN PPDHI_QUERY pThisQuery
|
|
pointer to the query to remove. No testing is performed on
|
|
this pointer so it's assumed to be a valid query pointer.
|
|
The pointer is invalid when this function returns.
|
|
|
|
Return Value:
|
|
|
|
TRUE
|
|
|
|
--*/
|
|
{
|
|
PPDHI_QUERY pPrevQuery;
|
|
PPDHI_QUERY pNextQuery;
|
|
PPDHI_COUNTER pThisCounter;
|
|
PPDHI_QUERY_MACHINE pQMachine;
|
|
PPDHI_QUERY_MACHINE pNextQMachine;
|
|
LONG lStatus;
|
|
BOOL bStatus;
|
|
HANDLE hQueryMutex;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS)
|
|
return WAIT_TIMEOUT;
|
|
|
|
hQueryMutex = pThisQuery->hMutex;
|
|
|
|
// close any async data collection threads
|
|
|
|
if (pThisQuery->hExitEvent != NULL) {
|
|
RELEASE_MUTEX(pThisQuery->hMutex);
|
|
// stop current thread first
|
|
SetEvent (pThisQuery->hExitEvent);
|
|
// wait 1 second for the thread to stop
|
|
lStatus = WaitForSingleObject (pThisQuery->hAsyncThread, 10000L);
|
|
if (lStatus == WAIT_TIMEOUT) {
|
|
REPORT_EVENT(EVENTLOG_ERROR_TYPE,
|
|
PDH_EVENT_CATEGORY_DEBUG,
|
|
PDH_ASYNC_QUERY_TIMEOUT);
|
|
}
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX (pThisQuery->hMutex) != ERROR_SUCCESS)
|
|
return WAIT_TIMEOUT;
|
|
bStatus = CloseHandle (pThisQuery->hExitEvent);
|
|
assert (bStatus);
|
|
pThisQuery->hExitEvent = NULL;
|
|
}
|
|
|
|
// define pointers
|
|
pPrevQuery = pThisQuery->next.blink;
|
|
pNextQuery = pThisQuery->next.flink;
|
|
|
|
// free any counters in counter list
|
|
if ((pThisCounter = pThisQuery->pCounterListHead) != NULL) {
|
|
while (pThisCounter->next.blink != pThisCounter->next.flink) {
|
|
// delete from list
|
|
// the deletion routine updates the blink pointer as it
|
|
// removes the specified entry.
|
|
FreeCounter (pThisCounter->next.blink);
|
|
}
|
|
// remove last counter
|
|
FreeCounter (pThisCounter);
|
|
pThisQuery->pCounterListHead = NULL;
|
|
}
|
|
|
|
if (!(pThisQuery->dwFlags & PDHIQ_WBEM_QUERY)) {
|
|
// free allocated memory in the query
|
|
if ((pQMachine = pThisQuery->pFirstQMachine) != NULL) {
|
|
// Free list of machine pointers
|
|
do {
|
|
pNextQMachine = pQMachine->pNext;
|
|
if (pQMachine->pPerfData != NULL) {
|
|
G_FREE (pQMachine->pPerfData);
|
|
}
|
|
G_FREE (pQMachine);
|
|
pQMachine = pNextQMachine;
|
|
} while (pQMachine != NULL);
|
|
pThisQuery->pFirstQMachine = NULL;
|
|
}
|
|
}
|
|
|
|
if (pThisQuery->dwFlags & PDHIQ_WBEM_QUERY) {
|
|
lStatus = PdhiFreeWbemQuery (pThisQuery);
|
|
}
|
|
|
|
if ( pThisQuery->dwReleaseLog != FALSE
|
|
&& pThisQuery->hLog != H_REALTIME_DATASOURCE
|
|
&& pThisQuery->hLog != H_WBEM_DATASOURCE) {
|
|
PdhCloseLog (pThisQuery->hLog, 0);
|
|
pThisQuery->hLog = H_REALTIME_DATASOURCE;
|
|
}
|
|
if (pThisQuery->hOutLog != NULL && IsValidLogHandle(pThisQuery->hOutLog)) {
|
|
PPDHI_LOG pOutLog = (PPDHI_LOG) pThisQuery->hOutLog;
|
|
pOutLog->pQuery = NULL;
|
|
}
|
|
|
|
// update pointers
|
|
if ((pPrevQuery == pThisQuery) && (pNextQuery == pThisQuery)) {
|
|
// then this query is the only (i.e. last) one in the list
|
|
PdhiDllHeadQueryPtr = NULL;
|
|
} else {
|
|
// update query list pointers
|
|
pPrevQuery->next.flink = pNextQuery;
|
|
pNextQuery->next.blink = pPrevQuery;
|
|
if (PdhiDllHeadQueryPtr == pThisQuery) {
|
|
// then this is the first entry in the list so point to the
|
|
// next one in line
|
|
PdhiDllHeadQueryPtr = pNextQuery;
|
|
}
|
|
}
|
|
|
|
if (pThisQuery->hMutex != NULL) {
|
|
pThisQuery->hMutex = NULL;
|
|
}
|
|
|
|
// clear the query structure
|
|
memset (pThisQuery, 0, sizeof(PDHI_QUERY));
|
|
|
|
// delete this query
|
|
G_FREE (pThisQuery);
|
|
|
|
// release and free the query mutex
|
|
RELEASE_MUTEX(hQueryMutex);
|
|
CloseHandle(hQueryMutex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryH(
|
|
IN HLOG hDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HQUERY * phQuery
|
|
)
|
|
{
|
|
PPDHI_QUERY pNewQuery;
|
|
PPDHI_QUERY pLastQuery;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
BOOL bWbemData = FALSE;
|
|
PPDHI_LOG pDataSource = NULL;
|
|
DWORD dwDataSource = DataSourceTypeH(hDataSource);
|
|
|
|
if (phQuery == NULL) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (dwDataSource == DATA_SOURCE_WBEM) {
|
|
hDataSource = H_WBEM_DATASOURCE;
|
|
bWbemData = TRUE;
|
|
}
|
|
|
|
if ( dwDataSource == DATA_SOURCE_WBEM
|
|
|| dwDataSource == DATA_SOURCE_REGISTRY) {
|
|
pDataSource = NULL;
|
|
}
|
|
else if (IsValidLogHandle(hDataSource)) {
|
|
pDataSource = (PPDHI_LOG) hDataSource;
|
|
}
|
|
else {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
pNewQuery = G_ALLOC(sizeof (PDHI_QUERY));
|
|
if (pNewQuery == NULL) {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
pNewQuery->hMutex = CreateMutexW(NULL, TRUE, NULL);
|
|
|
|
* (DWORD *)(& pNewQuery->signature[0]) = SigQuery;
|
|
|
|
if (PdhiDllHeadQueryPtr == NULL) {
|
|
PdhiDllHeadQueryPtr = pNewQuery->next.flink
|
|
= pNewQuery->next.blink
|
|
= pNewQuery;
|
|
}
|
|
else {
|
|
pLastQuery = PdhiDllHeadQueryPtr->next.blink;
|
|
pNewQuery->next.flink = PdhiDllHeadQueryPtr;
|
|
pNewQuery->next.blink = pLastQuery;
|
|
PdhiDllHeadQueryPtr->next.blink = pNewQuery;
|
|
pLastQuery->next.flink = pNewQuery;
|
|
}
|
|
|
|
pNewQuery->pCounterListHead = NULL;
|
|
pNewQuery->pFirstQMachine = NULL;
|
|
pNewQuery->dwLength = sizeof(PDHI_QUERY);
|
|
pNewQuery->dwUserData = dwUserData;
|
|
pNewQuery->dwFlags = 0;
|
|
pNewQuery->dwFlags |= (bWbemData ? PDHIQ_WBEM_QUERY : 0);
|
|
pNewQuery->hLog = hDataSource;
|
|
pNewQuery->dwReleaseLog = FALSE;
|
|
if ( pDataSource != NULL
|
|
&& LOWORD(pDataSource->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
|
|
ReturnStatus = PdhiRewindWmiLog(pDataSource);
|
|
if (ReturnStatus != ERROR_SUCCESS) {
|
|
RELEASE_MUTEX(pNewQuery->hMutex);
|
|
RELEASE_MUTEX(hPdhDataMutex);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
pNewQuery->hOutLog = NULL;
|
|
|
|
* (LONGLONG *)(& pNewQuery->TimeRange.StartTime) = MIN_TIME_VALUE;
|
|
* (LONGLONG *)(& pNewQuery->TimeRange.EndTime) = MAX_TIME_VALUE;
|
|
pNewQuery->TimeRange.SampleCount = 0;
|
|
pNewQuery->dwLastLogIndex = 0;
|
|
pNewQuery->dwInterval = 0;
|
|
pNewQuery->hAsyncThread = NULL;
|
|
pNewQuery->hExitEvent = NULL;
|
|
pNewQuery->hNewDataEvent = NULL;
|
|
|
|
pNewQuery->pRefresher = NULL;
|
|
pNewQuery->pRefresherCfg = NULL;
|
|
pNewQuery->LangID = GetUserDefaultUILanguage();
|
|
|
|
RELEASE_MUTEX(pNewQuery->hMutex);
|
|
|
|
__try {
|
|
* phQuery = (HQUERY) pNewQuery;
|
|
if(pDataSource != NULL) {
|
|
pDataSource->pQuery = (HQUERY) pNewQuery;
|
|
}
|
|
ReturnStatus = ERROR_SUCCESS;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
if (pNewQuery != NULL) {
|
|
PdhiFreeQuery(pNewQuery);
|
|
}
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
RELEASE_MUTEX(hPdhDataMutex);
|
|
}
|
|
|
|
Cleanup:
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
if ( hDataSource == H_REALTIME_DATASOURCE
|
|
|| hDataSource == H_WBEM_DATASOURCE) {
|
|
dwCurrentRealTimeDataSource ++;
|
|
}
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryW (
|
|
IN LPCWSTR szDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HQUERY *phQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
allocates a new query structure and inserts it at the end of the
|
|
query list.
|
|
|
|
Arguments:
|
|
|
|
IN LPCWSTR szDataSource
|
|
the name of the data (log) file to read from or NULL if the
|
|
current activity is desired.
|
|
|
|
IN DWORD dwUserData
|
|
the user defined data field for this query,
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
|
|
is invalid or incorrect.
|
|
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
|
|
not be allocated.
|
|
|
|
--*/
|
|
{
|
|
PPDHI_QUERY pNewQuery;
|
|
PPDHI_QUERY pLastQuery;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
HLOG hLogLocal = NULL;
|
|
DWORD dwLogType = 0;
|
|
BOOL bWbemData = FALSE;
|
|
DWORD dwDataSource = 0;
|
|
|
|
// try writing to return pointer
|
|
if (phQuery == NULL) {
|
|
return PDH_INVALID_ARGUMENT;
|
|
} else {
|
|
__try {
|
|
if (szDataSource != NULL) {
|
|
WCHAR TestChar;
|
|
// test for read access to the name
|
|
TestChar = *szDataSource;
|
|
if (TestChar == 0) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
} // else NULL is a valid arg
|
|
|
|
dwDataSource = DataSourceTypeW (szDataSource);
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
|
|
// validate the data source
|
|
switch (dwDataSource) {
|
|
case DATA_SOURCE_LOGFILE:
|
|
// then they are planning to read from a log file so
|
|
// try to open it
|
|
ReturnStatus = PdhOpenLogW (
|
|
szDataSource,
|
|
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
|
|
&dwLogType,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&hLogLocal);
|
|
|
|
if (ReturnStatus != ERROR_SUCCESS) {
|
|
return ReturnStatus;
|
|
}
|
|
break;
|
|
|
|
case DATA_SOURCE_WBEM:
|
|
bWbemData = TRUE;
|
|
// they want real-time data, so just keep going
|
|
hLogLocal = NULL;
|
|
break;
|
|
|
|
case DATA_SOURCE_REGISTRY:
|
|
// they want real-time data, so just keep going
|
|
hLogLocal = NULL;
|
|
break;
|
|
|
|
default:
|
|
assert (FALSE);
|
|
}
|
|
|
|
ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
// allocate new memory
|
|
pNewQuery = G_ALLOC (sizeof (PDHI_QUERY));
|
|
|
|
if (pNewQuery == NULL) {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
|
|
// create and capture the mutex for this query.
|
|
pNewQuery->hMutex = CreateMutexW (NULL, TRUE, NULL);
|
|
|
|
//initialize structures & list pointers
|
|
// assign signature
|
|
*(DWORD *)(&pNewQuery->signature[0]) = SigQuery;
|
|
|
|
// update list pointers
|
|
// test to see if this is the first query in the list
|
|
if (PdhiDllHeadQueryPtr == NULL) {
|
|
// then this is the first so fill in the static link pointers
|
|
PdhiDllHeadQueryPtr =
|
|
pNewQuery->next.flink =
|
|
pNewQuery->next.blink = pNewQuery;
|
|
} else {
|
|
// get pointer to "last" entry in list
|
|
pLastQuery = PdhiDllHeadQueryPtr->next.blink;
|
|
// update new query pointers
|
|
pNewQuery->next.flink = PdhiDllHeadQueryPtr;
|
|
pNewQuery->next.blink = pLastQuery;
|
|
// update existing pointers
|
|
PdhiDllHeadQueryPtr->next.blink = pNewQuery;
|
|
pLastQuery->next.flink = pNewQuery;
|
|
}
|
|
|
|
// initialize the counter linked list pointer
|
|
pNewQuery->pCounterListHead = NULL;
|
|
|
|
// initialize the machine list pointer
|
|
pNewQuery->pFirstQMachine = NULL;
|
|
|
|
// set length & user data
|
|
pNewQuery->dwLength = sizeof (PDHI_QUERY);
|
|
pNewQuery->dwUserData = dwUserData;
|
|
|
|
// initialize remaining data fields
|
|
pNewQuery->dwFlags = 0;
|
|
pNewQuery->dwFlags |= (bWbemData ? PDHIQ_WBEM_QUERY : 0);
|
|
|
|
pNewQuery->hLog = hLogLocal;
|
|
pNewQuery->hOutLog = NULL;
|
|
pNewQuery->dwReleaseLog = TRUE;
|
|
|
|
// initialize time range to include entire range
|
|
*(LONGLONG *)(&pNewQuery->TimeRange.StartTime) = MIN_TIME_VALUE;
|
|
*(LONGLONG *)(&pNewQuery->TimeRange.EndTime) = MAX_TIME_VALUE;
|
|
pNewQuery->TimeRange.SampleCount = 0;
|
|
|
|
pNewQuery->dwLastLogIndex = 0;
|
|
|
|
pNewQuery->dwInterval = 0; // no auto interval
|
|
pNewQuery->hAsyncThread = NULL; // timing thread;
|
|
pNewQuery->hExitEvent = NULL; // async timing thread exit
|
|
pNewQuery->hNewDataEvent = NULL; // no event
|
|
|
|
// initialize WBEM Data fields
|
|
pNewQuery->pRefresher = NULL;
|
|
pNewQuery->pRefresherCfg = NULL;
|
|
pNewQuery->LangID = GetUserDefaultUILanguage();
|
|
|
|
// release the mutex for this query
|
|
RELEASE_MUTEX(pNewQuery->hMutex);
|
|
|
|
__try {
|
|
// return new query pointer as a handle.
|
|
*phQuery = (HQUERY)pNewQuery;
|
|
ReturnStatus = ERROR_SUCCESS;
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
if (pNewQuery != NULL) {
|
|
// PdhiFreeQuery expects the data to be locked
|
|
PdhiFreeQuery (pNewQuery);
|
|
}
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
// release the data mutex
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
}
|
|
|
|
// if this query was added and it's a real-time query then disable
|
|
// future calls to change the data source.
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
if (hLogLocal == NULL) {
|
|
dwCurrentRealTimeDataSource ++;
|
|
}
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryA (
|
|
IN LPCSTR szDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HQUERY *phQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
allocates a new query structure and inserts it at the end of the
|
|
query list.
|
|
|
|
Arguments:
|
|
|
|
IN LPCSTR szDataSource
|
|
the name of the data (log) file to read from or NULL if the
|
|
current activity is desired.
|
|
|
|
IN DWORD dwUserData
|
|
the user defined data field for this query,
|
|
|
|
Return Value:
|
|
|
|
Returns a valid query handle if successful or INVALID_HANDLE_VALUE
|
|
if not. WIN32 Error status is retrieved using GetLastError()
|
|
|
|
--*/
|
|
{
|
|
LPWSTR szWideArg = NULL;
|
|
DWORD dwLength = 0;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
|
|
if (phQuery == NULL) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
} else {
|
|
try {
|
|
if (szDataSource != NULL) {
|
|
dwLength = (DWORD)strlen(szDataSource);
|
|
szWideArg = G_ALLOC ((dwLength + 1) * sizeof(WCHAR));
|
|
} else {
|
|
szWideArg = NULL;
|
|
}
|
|
|
|
if (szWideArg != NULL) {
|
|
// convert ANSI arg to Wide chars and call wide char version
|
|
// include null in conversion (i.e. length+1) so wide char
|
|
// string is null terminated.
|
|
MultiByteToWideChar(_getmbcp(),
|
|
0,
|
|
szDataSource,
|
|
dwLength,
|
|
(LPWSTR) szWideArg,
|
|
dwLength + 1);
|
|
} else if (szDataSource != NULL) {
|
|
// then a name was passed in but not converted to a wide
|
|
// character string so a memory allocation failure occurred
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
// call wide char version of function
|
|
ReturnStatus = PdhOpenQueryW (szWideArg, dwUserData, phQuery);
|
|
}
|
|
if (szWideArg != NULL) {
|
|
// free memory
|
|
G_FREE (szWideArg);
|
|
}
|
|
// and return handle
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiAddCounter(
|
|
IN HQUERY hQuery,
|
|
IN LPCWSTR szFullName,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HCOUNTER *phCounter,
|
|
IN PPDHI_COUNTER pNewCounter
|
|
)
|
|
/* Internal function called by PdhAddCounterW, PdhAddCounterA.
|
|
Assumes that szFullName and pNewCounter are properly allocated,
|
|
and initialized, i.e. szFullName has the counter path, and
|
|
pNewCounter zeroed.
|
|
*/
|
|
{
|
|
PPDHI_COUNTER pLastCounter;
|
|
PPDHI_QUERY pQuery;
|
|
PDH_STATUS ReturnStatus;
|
|
BOOL bStatus = TRUE;
|
|
|
|
// we're changing the contents of PDH data so lock it
|
|
|
|
* phCounter = NULL;
|
|
ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
if (!IsValidQuery(hQuery)) {
|
|
// invalid query handle
|
|
ReturnStatus = PDH_INVALID_HANDLE;
|
|
} else {
|
|
// assign signature & length values
|
|
*(DWORD *)(&pNewCounter->signature[0]) = SigCounter;
|
|
pNewCounter->dwLength = sizeof(PDHI_COUNTER);
|
|
|
|
pQuery = (PPDHI_QUERY)hQuery;
|
|
|
|
ReturnStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
|
|
// link to owning query
|
|
pNewCounter->pOwner = pQuery;
|
|
|
|
// set user data fields
|
|
pNewCounter->dwUserData = (DWORD) dwUserData;
|
|
|
|
// counter is not init'd yet
|
|
pNewCounter->dwFlags = PDHIC_COUNTER_NOT_INIT;
|
|
|
|
// initialize scale to 1X and let the caller make any changes
|
|
pNewCounter->lScale = 0;
|
|
pNewCounter->szFullName = (LPWSTR) szFullName;
|
|
|
|
if (pQuery->dwFlags & PDHIQ_WBEM_QUERY) {
|
|
pNewCounter->dwFlags |= PDHIC_WBEM_COUNTER;
|
|
// then this is a WBEM query so use WBEM
|
|
// functions to initialize it
|
|
bStatus = WbemInitCounter (pNewCounter);
|
|
} else {
|
|
bStatus = InitCounter(pNewCounter);
|
|
}
|
|
// load counter data using data retrieved from system
|
|
if (bStatus) {
|
|
// update list pointers
|
|
// test to see if this is the first query in the list
|
|
if (pQuery->pCounterListHead == NULL) {
|
|
// then this is the 1st so fill in the
|
|
// static link pointers
|
|
pQuery->pCounterListHead =
|
|
pNewCounter->next.flink =
|
|
pNewCounter->next.blink = pNewCounter;
|
|
} else {
|
|
pLastCounter = pQuery->pCounterListHead->next.blink;
|
|
pNewCounter->next.flink = pQuery->pCounterListHead;
|
|
pNewCounter->next.blink = pLastCounter;
|
|
pLastCounter->next.flink = pNewCounter;
|
|
pQuery->pCounterListHead->next.blink = pNewCounter;
|
|
}
|
|
* phCounter = (HCOUNTER) pNewCounter;
|
|
ReturnStatus = ERROR_SUCCESS;
|
|
} else {
|
|
// get the error value
|
|
ReturnStatus = GetLastError();
|
|
}
|
|
|
|
RELEASE_MUTEX (pQuery->hMutex);
|
|
}
|
|
}
|
|
RELEASE_MUTEX(hPdhDataMutex);
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAddCounterW (
|
|
IN HQUERY hQuery,
|
|
IN LPCWSTR szFullCounterPath,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HCOUNTER *phCounter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and initializes a counter structure and attaches it to the
|
|
specified query.
|
|
|
|
Arguments:
|
|
|
|
IN HQUERY hQuery
|
|
handle of the query to attach this counter to once the counter
|
|
entry has been successfully created.
|
|
|
|
IN LPCWSTR szFullCounterPath
|
|
pointer to the path string that describes the counter to add to
|
|
the query referenced above. This string must specify a single
|
|
counter. Wildcard path strings are not permitted.
|
|
|
|
IN DWORD dwUserData
|
|
the user defined data field for this query.
|
|
|
|
IN HCOUNTER *phCounter
|
|
pointer to the buffer that will get the handle value of the
|
|
successfully created counter entry.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
|
|
is invalid or incorrect.
|
|
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
|
|
not be allocated.
|
|
PDH_INVALID_HANDLE is returned if the query handle is not valid.
|
|
PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
|
|
not found
|
|
PDH_CSTATUS_NO_OBJECT is returned if the specified object could
|
|
not be found
|
|
PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
|
|
be created.
|
|
PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
|
|
string could not be parsed or interpreted
|
|
PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
|
|
path string is passed in
|
|
PDH_FUNCTION_NOT_FOUND is returned if the calculation function
|
|
for this counter could not be determined.
|
|
|
|
--*/
|
|
{
|
|
PPDHI_COUNTER pNewCounter = NULL;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
SIZE_T nPathLen = 0;
|
|
LPWSTR szFullName = NULL;
|
|
HCOUNTER hLocalCounter = NULL;
|
|
|
|
if ((szFullCounterPath == NULL) || (phCounter == NULL)) {
|
|
return PDH_INVALID_ARGUMENT;
|
|
}
|
|
__try {
|
|
*phCounter = NULL; // init to null
|
|
|
|
nPathLen = lstrlenW(szFullCounterPath);
|
|
if ((nPathLen == 0) || (nPathLen >= MAX_COUNTER_PATH-1)) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szFullName = G_ALLOC( (nPathLen + 1) * sizeof(WCHAR) );
|
|
if (szFullName) {
|
|
lstrcpyW (szFullName, szFullCounterPath);
|
|
}
|
|
else {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
pNewCounter = G_ALLOC (sizeof (PDHI_COUNTER));
|
|
if (pNewCounter == NULL) {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
RtlZeroMemory(pNewCounter, sizeof(PDHI_COUNTER));
|
|
}
|
|
}
|
|
|
|
// query handle is tested by PdhiAddCounter
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
ReturnStatus = PdhiAddCounter(
|
|
hQuery, szFullName,
|
|
dwUserData, &hLocalCounter,
|
|
pNewCounter);
|
|
if (ReturnStatus == ERROR_SUCCESS && hLocalCounter != NULL) {
|
|
__try {
|
|
*phCounter = hLocalCounter;
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
}
|
|
if (ReturnStatus != ERROR_SUCCESS) {
|
|
if (pNewCounter) {
|
|
if (pNewCounter->szFullName == NULL) {
|
|
G_FREE(szFullName);
|
|
}
|
|
if (!FreeCounter(pNewCounter)) {
|
|
G_FREE (pNewCounter);
|
|
}
|
|
} else if (szFullName) { // allocated this, but not pNewCounter
|
|
G_FREE (szFullName);
|
|
}
|
|
}
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAddCounterA (
|
|
IN HQUERY hQuery,
|
|
IN LPCSTR szFullCounterPath,
|
|
IN DWORD_PTR dwUserData,
|
|
IN HCOUNTER *phCounter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and initializes a counter structure and attaches it to the
|
|
specified query.
|
|
|
|
Arguments:
|
|
|
|
IN HQUERY hQuery
|
|
handle of the query to attach this counter to once the counter
|
|
entry has been successfully created.
|
|
|
|
IN LPCSTR szFullCounterPath
|
|
pointer to the path string that describes the counter to add to
|
|
the query referenced above. This string must specify a single
|
|
counter. Wildcard path strings are not permitted.
|
|
|
|
IN DWORD dwUserData
|
|
the user defined data field for this query.
|
|
|
|
IN HCOUNTER *phCounter
|
|
pointer to the buffer that will get the handle value of the
|
|
successfully created counter entry.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_ARGUMENT is returned when one or more of the arguements
|
|
is invalid or incorrect.
|
|
PDH_MEMORY_ALLOCATION_FAILURE is returned when a memory buffer could
|
|
not be allocated.
|
|
PDH_INVALID_HANDLE is returned if the query handle is not valid.
|
|
PDH_CSTATUS_NO_COUNTER is returned if the specified counter was
|
|
not found
|
|
PDH_CSTATUS_NO_OBJECT is returned if the specified object could
|
|
not be found
|
|
PDH_CSTATUS_NO_MACHINE is returned if a machine entry could not
|
|
be created.
|
|
PDH_CSTATUS_BAD_COUNTERNAME is returned if the counter name path
|
|
string could not be parsed or interpreted
|
|
PDH_CSTATUS_NO_COUNTERNAME is returned if an empty counter name
|
|
path string is passed in
|
|
PDH_FUNCTION_NOT_FOUND is returned if the calculation function
|
|
for this counter could not be determined.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR szFullName = NULL;
|
|
int nLength = 0;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
HCOUNTER hLocalCounter = NULL;
|
|
PPDHI_COUNTER pNewCounter = NULL;
|
|
|
|
if (phCounter == NULL || szFullCounterPath == NULL)
|
|
return PDH_INVALID_ARGUMENT;
|
|
|
|
__try {
|
|
// try writing to return pointer
|
|
*phCounter = NULL;
|
|
|
|
nLength = strlen(szFullCounterPath);
|
|
if ((nLength == 0) || (nLength >= MAX_COUNTER_PATH-1)) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szFullName = G_ALLOC((nLength + 1) * sizeof(WCHAR));
|
|
if (szFullName == NULL) {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
MultiByteToWideChar(_getmbcp(),
|
|
0,
|
|
szFullCounterPath,
|
|
nLength,
|
|
(LPWSTR) szFullName,
|
|
nLength + 1);
|
|
}
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
pNewCounter = G_ALLOC (sizeof (PDHI_COUNTER));
|
|
if (pNewCounter == NULL) {
|
|
ReturnStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
RtlZeroMemory(pNewCounter, sizeof(PDHI_COUNTER));
|
|
}
|
|
}
|
|
|
|
// query handle is tested by PdhiAddCounter
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
ReturnStatus = PdhiAddCounter(
|
|
hQuery, szFullName,
|
|
dwUserData, & hLocalCounter,
|
|
pNewCounter);
|
|
if (ReturnStatus == ERROR_SUCCESS && hLocalCounter != NULL) {
|
|
__try {
|
|
*phCounter = hLocalCounter;
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
}
|
|
if (ReturnStatus != ERROR_SUCCESS) {
|
|
if (pNewCounter) {
|
|
if (pNewCounter->szFullName == NULL) {
|
|
G_FREE(szFullName);
|
|
}
|
|
if (!FreeCounter(pNewCounter)) {
|
|
G_FREE (pNewCounter);
|
|
}
|
|
} else if (szFullName) { // allocated this, but not pNewCounter
|
|
G_FREE (szFullName);
|
|
}
|
|
}
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhRemoveCounter (
|
|
IN HCOUNTER hCounter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes the specified counter from the query it is attached to and
|
|
closes any handles and frees any memory associated with this
|
|
counter
|
|
|
|
Arguments:
|
|
|
|
IN HCOUNTER hCounter
|
|
handle of the counter to remove from the query.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_HANDLE is returned if the counter handle is not valid.
|
|
|
|
--*/
|
|
{
|
|
PPDHI_COUNTER pThisCounter;
|
|
PPDHI_QUERY pThisQuery;
|
|
PPDHI_COUNTER pNextCounter;
|
|
|
|
PPDHI_QUERY_MACHINE pQMachine;
|
|
PPDHI_QUERY_MACHINE pNextQMachine;
|
|
|
|
PDH_STATUS pdhStatus = ERROR_SUCCESS;
|
|
|
|
// we're changing the contents PDH data so lock it
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
if (IsValidCounter(hCounter)) {
|
|
// it's ok to cast it to a pointer now.
|
|
pThisCounter = (PPDHI_COUNTER)hCounter;
|
|
pThisQuery = pThisCounter->pOwner;
|
|
|
|
if (! IsValidQuery(pThisQuery)) {
|
|
pdhStatus = PDH_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS) {
|
|
pdhStatus = WAIT_TIMEOUT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (pThisCounter == pThisQuery->pCounterListHead) {
|
|
if (pThisCounter->next.flink == pThisCounter){
|
|
// then this is the only counter in the query
|
|
FreeCounter (pThisCounter);
|
|
pThisQuery->pCounterListHead = NULL;
|
|
|
|
if (!(pThisQuery->dwFlags & PDHIQ_WBEM_QUERY)) {
|
|
// remove the QMachine list since there are now no more
|
|
// counters to query
|
|
if ((pQMachine = pThisQuery->pFirstQMachine) != NULL) {
|
|
// Free list of machine pointers
|
|
do {
|
|
pNextQMachine = pQMachine->pNext;
|
|
if (pQMachine->pPerfData != NULL) {
|
|
G_FREE (pQMachine->pPerfData);
|
|
}
|
|
G_FREE (pQMachine);
|
|
pQMachine = pNextQMachine;
|
|
} while (pQMachine != NULL);
|
|
pThisQuery->pFirstQMachine = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
// they are deleting the first counter from the list
|
|
// so update the list pointer
|
|
// Free Counter takes care of the list links, we just
|
|
// need to manage the list head pointer
|
|
pNextCounter = pThisCounter->next.flink;
|
|
FreeCounter (pThisCounter);
|
|
pThisQuery->pCounterListHead = pNextCounter;
|
|
}
|
|
} else {
|
|
// remove this from the list
|
|
FreeCounter (pThisCounter);
|
|
}
|
|
RELEASE_MUTEX (pThisQuery->hMutex);
|
|
} else {
|
|
pdhStatus = PDH_INVALID_HANDLE;
|
|
}
|
|
|
|
Cleanup:
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
return pdhStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhSetQueryTimeRange (
|
|
IN HQUERY hQuery,
|
|
IN PPDH_TIME_INFO pInfo
|
|
)
|
|
{
|
|
PPDHI_QUERY pQuery;
|
|
PDH_STATUS pdhStatus = ERROR_SUCCESS;
|
|
|
|
if (pInfo == NULL) {
|
|
pdhStatus = PDH_INVALID_ARGUMENT;
|
|
} else {
|
|
if (IsValidQuery(hQuery)) {
|
|
pQuery = (PPDHI_QUERY)hQuery;
|
|
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pQuery->hMutex);
|
|
if (pdhStatus == ERROR_SUCCESS) {
|
|
if (IsValidQuery(hQuery)) {
|
|
if (pQuery->hLog == NULL) {
|
|
pdhStatus = ERROR_SUCCESS;
|
|
} else {
|
|
__try {
|
|
if (*(LONGLONG *)(&pInfo->EndTime) > *(LONGLONG *)(&pInfo->StartTime)) {
|
|
// reset log file pointers to beginning so next query
|
|
// will read from the start of the time range
|
|
pdhStatus = PdhiResetLogBuffers (pQuery->hLog);
|
|
// ok so now load new time range
|
|
if (pdhStatus == ERROR_SUCCESS) {
|
|
pQuery->TimeRange = *pInfo;
|
|
pQuery->dwLastLogIndex = 0;
|
|
}
|
|
} else {
|
|
// end time is smaller (earlier) than start time
|
|
pdhStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
pdhStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
} else {
|
|
// the query disappeared while we were waiting for it
|
|
pdhStatus = PDH_INVALID_HANDLE;
|
|
}
|
|
RELEASE_MUTEX (pQuery->hMutex);
|
|
} // else couldn't lock query
|
|
} else {
|
|
pdhStatus = PDH_INVALID_HANDLE;
|
|
}
|
|
}
|
|
return pdhStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiCollectQueryData (
|
|
IN PPDHI_QUERY pQuery,
|
|
IN LONGLONG *pllTimeStamp
|
|
)
|
|
{
|
|
PDH_STATUS Status;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
if (pQuery->dwFlags & PDHIQ_WBEM_QUERY) {
|
|
Status = GetQueryWbemData (pQuery, pllTimeStamp);
|
|
} else {
|
|
Status = GetQueryPerfData (pQuery, pllTimeStamp);
|
|
}
|
|
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhCollectQueryData (
|
|
IN HQUERY hQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the current value of each counter attached to the specified
|
|
query.
|
|
|
|
For this version, each machine associated with this query is polled
|
|
sequentially. This is simple and safe, but potentially slow so a
|
|
multi-threaded approach will be reviewed for the next version.
|
|
|
|
Note that while the call may succeed, no data may be available. The
|
|
status of each counter MUST be checked before its data is used.
|
|
|
|
Arguments:
|
|
|
|
IN HQUERY hQuery
|
|
handle of the query to update.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_HANDLE is returned if the query handle is not valid.
|
|
|
|
PDH_NO_DATA is returned if the query does not have any counters defined
|
|
yet.
|
|
|
|
--*/
|
|
{
|
|
PDH_STATUS Status;
|
|
PPDHI_QUERY pQuery;
|
|
LONGLONG llTimeStamp;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
if (IsValidQuery(hQuery)) {
|
|
pQuery = (PPDHI_QUERY)hQuery;
|
|
|
|
Status = PdhiCollectQueryData (pQuery, &llTimeStamp);
|
|
} else {
|
|
Status = PDH_INVALID_HANDLE;
|
|
}
|
|
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhCollectQueryDataEx (
|
|
IN HQUERY hQuery,
|
|
IN DWORD dwIntervalTime,
|
|
IN HANDLE hNewDataEvent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the current value of each counter attached to the specified
|
|
query periodically based on the interval time specified.
|
|
|
|
For this version, each machine associated with this query is polled
|
|
sequentially.
|
|
|
|
Note that while the call may succeed, no data may be available. The
|
|
status of each counter MUST be checked before its data is used.
|
|
|
|
Arguments:
|
|
|
|
IN HQUERY hQuery
|
|
handle of the query to update.
|
|
|
|
IN DWORD dwIntervalTime
|
|
Interval to poll for new data in seconds
|
|
this value must be > 0. A value of 0 will terminate any current
|
|
data collection threads.
|
|
|
|
IN HANDLE hNewDataEvent
|
|
Handle to an Event that should be signaled when new data is
|
|
available. This can be NULL if no notification is desired.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_HANDLE is returned if the query handle is not valid.
|
|
|
|
--*/
|
|
{
|
|
PDH_STATUS lStatus = ERROR_SUCCESS;
|
|
PPDHI_QUERY pQuery;
|
|
DWORD dwThreadId;
|
|
BOOL bStatus;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
if (IsValidQuery(hQuery)) {
|
|
// set the query structure's interval to the caller specified
|
|
// value then start the timing thread.
|
|
pQuery = (PPDHI_QUERY)hQuery;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX (pQuery->hMutex) != ERROR_SUCCESS) {
|
|
lStatus = WAIT_TIMEOUT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (pQuery->hExitEvent != NULL) {
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
// stop current thread first
|
|
SetEvent (pQuery->hExitEvent);
|
|
// wait 1 second for the thread to stop
|
|
lStatus = WaitForSingleObject (pQuery->hAsyncThread, 10000L);
|
|
if (lStatus == WAIT_TIMEOUT) {
|
|
REPORT_EVENT(EVENTLOG_ERROR_TYPE,
|
|
PDH_EVENT_CATEGORY_DEBUG,
|
|
PDH_ASYNC_QUERY_TIMEOUT);
|
|
}
|
|
|
|
lStatus = WAIT_FOR_AND_LOCK_MUTEX (pQuery->hMutex);
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
bStatus = CloseHandle (pQuery->hExitEvent);
|
|
assert (bStatus);
|
|
pQuery->hExitEvent = NULL;
|
|
bStatus = CloseHandle (pQuery->hAsyncThread);
|
|
assert (bStatus);
|
|
pQuery->hAsyncThread = 0;
|
|
}
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// query mutex is still locked at this point
|
|
if (dwIntervalTime > 0) {
|
|
// start a new interval
|
|
// initialize new values
|
|
pQuery->dwInterval = dwIntervalTime;
|
|
pQuery->hNewDataEvent = hNewDataEvent;
|
|
pQuery->hExitEvent = CreateEventW (NULL, TRUE, FALSE, NULL);
|
|
pQuery->hAsyncThread = CreateThread (
|
|
NULL, 0, PdhiAsyncTimerThreadProc,
|
|
(LPVOID)pQuery, 0, &dwThreadId);
|
|
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
|
|
if (pQuery->hAsyncThread == NULL) {
|
|
lStatus = WAIT_FOR_AND_LOCK_MUTEX (pQuery->hMutex);
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
pQuery->dwInterval = 0;
|
|
pQuery->hNewDataEvent = NULL;
|
|
bStatus = CloseHandle (pQuery->hExitEvent);
|
|
assert (bStatus);
|
|
pQuery->hExitEvent = NULL;
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
lStatus = GetLastError();
|
|
}
|
|
} else {
|
|
// lstatus = ERROR_SUCCESS from above
|
|
}
|
|
} else {
|
|
// they just wanted to stop so clean up Query struct
|
|
pQuery->dwInterval = 0;
|
|
pQuery->hNewDataEvent = NULL;
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
// lstatus = ERROR_SUCCESS from above
|
|
}
|
|
}
|
|
} else {
|
|
lStatus = PDH_INVALID_HANDLE;
|
|
}
|
|
|
|
Cleanup:
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
return lStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhCloseQuery (
|
|
IN HQUERY hQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
closes the query, all counters, connections and other resources
|
|
related to this query are freed as well.
|
|
|
|
Arguments:
|
|
|
|
IN HQUERY hQuery
|
|
the handle of the query to free.
|
|
|
|
Return Value:
|
|
|
|
Returns ERROR_SUCCESS if a new query was created and initialized,
|
|
and a PDH_ error value if not.
|
|
|
|
PDH_INVALID_HANDLE is returned if the query handle is not valid.
|
|
|
|
--*/
|
|
{
|
|
PDH_STATUS dwReturn;
|
|
// lock system data
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
if (IsValidQuery(hQuery)) {
|
|
// dispose of query
|
|
PPDHI_QUERY pQuery = (PPDHI_QUERY) hQuery;
|
|
if (pQuery->hLog == H_REALTIME_DATASOURCE
|
|
|| pQuery->hLog == H_WBEM_DATASOURCE) {
|
|
dwCurrentRealTimeDataSource --;
|
|
if (dwCurrentRealTimeDataSource < 0) {
|
|
dwCurrentRealTimeDataSource = 0;
|
|
}
|
|
}
|
|
PdhiFreeQuery (pQuery);
|
|
// release data lock
|
|
dwReturn = ERROR_SUCCESS;
|
|
} else {
|
|
dwReturn = PDH_INVALID_HANDLE;
|
|
}
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
BOOL
|
|
PdhiQueryCleanup (
|
|
)
|
|
{
|
|
PPDHI_QUERY pThisQuery;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) != ERROR_SUCCESS) return WAIT_TIMEOUT;
|
|
|
|
// free any queries in the query list
|
|
pThisQuery = PdhiDllHeadQueryPtr;
|
|
if (pThisQuery != NULL) {
|
|
while (pThisQuery->next.blink != pThisQuery->next.flink) {
|
|
// delete from list
|
|
// the deletion routine updates the blink pointer as it
|
|
// removes the specified entry.
|
|
PdhiFreeQuery (pThisQuery->next.blink);
|
|
}
|
|
// remove last query
|
|
PdhiFreeQuery (pThisQuery);
|
|
PdhiDllHeadQueryPtr = NULL;
|
|
|
|
dwCurrentRealTimeDataSource = 0;
|
|
}
|
|
|
|
RELEASE_MUTEX (hPdhDataMutex);
|
|
return TRUE;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhGetDllVersion(
|
|
IN LPDWORD lpdwVersion
|
|
)
|
|
{
|
|
PDH_STATUS pdhStatus = ERROR_SUCCESS;
|
|
|
|
__try {
|
|
*lpdwVersion = PDH_VERSION;
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
pdhStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
return pdhStatus;
|
|
}
|
|
|
|
BOOL
|
|
PdhIsRealTimeQuery (
|
|
IN HQUERY hQuery
|
|
)
|
|
{
|
|
PPDHI_QUERY pQuery;
|
|
BOOL bReturn = FALSE;
|
|
|
|
SetLastError (ERROR_SUCCESS);
|
|
if (IsValidQuery(hQuery)) {
|
|
__try {
|
|
pQuery = (PPDHI_QUERY)hQuery;
|
|
if (pQuery->hLog == NULL) {
|
|
bReturn = TRUE;
|
|
} else {
|
|
bReturn = FALSE;
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError (GetExceptionCode());
|
|
}
|
|
} else {
|
|
bReturn = FALSE;
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhFormatFromRawValue (
|
|
IN DWORD dwCounterType,
|
|
IN DWORD dwFormat,
|
|
IN LONGLONG *pTimeBase,
|
|
IN PPDH_RAW_COUNTER pRawValue1,
|
|
IN PPDH_RAW_COUNTER pRawValue2,
|
|
IN PPDH_FMT_COUNTERVALUE pFmtValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calculates the formatted counter value using the data in the RawValue
|
|
buffer in the format requested by the format field using the
|
|
calculation functions of the counter type specified by the
|
|
dwCounterType field.
|
|
|
|
Arguments:
|
|
|
|
IN DWORD dwCounterType
|
|
The type of the counter to use in order to determine the
|
|
calculation functions for interpretation of the raw value buffers
|
|
|
|
IN DWORD dwFormat
|
|
Format in which the requested data should be returned. The
|
|
values for this field are described in the PDH.H header
|
|
file.
|
|
|
|
IN LONGLONG *pTimeBase
|
|
pointer to the _int64 value containing the timebase (i.e. counter
|
|
unit frequency) used by this counter. This can be NULL if it's not
|
|
required by the counter type
|
|
IN PPDH_RAW_COUNTER rawValue1
|
|
pointer to the buffer that contains the first raw value structure
|
|
|
|
IN PPDH_RAW_COUNTER rawValue2
|
|
pointer to the buffer that contains the second raw value structure.
|
|
This argument may be null if only one value is required for the
|
|
computation.
|
|
|
|
IN PPDH_FMT_COUNTERVALUE fmtValue
|
|
the pointer to the data buffer passed by the caller to receive
|
|
the data requested. If the counter requires 2 values, (as in the
|
|
case of a rate counter), rawValue1 is assumed to be the most
|
|
recent value and rawValue2, the older value.
|
|
|
|
Return Value:
|
|
|
|
The WIN32 Error status of the function's operation. Common values
|
|
returned are:
|
|
ERROR_SUCCESS when all requested data is returned
|
|
PDH_INVALID_HANDLE if the counter handle is incorrect
|
|
PDH_INVALID_ARGUMENT if an argument is incorrect
|
|
|
|
--*/
|
|
{
|
|
PDH_STATUS lStatus = ERROR_SUCCESS;
|
|
LPCOUNTERCALC pCalcFunc;
|
|
LPCOUNTERSTAT pStatFunc;
|
|
LONGLONG llTimeBase;
|
|
BOOL bReturn;
|
|
|
|
// TODO: Need to check for pRawValue1
|
|
// bad arguments are caught in the PdhiComputeFormattedValue function
|
|
// NOTE: postW2k pTimeBase really do not need to be a pointer, since it is
|
|
// not returned
|
|
if (pTimeBase != NULL) {
|
|
try {
|
|
DWORD dwTempStatus;
|
|
DWORD dwTypeMask;
|
|
|
|
// read access to the timebase
|
|
llTimeBase = *pTimeBase;
|
|
|
|
// we should have read access to the rawValues
|
|
dwTempStatus = *((DWORD volatile *)&pRawValue1->CStatus);
|
|
|
|
// this one could be NULL
|
|
if (pRawValue2 != NULL) {
|
|
dwTempStatus = *((DWORD volatile *)&pRawValue2->CStatus);
|
|
}
|
|
|
|
// and write access to the fmtValue
|
|
pFmtValue->CStatus = 0;
|
|
|
|
// validate format flags:
|
|
// only one of the following can be set at a time
|
|
dwTypeMask = dwFormat &
|
|
(PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
|
|
if (!((dwTypeMask == PDH_FMT_LONG) ||
|
|
(dwTypeMask == PDH_FMT_DOUBLE) ||
|
|
(dwTypeMask == PDH_FMT_LARGE))) {
|
|
lStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
lStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
} else {
|
|
llTimeBase = 0;
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
|
|
// get calc func for counter type this will also test the
|
|
// validity of the counter type argument
|
|
|
|
bReturn = AssignCalcFunction (
|
|
dwCounterType,
|
|
&pCalcFunc,
|
|
&pStatFunc);
|
|
|
|
if (!bReturn) {
|
|
lStatus = GetLastError();
|
|
} else {
|
|
lStatus = PdhiComputeFormattedValue (
|
|
pCalcFunc,
|
|
dwCounterType,
|
|
0L,
|
|
dwFormat,
|
|
pRawValue1,
|
|
pRawValue2,
|
|
&llTimeBase,
|
|
0L,
|
|
pFmtValue);
|
|
}
|
|
}
|
|
return lStatus;
|
|
|
|
}
|
|
|
|
LPWSTR
|
|
PdhiMatchObjectNameInList(
|
|
IN LPWSTR szObjectName,
|
|
IN LPWSTR * szSrcPerfStrings,
|
|
IN LPWSTR * szDestPerfStrings,
|
|
IN DWORD dwLastString)
|
|
{
|
|
LPWSTR szRtnName = NULL;
|
|
DWORD i;
|
|
|
|
for (i = 0; i <= dwLastString; i ++) {
|
|
if ( szSrcPerfStrings[i]
|
|
&& szSrcPerfStrings[i] != L'\0'
|
|
&& lstrcmpiW(szObjectName, szSrcPerfStrings[i]) == 0) {
|
|
szRtnName = szDestPerfStrings[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return szRtnName;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiBuildFullCounterPath(
|
|
IN BOOL bMachine,
|
|
IN PPDHI_COUNTER_PATH pCounterPath,
|
|
IN LPWSTR szObjectName,
|
|
IN LPWSTR szCounterName,
|
|
IN LPWSTR szFullPath
|
|
)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
|
|
// Internal routine,
|
|
// Build full counter path name from counter path structure, assume
|
|
// passed-in string buffer is large enough to hold.
|
|
|
|
if (bMachine) {
|
|
lstrcpyW(szFullPath, pCounterPath->szMachineName);
|
|
lstrcatW(szFullPath, cszBackSlash);
|
|
}
|
|
else {
|
|
lstrcpyW(szFullPath, cszBackSlash);
|
|
}
|
|
lstrcatW(szFullPath, szObjectName);
|
|
if ( pCounterPath->szInstanceName != NULL
|
|
&& pCounterPath->szInstanceName[0] != L'\0') {
|
|
lstrcatW(szFullPath, cszLeftParen);
|
|
if ( pCounterPath->szParentName != NULL
|
|
&& pCounterPath->szParentName[0] != L'\0') {
|
|
lstrcatW(szFullPath, pCounterPath->szParentName);
|
|
lstrcatW(szFullPath, cszSlash);
|
|
}
|
|
lstrcatW(szFullPath, pCounterPath->szInstanceName);
|
|
if ( pCounterPath->dwIndex != ((DWORD) -1)
|
|
&& pCounterPath->dwIndex != 0) {
|
|
WCHAR szDigits[16];
|
|
|
|
ZeroMemory(szDigits, 16 * sizeof(WCHAR));
|
|
lstrcatW(szFullPath, cszPoundSign);
|
|
_ltow((long) pCounterPath->dwIndex, szDigits, 10);
|
|
lstrcatW(szFullPath, szDigits);
|
|
}
|
|
lstrcatW(szFullPath, cszRightParen);
|
|
}
|
|
lstrcatW(szFullPath, cszBackSlash);
|
|
lstrcatW(szFullPath, szCounterName);
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiTranslateCounter(
|
|
IN LPWSTR szSourcePath,
|
|
IN LPVOID pFullPathName,
|
|
IN LPDWORD pcchPathLength,
|
|
IN BOOL bLocaleTo009,
|
|
IN BOOL bUnicode)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
PPERF_MACHINE pMachine = NULL;
|
|
PPDHI_COUNTER_PATH pCounterPath = NULL;
|
|
LPWSTR szRtnPath = NULL;
|
|
DWORD dwPathSize;
|
|
DWORD dwRtnPathSize;
|
|
DWORD dwSize;
|
|
BOOL bMachineThere = FALSE;
|
|
|
|
bMachineThere = (lstrlenW(szSourcePath) >= 2)
|
|
&& (szSourcePath[0] == BACKSLASH_L)
|
|
&& (szSourcePath[1] == BACKSLASH_L);
|
|
|
|
dwPathSize = sizeof(WCHAR) * (lstrlenW(szSourcePath) + 2);
|
|
dwSize = sizeof(PDHI_COUNTER_PATH) + 2 * dwPathSize;
|
|
pCounterPath = G_ALLOC(dwSize);
|
|
if (pCounterPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ParseFullPathNameW(szSourcePath, & dwSize, pCounterPath, FALSE)) {
|
|
pMachine = GetMachineW(pCounterPath->szMachineName, 0);
|
|
if (pMachine && pMachine->dwStatus == ERROR_SUCCESS) {
|
|
LPWSTR szObjectName;
|
|
LPWSTR szCounterName;
|
|
BOOLEAN bInstance = TRUE;
|
|
|
|
if (bLocaleTo009) {
|
|
szObjectName = PdhiMatchObjectNameInList(
|
|
pCounterPath->szObjectName,
|
|
pMachine->szPerfStrings,
|
|
pMachine->sz009PerfStrings,
|
|
pMachine->dwLastPerfString);
|
|
szCounterName = PdhiMatchObjectNameInList(
|
|
pCounterPath->szCounterName,
|
|
pMachine->szPerfStrings,
|
|
pMachine->sz009PerfStrings,
|
|
pMachine->dwLastPerfString);
|
|
}
|
|
else {
|
|
szObjectName = PdhiMatchObjectNameInList(
|
|
pCounterPath->szObjectName,
|
|
pMachine->sz009PerfStrings,
|
|
pMachine->szPerfStrings,
|
|
pMachine->dwLastPerfString);
|
|
szCounterName = PdhiMatchObjectNameInList(
|
|
pCounterPath->szCounterName,
|
|
pMachine->sz009PerfStrings,
|
|
pMachine->szPerfStrings,
|
|
pMachine->dwLastPerfString);
|
|
}
|
|
if ( (szObjectName == NULL)
|
|
&& (* pCounterPath->szObjectName == SPLAT_L)) {
|
|
szObjectName = pCounterPath->szObjectName;
|
|
}
|
|
if ( (szCounterName == NULL)
|
|
&& (* pCounterPath->szCounterName == SPLAT_L)) {
|
|
szCounterName = pCounterPath->szCounterName;
|
|
}
|
|
|
|
if (szObjectName == NULL || szCounterName == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( pCounterPath->szInstanceName != NULL
|
|
&& pCounterPath->szInstanceName[0] != L'\0') {
|
|
dwRtnPathSize = sizeof(WCHAR)
|
|
* ( lstrlenW(pCounterPath->szMachineName)
|
|
+ lstrlenW(szObjectName)
|
|
+ lstrlenW(pCounterPath->szInstanceName)
|
|
+ lstrlenW(szCounterName) + 5);
|
|
if ( pCounterPath->szParentName != NULL
|
|
&& pCounterPath->szParentName[0] != L'\0') {
|
|
dwRtnPathSize += (sizeof(WCHAR)
|
|
* (lstrlenW(pCounterPath->szParentName) + 1));
|
|
}
|
|
if ( pCounterPath->dwIndex != ((DWORD) -1)
|
|
&& pCounterPath->dwIndex != 0) {
|
|
dwRtnPathSize += (sizeof(WCHAR) * 16);
|
|
}
|
|
}
|
|
else {
|
|
dwRtnPathSize = sizeof(WCHAR)
|
|
* ( lstrlenW(pCounterPath->szMachineName)
|
|
+ lstrlenW(szObjectName)
|
|
+ lstrlenW(szCounterName) + 3);
|
|
bInstance = FALSE;
|
|
}
|
|
szRtnPath = G_ALLOC(dwRtnPathSize);
|
|
if (szRtnPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
PdhiBuildFullCounterPath(bMachineThere,
|
|
pCounterPath,
|
|
szObjectName,
|
|
szCounterName,
|
|
szRtnPath);
|
|
if (bUnicode) {
|
|
if ( (pFullPathName)
|
|
&& ( (* pcchPathLength)
|
|
>= (DWORD) (lstrlenW(szRtnPath) + 1))) {
|
|
lstrcpyW(pFullPathName, szRtnPath);
|
|
}
|
|
else {
|
|
Status = PDH_MORE_DATA;
|
|
}
|
|
* pcchPathLength = lstrlenW(szRtnPath) + 1;
|
|
}
|
|
else {
|
|
dwRtnPathSize = * pcchPathLength;
|
|
if (bLocaleTo009) {
|
|
Status = PdhiConvertUnicodeToAnsi(CP_ACP,
|
|
szRtnPath, pFullPathName, & dwRtnPathSize);
|
|
}
|
|
else {
|
|
Status = PdhiConvertUnicodeToAnsi(_getmbcp(),
|
|
szRtnPath, pFullPathName, & dwRtnPathSize);
|
|
}
|
|
* pcchPathLength = dwRtnPathSize;
|
|
}
|
|
|
|
pMachine->dwRefCount --;
|
|
RELEASE_MUTEX(pMachine->hMutex);
|
|
}
|
|
else {
|
|
Status = PDH_CSTATUS_NO_MACHINE;
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_CSTATUS_BAD_COUNTERNAME;
|
|
}
|
|
|
|
Cleanup:
|
|
if (szRtnPath != NULL) {
|
|
G_FREE(szRtnPath);
|
|
}
|
|
if (pCounterPath != NULL) {
|
|
G_FREE(pCounterPath);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhTranslate009CounterW(
|
|
IN LPWSTR szLocalePath,
|
|
IN LPWSTR pszFullPathName,
|
|
IN LPDWORD pcchPathLength)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
|
|
if (szLocalePath == NULL || pszFullPathName == NULL
|
|
|| pcchPathLength == NULL
|
|
|| * pcchPathLength == 0) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
* pszFullPathName = 0;
|
|
* (LPWSTR) ( ((LPBYTE) pszFullPathName)
|
|
+ ((* pcchPathLength) - sizeof(WCHAR))) = 0;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhiTranslateCounter(
|
|
szLocalePath, pszFullPathName, pcchPathLength, TRUE, TRUE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhTranslate009CounterA(
|
|
IN LPSTR szLocalePath,
|
|
IN LPSTR pszFullPathName,
|
|
IN LPDWORD pcchPathLength)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPWSTR szTmpPath = NULL;
|
|
DWORD dwPathSize;
|
|
|
|
if (szLocalePath == NULL || pszFullPathName == NULL
|
|
|| pcchPathLength == NULL
|
|
|| * pcchPathLength == 0) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
* pszFullPathName = 0;
|
|
* (LPSTR) ( ((LPBYTE) pszFullPathName)
|
|
+ ((* pcchPathLength) - sizeof(CHAR))) = 0;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
dwPathSize = sizeof(WCHAR) * (lstrlenA(szLocalePath) + 1);
|
|
szTmpPath = G_ALLOC(dwPathSize);
|
|
if (szTmpPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
MultiByteToWideChar(_getmbcp(),
|
|
0,
|
|
szLocalePath,
|
|
lstrlenA(szLocalePath),
|
|
szTmpPath,
|
|
dwPathSize / sizeof(WCHAR));
|
|
Status = PdhiTranslateCounter(
|
|
szTmpPath, pszFullPathName, pcchPathLength, TRUE, FALSE);
|
|
G_FREE(szTmpPath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhTranslateLocaleCounterW(
|
|
IN LPWSTR sz009Path,
|
|
IN LPWSTR pszFullPathName,
|
|
IN LPDWORD pcchPathLength)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
|
|
if (sz009Path == NULL || pszFullPathName == NULL
|
|
|| pcchPathLength == NULL
|
|
|| * pcchPathLength == 0) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
* pszFullPathName = 0;
|
|
* (LPWSTR) ( ((LPBYTE) pszFullPathName)
|
|
+ ((* pcchPathLength) - sizeof(WCHAR))) = 0;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhiTranslateCounter(
|
|
sz009Path, pszFullPathName, pcchPathLength, FALSE, TRUE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhTranslateLocaleCounterA(
|
|
IN LPSTR sz009Path,
|
|
IN LPSTR pszFullPathName,
|
|
IN LPDWORD pcchPathLength)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPWSTR szTmpPath = NULL;
|
|
DWORD dwPathSize;
|
|
|
|
if (sz009Path == NULL || pszFullPathName == NULL
|
|
|| pcchPathLength == NULL
|
|
|| * pcchPathLength == 0) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
* pszFullPathName = 0;
|
|
* (LPSTR) ( ((LPBYTE) pszFullPathName)
|
|
+ ((* pcchPathLength) - sizeof(CHAR))) = 0;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
dwPathSize = sizeof(WCHAR) * (lstrlenA(sz009Path) + 1);
|
|
szTmpPath = G_ALLOC(dwPathSize);
|
|
if (szTmpPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
sz009Path,
|
|
lstrlenA(sz009Path),
|
|
szTmpPath,
|
|
dwPathSize / sizeof(WCHAR));
|
|
Status = PdhiTranslateCounter(
|
|
szTmpPath, pszFullPathName, pcchPathLength, FALSE, FALSE);
|
|
G_FREE(szTmpPath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAdd009CounterW(
|
|
IN HQUERY hQuery,
|
|
IN LPWSTR szFullPath,
|
|
IN DWORD_PTR dwUserData,
|
|
OUT HCOUNTER * phCounter)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPWSTR szLocalePath = NULL;
|
|
DWORD dwPathLength = sizeof(WCHAR) * (lstrlenW(szFullPath) + 1);
|
|
|
|
szLocalePath = G_ALLOC(dwPathLength);
|
|
if (szLocalePath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
Status = PdhTranslateLocaleCounterW(
|
|
szFullPath, szLocalePath, & dwPathLength);
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhAddCounterW(
|
|
hQuery, szLocalePath, dwUserData, phCounter);
|
|
}
|
|
if (Status != ERROR_SUCCESS) {
|
|
G_FREE(szLocalePath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAdd009CounterA(
|
|
IN HQUERY hQuery,
|
|
IN LPSTR szFullPath,
|
|
IN DWORD_PTR dwUserData,
|
|
OUT HCOUNTER * phCounter)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPSTR szLocalePath = NULL;
|
|
DWORD dwPathLength = sizeof(WCHAR) * (lstrlenA(szFullPath) + 1);
|
|
|
|
szLocalePath = G_ALLOC(dwPathLength);
|
|
if (szLocalePath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
Status = PdhTranslateLocaleCounterA(
|
|
szFullPath, szLocalePath, & dwPathLength);
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhAddCounterA(
|
|
hQuery, szLocalePath, dwUserData, phCounter);
|
|
}
|
|
if (Status != ERROR_SUCCESS) {
|
|
G_FREE(szLocalePath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiConvertUnicodeToAnsi(
|
|
IN UINT uCodePage,
|
|
IN LPWSTR wszSrc,
|
|
IN LPSTR aszDest,
|
|
IN LPDWORD pdwSize
|
|
)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
DWORD dwDest;
|
|
DWORD dwSrc = 0;
|
|
|
|
if (wszSrc == NULL || * wszSrc == L'\0' || pdwSize == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
dwSrc = lstrlenW(wszSrc);
|
|
dwDest = WideCharToMultiByte(uCodePage,
|
|
0,
|
|
wszSrc,
|
|
dwSrc,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
if (aszDest != NULL && (dwDest + 1) <= * pdwSize) {
|
|
ZeroMemory(aszDest, dwDest + 1);
|
|
WideCharToMultiByte(_getmbcp(),
|
|
0,
|
|
wszSrc,
|
|
dwSrc,
|
|
aszDest,
|
|
* pdwSize,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
else {
|
|
Status = PDH_MORE_DATA;
|
|
}
|
|
|
|
* pdwSize = dwDest + 1;
|
|
}
|
|
return Status;
|
|
}
|
|
|