2099 lines
73 KiB
C
2099 lines
73 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 <math.h>
|
|
#include "mbctype.h"
|
|
#include "strsafe.h"
|
|
#include <pdh.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(
|
|
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;
|
|
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_ULONGX, 2),
|
|
ERROR_SUCCESS,
|
|
TRACE_PTR(pThisQuery),
|
|
TRACE_DWORD(pThisQuery->dwFlags),
|
|
NULL));
|
|
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) {
|
|
TRACE((PDH_DBG_TRACE_ERROR), (__LINE__, PDH_QUERY, 0, lStatus, NULL));
|
|
}
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(pThisQuery->hMutex) != ERROR_SUCCESS)
|
|
return WAIT_TIMEOUT;
|
|
|
|
bStatus = CloseHandle(pThisQuery->hExitEvent);
|
|
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;
|
|
}
|
|
|
|
// delete this query
|
|
G_FREE(pThisQuery);
|
|
|
|
// release and free the query mutex
|
|
RELEASE_MUTEX(hQueryMutex);
|
|
CloseHandle(hQueryMutex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryH(
|
|
IN PDH_HLOG hDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN PDH_HQUERY * phQuery
|
|
)
|
|
{
|
|
PPDHI_QUERY pNewQuery;
|
|
PPDHI_QUERY pLastQuery;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
BOOL bWbemData = FALSE;
|
|
PPDHI_LOG pDataSource = NULL;
|
|
DWORD dwDataSource;
|
|
DWORD_PTR dwLocalData;
|
|
|
|
__try {
|
|
dwLocalData = dwUserData;
|
|
dwDataSource = DataSourceTypeH(hDataSource);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
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 = dwLocalData;
|
|
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 ++;
|
|
}
|
|
}
|
|
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2)
|
|
| ARG_DEF(ARG_TYPE_PTR, 3),
|
|
ReturnStatus,
|
|
TRACE_PTR(hDataSource),
|
|
TRACE_PTR(phQuery),
|
|
TRACE_PTR(pNewQuery),
|
|
TRACE_DWORD(dwDataSource),
|
|
TRACE_DWORD(dwCurrentRealTimeDataSource),
|
|
NULL));
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryW(
|
|
IN LPCWSTR szDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN PDH_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;
|
|
DWORD_PTR dwLocalData;
|
|
|
|
// try writing to return pointer
|
|
if (phQuery == NULL) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
if (szDataSource != NULL) {
|
|
dwLocalData = lstrlenW(szDataSource);
|
|
|
|
if (dwLocalData == 0 || dwLocalData > PDH_MAX_DATASOURCE_PATH) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (* szDataSource == L'\0') {
|
|
// test for read access to the name
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
} // else NULL is a valid arg
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
dwLocalData = dwUserData;
|
|
dwDataSource = DataSourceTypeW(szDataSource);
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
// 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);
|
|
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:
|
|
break;
|
|
}
|
|
}
|
|
if (ReturnStatus != ERROR_SUCCESS) goto Cleanup;
|
|
|
|
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 = dwLocalData;
|
|
// 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 ++;
|
|
}
|
|
else {
|
|
PPDHI_LOG pLog = (PPDHI_LOG) hLogLocal;
|
|
pLog->pQuery = pNewQuery;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2),
|
|
ReturnStatus,
|
|
TRACE_PTR(phQuery),
|
|
TRACE_PTR(pNewQuery),
|
|
TRACE_DWORD(dwDataSource),
|
|
TRACE_DWORD(dwCurrentRealTimeDataSource),
|
|
NULL));
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhOpenQueryA(
|
|
IN LPCSTR szDataSource,
|
|
IN DWORD_PTR dwUserData,
|
|
IN PDH_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;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
DWORD_PTR dwLocalData;
|
|
|
|
if (phQuery == NULL) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
if (szDataSource != NULL) {
|
|
DWORD dwLength = lstrlenA(szDataSource);
|
|
if (dwLength == 0 || dwLength > PDH_MAX_DATASOURCE_PATH) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szWideArg = PdhiMultiByteToWideChar(_getmbcp(), (LPSTR) szDataSource);
|
|
if (szWideArg == 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;
|
|
}
|
|
}
|
|
}
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
* phQuery = NULL;
|
|
dwLocalData = dwUserData;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
// call wide char version of function
|
|
ReturnStatus = PdhOpenQueryW(szWideArg, dwLocalData, phQuery);
|
|
}
|
|
G_FREE (szWideArg);
|
|
// and return handle
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiAddCounter(
|
|
PDH_HQUERY hQuery,
|
|
LPCWSTR szFullName,
|
|
DWORD_PTR dwUserData,
|
|
PDH_HCOUNTER * phCounter,
|
|
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 = NULL;
|
|
PPDHI_QUERY pQuery = NULL;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
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);
|
|
}
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_PTR, 1) | ARG_DEF(ARG_TYPE_PTR, 2)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 3),
|
|
ReturnStatus,
|
|
TRACE_PTR(pQuery),
|
|
TRACE_PTR(pNewCounter),
|
|
TRACE_WSTR(szFullName),
|
|
TRACE_DWORD(pNewCounter->dwUserData),
|
|
NULL));
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAddCounterW(
|
|
IN PDH_HQUERY hQuery,
|
|
IN LPCWSTR szFullCounterPath,
|
|
IN DWORD_PTR dwUserData,
|
|
IN PDH_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;
|
|
PDH_HCOUNTER hLocalCounter = NULL;
|
|
PDH_HQUERY hLocalQuery;
|
|
DWORD_PTR dwLocalData;
|
|
|
|
if (szFullCounterPath == NULL || phCounter == NULL) {
|
|
return PDH_INVALID_ARGUMENT;
|
|
}
|
|
__try {
|
|
hLocalQuery = hQuery;
|
|
dwLocalData = dwUserData;
|
|
* phCounter = NULL; // init to null
|
|
|
|
nPathLen = lstrlenW(szFullCounterPath);
|
|
if (nPathLen == 0 || nPathLen > PDH_MAX_COUNTER_PATH) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szFullName = G_ALLOC((nPathLen + 1) * sizeof(WCHAR));
|
|
if (szFullName) {
|
|
StringCchCopyW(szFullName, nPathLen + 1, 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;
|
|
}
|
|
}
|
|
|
|
// query handle is tested by PdhiAddCounter
|
|
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
ReturnStatus = PdhiAddCounter(hLocalQuery, szFullName, dwLocalData, & 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 != NULL) {
|
|
if (pNewCounter->szFullName == NULL) {
|
|
G_FREE(szFullName);
|
|
}
|
|
if (! FreeCounter(pNewCounter)) {
|
|
if (pNewCounter->szFullName != NULL) {
|
|
G_FREE(pNewCounter->szFullName);
|
|
}
|
|
G_FREE(pNewCounter);
|
|
}
|
|
}
|
|
else if (szFullName != NULL) { // allocated this, but not pNewCounter
|
|
G_FREE(szFullName);
|
|
}
|
|
}
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAddCounterA(
|
|
IN PDH_HQUERY hQuery,
|
|
IN LPCSTR szFullCounterPath,
|
|
IN DWORD_PTR dwUserData,
|
|
IN PDH_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;
|
|
PDH_STATUS ReturnStatus = ERROR_SUCCESS;
|
|
PDH_HCOUNTER hLocalCounter = NULL;
|
|
PDH_HQUERY hLocalQuery;
|
|
DWORD_PTR dwLocalData;
|
|
PPDHI_COUNTER pNewCounter = NULL;
|
|
|
|
if (phCounter == NULL || szFullCounterPath == NULL) {
|
|
return PDH_INVALID_ARGUMENT;
|
|
}
|
|
|
|
__try {
|
|
DWORD dwLength = lstrlenA(szFullCounterPath);
|
|
|
|
// try writing to return pointer
|
|
hLocalQuery = hQuery;
|
|
dwLocalData = dwUserData;
|
|
* phCounter = NULL;
|
|
|
|
if (dwLength == 0 || dwLength > PDH_MAX_COUNTER_PATH) {
|
|
ReturnStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szFullName = PdhiMultiByteToWideChar(_getmbcp(), (LPSTR) szFullCounterPath);
|
|
if (szFullName == NULL) {
|
|
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;
|
|
}
|
|
}
|
|
// query handle is tested by PdhiAddCounter
|
|
if (ReturnStatus == ERROR_SUCCESS) {
|
|
ReturnStatus = PdhiAddCounter( hLocalQuery, szFullName, dwLocalData, & 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 != NULL) {
|
|
if (pNewCounter->szFullName == NULL) {
|
|
G_FREE(szFullName);
|
|
}
|
|
if (! FreeCounter(pNewCounter)) {
|
|
if (pNewCounter->szFullName != NULL) {
|
|
G_FREE(pNewCounter->szFullName);
|
|
}
|
|
G_FREE(pNewCounter);
|
|
}
|
|
}
|
|
else if (szFullName != NULL) { // allocated this, but not pNewCounter
|
|
G_FREE(szFullName);
|
|
}
|
|
}
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhRemoveCounter(
|
|
IN PDH_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 PDH_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(
|
|
PPDHI_QUERY pQuery,
|
|
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 PDH_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) {
|
|
TRACE((PDH_DBG_TRACE_ERROR), (__LINE__, PDH_QUERY, 0, lStatus, NULL));
|
|
}
|
|
lStatus = WAIT_FOR_AND_LOCK_MUTEX(pQuery->hMutex);
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
bStatus = CloseHandle(pQuery->hExitEvent);
|
|
pQuery->hExitEvent = NULL;
|
|
bStatus = CloseHandle(pQuery->hAsyncThread);
|
|
pQuery->hAsyncThread = NULL;
|
|
}
|
|
}
|
|
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
// query mutex is still locked at this point
|
|
if (dwIntervalTime > 0) {
|
|
// start a new interval
|
|
// initialize new values
|
|
__try {
|
|
pQuery->dwInterval = dwIntervalTime;
|
|
pQuery->hNewDataEvent = hNewDataEvent;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
lStatus = PDH_INVALID_ARGUMENT;
|
|
}
|
|
if (lStatus == ERROR_SUCCESS) {
|
|
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);
|
|
pQuery->hExitEvent = NULL;
|
|
RELEASE_MUTEX(pQuery->hMutex);
|
|
lStatus = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
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 PDH_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;
|
|
BOOL bReturn = FALSE;
|
|
|
|
if (WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex) == ERROR_SUCCESS) {
|
|
// 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);
|
|
bReturn = TRUE;
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
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 PDH_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(
|
|
LPWSTR szObjectName,
|
|
LPWSTR * szSrcPerfStrings,
|
|
LPWSTR * szDestPerfStrings,
|
|
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(
|
|
BOOL bMachine,
|
|
PPDHI_COUNTER_PATH pCounterPath,
|
|
LPWSTR szObjectName,
|
|
LPWSTR szCounterName,
|
|
LPWSTR szFullPath,
|
|
DWORD dwFullPath
|
|
)
|
|
{
|
|
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) {
|
|
StringCchCopyW(szFullPath, dwFullPath, pCounterPath->szMachineName);
|
|
StringCchCatW(szFullPath, dwFullPath, cszBackSlash);
|
|
}
|
|
else {
|
|
StringCchCopyW(szFullPath, dwFullPath, cszBackSlash);
|
|
}
|
|
StringCchCatW(szFullPath, dwFullPath, szObjectName);
|
|
if (pCounterPath->szInstanceName != NULL && pCounterPath->szInstanceName[0] != L'\0') {
|
|
StringCchCatW(szFullPath, dwFullPath, cszLeftParen);
|
|
if (pCounterPath->szParentName != NULL && pCounterPath->szParentName[0] != L'\0') {
|
|
StringCchCatW(szFullPath, dwFullPath, pCounterPath->szParentName);
|
|
StringCchCatW(szFullPath, dwFullPath, cszSlash);
|
|
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 3)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 4)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 5),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(pCounterPath->szMachineName),
|
|
TRACE_WSTR(szObjectName),
|
|
TRACE_WSTR(szCounterName),
|
|
TRACE_WSTR(pCounterPath->szParentName),
|
|
TRACE_WSTR(pCounterPath->szInstanceName),
|
|
TRACE_DWORD(pCounterPath->dwIndex),
|
|
NULL));
|
|
}
|
|
else {
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 3)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 4),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(pCounterPath->szMachineName),
|
|
TRACE_WSTR(szObjectName),
|
|
TRACE_WSTR(szCounterName),
|
|
TRACE_WSTR(pCounterPath->szInstanceName),
|
|
TRACE_DWORD(pCounterPath->dwIndex),
|
|
NULL));
|
|
}
|
|
StringCchCatW(szFullPath, dwFullPath, pCounterPath->szInstanceName);
|
|
if (pCounterPath->dwIndex != ((DWORD) -1) && pCounterPath->dwIndex != 0) {
|
|
WCHAR szDigits[16];
|
|
|
|
ZeroMemory(szDigits, 16 * sizeof(WCHAR));
|
|
StringCchCatW(szFullPath, dwFullPath, cszPoundSign);
|
|
_ltow((long) pCounterPath->dwIndex, szDigits, 10);
|
|
StringCchCatW(szFullPath, dwFullPath, szDigits);
|
|
}
|
|
StringCchCatW(szFullPath, dwFullPath, cszRightParen);
|
|
}
|
|
else {
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 3),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(pCounterPath->szMachineName),
|
|
TRACE_WSTR(szObjectName),
|
|
TRACE_WSTR(szCounterName),
|
|
TRACE_DWORD(pCounterPath->dwIndex),
|
|
NULL));
|
|
}
|
|
StringCchCatW(szFullPath, dwFullPath, cszBackSlash);
|
|
StringCchCatW(szFullPath, dwFullPath, szCounterName);
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiTranslateCounter(
|
|
LPWSTR szSourcePath,
|
|
LPVOID pFullPathName,
|
|
LPDWORD pcchPathLength,
|
|
BOOL bLocaleTo009,
|
|
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(szStaticLocalMachineName) + 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 = GetMachine(pCounterPath->szMachineName, 0, PDH_GM_UPDATE_PERFNAME_ONLY);
|
|
if (pMachine == NULL) {
|
|
Status = PDH_CSTATUS_NO_MACHINE;
|
|
}
|
|
else if (pMachine->dwStatus != ERROR_SUCCESS) {
|
|
pMachine->dwRefCount --;
|
|
RELEASE_MUTEX(pMachine->hMutex);
|
|
Status = PDH_CSTATUS_NO_MACHINE;
|
|
}
|
|
else {
|
|
LPWSTR szObjectName = NULL;
|
|
LPWSTR szCounterName = NULL;
|
|
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) {
|
|
DWORD dwObjectTitle = wcstoul(pCounterPath->szObjectName, NULL, 10);
|
|
if (dwObjectTitle != 0) {
|
|
szObjectName = pCounterPath->szObjectName;
|
|
}
|
|
}
|
|
if (szCounterName == NULL) {
|
|
DWORD dwCounterTitle = wcstoul(pCounterPath->szCounterName, NULL, 10);
|
|
if (dwCounterTitle != 0) {
|
|
szCounterName = pCounterPath->szCounterName;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
else {
|
|
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;
|
|
}
|
|
else {
|
|
PdhiBuildFullCounterPath(
|
|
bMachineThere, pCounterPath, szObjectName, szCounterName, szRtnPath, dwRtnPathSize);
|
|
__try {
|
|
if (bUnicode) {
|
|
if ((pFullPathName != NULL) && ((* pcchPathLength) >= (DWORD) (lstrlenW(szRtnPath) + 1))) {
|
|
StringCchCopyW(pFullPathName, * pcchPathLength, 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;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
}
|
|
pMachine->dwRefCount --;
|
|
RELEASE_MUTEX(pMachine->hMutex);
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_CSTATUS_BAD_COUNTERNAME;
|
|
}
|
|
|
|
Cleanup:
|
|
G_FREE(szRtnPath);
|
|
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 || pcchPathLength == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
DWORD dwPathLength = * pcchPathLength;
|
|
|
|
if (* szLocalePath == L'\0' || lstrlenW(szLocalePath) > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (dwPathLength > 0) {
|
|
if (pszFullPathName == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
* pszFullPathName = L'\0';
|
|
* (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = L'\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;
|
|
|
|
if (szLocalePath == NULL || pcchPathLength == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
DWORD dwPathLength = * pcchPathLength;
|
|
|
|
if (* szLocalePath == '\0' || lstrlenA(szLocalePath) > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szTmpPath = PdhiMultiByteToWideChar(_getmbcp(), szLocalePath);
|
|
if (szTmpPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
if (dwPathLength > 0) {
|
|
if (pszFullPathName == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
* pszFullPathName = '\0';
|
|
* (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
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 || pcchPathLength == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
DWORD dwPathLength = * pcchPathLength;
|
|
|
|
if (* sz009Path == L'\0' || lstrlenW(sz009Path) > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (dwPathLength > 0) {
|
|
if (pszFullPathName == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
* pszFullPathName = L'\0';
|
|
* (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = L'\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 || pcchPathLength == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
__try {
|
|
DWORD dwPathLength = * pcchPathLength;
|
|
|
|
if (* sz009Path == '\0' || lstrlenA(sz009Path) > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
szTmpPath = PdhiMultiByteToWideChar(CP_ACP, sz009Path);
|
|
if (szTmpPath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
if (dwPathLength > 0) {
|
|
if (pszFullPathName == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
* pszFullPathName = '\0';
|
|
* (LPWSTR) (pszFullPathName + (dwPathLength - 1)) = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhiTranslateCounter(szTmpPath, pszFullPathName, pcchPathLength, FALSE, FALSE);
|
|
}
|
|
G_FREE(szTmpPath);
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAdd009CounterW(
|
|
IN PDH_HQUERY hQuery,
|
|
IN LPWSTR szFullPath,
|
|
IN DWORD_PTR dwUserData,
|
|
OUT PDH_HCOUNTER * phCounter
|
|
)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPWSTR szLocalePath = NULL;
|
|
DWORD dwPathLength;
|
|
|
|
if (szFullPath == NULL || phCounter == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (IsValidQuery(hQuery)) {
|
|
__try {
|
|
DWORD_PTR dwLocalData = dwUserData;
|
|
|
|
* phCounter = NULL;
|
|
dwPathLength = lstrlenW(szFullPath);
|
|
if (dwPathLength > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
dwPathLength ++;
|
|
szLocalePath = G_ALLOC(sizeof(WCHAR) * dwPathLength);
|
|
if (szLocalePath != NULL) {
|
|
Status = PdhTranslateLocaleCounterW(szFullPath, szLocalePath, & dwPathLength);
|
|
while (Status == PDH_MORE_DATA) {
|
|
G_FREE(szLocalePath);
|
|
szLocalePath = G_ALLOC(sizeof(WCHAR) * dwPathLength);
|
|
if (szLocalePath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
Status = PdhTranslateLocaleCounterW(szFullPath, szLocalePath, & dwPathLength);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhAddCounterW(hQuery, szLocalePath, dwUserData, phCounter);
|
|
}
|
|
G_FREE(szLocalePath);
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhAdd009CounterA(
|
|
IN PDH_HQUERY hQuery,
|
|
IN LPSTR szFullPath,
|
|
IN DWORD_PTR dwUserData,
|
|
OUT PDH_HCOUNTER * phCounter
|
|
)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
LPSTR szLocalePath = NULL;
|
|
DWORD dwPathLength;
|
|
|
|
if (szFullPath == NULL || phCounter == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (IsValidQuery(hQuery)) {
|
|
__try {
|
|
DWORD_PTR dwLocalData = dwUserData;
|
|
|
|
* phCounter = NULL;
|
|
dwPathLength = lstrlenA(szFullPath) + 1;
|
|
if (dwPathLength > PDH_MAX_COUNTER_PATH) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
dwPathLength ++;
|
|
szLocalePath = G_ALLOC(sizeof(CHAR) * dwPathLength);
|
|
if (szLocalePath != NULL) {
|
|
Status = PdhTranslateLocaleCounterA(szFullPath, szLocalePath, & dwPathLength);
|
|
while (Status == PDH_MORE_DATA) {
|
|
G_FREE(szLocalePath);
|
|
szLocalePath = G_ALLOC(sizeof(CHAR) * dwPathLength);
|
|
if (szLocalePath == NULL) {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
else {
|
|
Status = PdhTranslateLocaleCounterA(szFullPath, szLocalePath, & dwPathLength);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
else {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = PdhAddCounterA(hQuery, szLocalePath, dwUserData, phCounter);
|
|
}
|
|
G_FREE(szLocalePath);
|
|
return Status;
|
|
}
|
|
|
|
PDH_FUNCTION
|
|
PdhiConvertUnicodeToAnsi(
|
|
UINT uCodePage,
|
|
LPWSTR wszSrc,
|
|
LPSTR aszDest,
|
|
LPDWORD pdwSize
|
|
)
|
|
{
|
|
PDH_STATUS Status = ERROR_SUCCESS;
|
|
DWORD dwDest;
|
|
DWORD dwSrc = 0;
|
|
DWORD dwSize = * pdwSize;
|
|
|
|
if (wszSrc == NULL || pdwSize == NULL) {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else if (* wszSrc == L'\0') {
|
|
Status = PDH_INVALID_ARGUMENT;
|
|
}
|
|
else {
|
|
dwSrc = lstrlenW(wszSrc);
|
|
dwDest = WideCharToMultiByte(uCodePage, 0, wszSrc, dwSrc, NULL, 0, NULL, NULL);
|
|
if (aszDest != NULL && (dwDest + 1) <= dwSize) {
|
|
ZeroMemory(aszDest, dwSize * sizeof(CHAR));
|
|
WideCharToMultiByte(_getmbcp(), 0, wszSrc, dwSrc, aszDest, * pdwSize, NULL, NULL);
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_STR, 2),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(wszSrc),
|
|
TRACE_STR(aszDest),
|
|
TRACE_DWORD(dwSrc),
|
|
TRACE_DWORD(dwDest),
|
|
TRACE_DWORD(dwSize),
|
|
NULL));
|
|
}
|
|
else {
|
|
Status = PDH_MORE_DATA;
|
|
TRACE((PDH_DBG_TRACE_WARNING),
|
|
(__LINE__,
|
|
PDH_QUERY,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
PDH_MORE_DATA,
|
|
TRACE_WSTR(wszSrc),
|
|
TRACE_DWORD(dwSrc),
|
|
TRACE_DWORD(dwDest),
|
|
TRACE_DWORD(dwSize),
|
|
NULL));
|
|
}
|
|
|
|
* pdwSize = dwDest + 1;
|
|
}
|
|
return Status;
|
|
}
|
|
|