windows-nt/Source/XPSP1/NT/sdktools/pdh/pdhlog/log.c
2020-09-26 16:20:57 +08:00

3661 lines
119 KiB
C

/*++
Copyright (C) 1995-1999 Microsoft Corporation
Module Name:
log.c
Abstract:
Log file interface functions exposed in pdh.dll
--*/
#include <windows.h>
#ifndef _PRSHT_H_ // to eliminate W4 errors in commdlg.h
#define _PRSHT_H_
#endif
#include <commdlg.h>
#include <stdlib.h>
#include <assert.h>
#include <mbctype.h>
#include <pdh.h>
#include "pdhidef.h"
//#include "pdhdlgs.h"
#include "strings.h"
#include "log_text.h"
#include "log_bin.h"
#include "log_sql.h"
#include "log_pm.h"
#include "log_wmi.h"
//#include "datasrc.h"
#include "resource.h"
#include "pdhmsg.h"
#pragma warning ( disable : 4213)
// note that when the log file headers are written
// they will be prefixed with a double quote character
LPCSTR szTsvLogFileHeader = "(PDH-TSV 4.0)";
LPCSTR szCsvLogFileHeader = "(PDH-CSV 4.0)";
LPCSTR szBinLogFileHeader = "(PDH-BIN 4.0)";
LPCSTR szTsvType = "PDH-TSV";
LPCSTR szCsvType = "PDH-CSV";
LPCSTR szBinaryType = "PDH-BIN";
const DWORD dwFileHeaderLength = 13;
const DWORD dwTypeLoc = 2;
const DWORD dwVersionLoc = 10;
const DWORD dwFieldLength = 7;
const DWORD dwPerfmonTypeLength = 5; //size in chars
// max mapping size of headers for binary log files
#define PDH_LOG_HEADER_MAP_SIZE 8192
#define VALUE_BUFFER_SIZE 32
typedef struct _FILE_FILTER_INFO {
UINT nDisplayTextResourceId;
LPWSTR szFilterText;
DWORD dwFilterTextSize;
} FILE_FILTER_INFO;
//
// global variables
//
PPDHI_LOG PdhiFirstLogEntry = NULL;
PPDHI_MAPPED_LOG_FILE PdhipFirstLogFile = NULL;
FILE_FILTER_INFO ffiLogFilterInfo[] = {
{IDS_LOGTYPE_PDH_LOGS, (LPWSTR)L"*.blg;*.csv;*.tsv", 17},
{IDS_LOGTYPE_BIN_LOGS, (LPWSTR)L"*.blg", 5},
{IDS_LOGTYPE_CSV_LOGS, (LPWSTR)L"*.csv", 5},
{IDS_LOGTYPE_TSV_LOGS, (LPWSTR)L"*.tsv", 5},
{IDS_LOGTYPE_PM_LOGS, (LPWSTR)L"*.log", 5},
{IDS_LOGTYPE_ALL_LOGS, (LPWSTR)L"*.blg;*.csv;*.tsv;*.log", 23},
{IDS_LOGTYPE_ALL_FILES, (LPWSTR)L"*.*", 4},
{0, NULL, 0}
};
STATIC_DWORD
MakeLogFilterInfoString (
LPWSTR szLogFilter,
DWORD cchLogFilterSize
)
{
FILE_FILTER_INFO *pFFI;
WCHAR szThisEntry[512];
LPWSTR szDestPtr;
LPWSTR szEndPtr;
DWORD dwThisStringLen;
szDestPtr = szLogFilter;
szEndPtr = szDestPtr + cchLogFilterSize;
pFFI = &ffiLogFilterInfo[0];
while ((szEndPtr > szDestPtr) && (pFFI->szFilterText != NULL)) {
dwThisStringLen = LoadStringW(ThisDLLHandle,
pFFI->nDisplayTextResourceId,
szThisEntry, (sizeof(szThisEntry)/sizeof(szThisEntry[0])));
if ((szDestPtr + dwThisStringLen) < szEndPtr) {
// add in this string
lstrcpyW (szDestPtr, szThisEntry);
szDestPtr += dwThisStringLen;
// add in NULL
*szDestPtr++ = 0;
}
dwThisStringLen = pFFI->dwFilterTextSize;
if ((szDestPtr + dwThisStringLen) < szEndPtr) {
// add in this string
lstrcpyW (szDestPtr, pFFI->szFilterText);
szDestPtr += dwThisStringLen;
// add in NULL
*szDestPtr++ = 0;
}
pFFI++;
}
if (szEndPtr > szDestPtr) {
// add MSZ NULL
*szDestPtr++ = 0;
return ERROR_SUCCESS;
} else {
return ERROR_INSUFFICIENT_BUFFER;
}
}
//
// Internal Logging utility functions
//
STATIC_DWORD
OpenReadonlyMappedFile (
PPDHI_LOG pLog,
LPCWSTR szFileName,
PPDHI_MAPPED_LOG_FILE * pFileEntry,
DWORD dwLogType
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwStatus;
DWORD dwSize;
PPDHI_MAPPED_LOG_FILE pOpenedFile;
WCHAR szSectionName[MAX_PATH * 4];
LPWSTR szThisChar;
DWORD dwLoSize, dwHiSize;
dwStatus = WaitForSingleObject (hPdhContextMutex, 10000);
if (dwStatus == WAIT_TIMEOUT) {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
if (pdhStatus == ERROR_SUCCESS) {
if (PdhipFirstLogFile == NULL) {
// then there are no mapped files so create a new entry and
// fill it with this file
pOpenedFile = NULL;
} else {
for (pOpenedFile = PdhipFirstLogFile;
pOpenedFile != NULL;
pOpenedFile = pOpenedFile->pNext) {
if (lstrcmpiW (szFileName, pOpenedFile->szLogFileName) == 0) break;
}
// here pOpenedFile will either be NULL or a ponter
}
if (pOpenedFile == NULL) {
// create a new entry
dwSize = lstrlenW (szFileName) + 1;
dwSize *= sizeof(WCHAR);
dwSize = QWORD_MULTIPLE (dwSize);
dwSize += sizeof (PDHI_MAPPED_LOG_FILE);
pOpenedFile = (PPDHI_MAPPED_LOG_FILE)G_ALLOC (dwSize);
if (pOpenedFile != NULL) {
// initialize the pointers
pOpenedFile->szLogFileName = (LPWSTR)&pOpenedFile[1];
lstrcpyW (pOpenedFile->szLogFileName, szFileName);
pOpenedFile->hFileHandle = CreateFileW (
pOpenedFile->szLogFileName,
GENERIC_READ, // Read Access for input
FILE_SHARE_READ | FILE_SHARE_WRITE, // allow read sharing
NULL, // default security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // ignored
NULL); // no template file
if (pOpenedFile->hFileHandle != INVALID_HANDLE_VALUE) {
DWORD dwPID;
dwPID = GetCurrentProcessId ();
swprintf (szSectionName, (LPCWSTR)L"%s_%8.8x_%s",
cszLogSectionName, dwPID, pOpenedFile->szLogFileName);
// remove filename type characters
for (szThisChar = &szSectionName[0]; *szThisChar != 0; szThisChar++) {
switch (*szThisChar) {
case L'\\':
case L':':
case L'.':
*szThisChar = L'_';
break;
default:
break;
}
}
dwLoSize = GetFileSize (
pOpenedFile->hFileHandle,
& dwHiSize);
pOpenedFile->llFileSize = dwHiSize;
pOpenedFile->llFileSize <<= 32;
pOpenedFile->llFileSize &= 0xFFFFFFFF00000000;
pOpenedFile->llFileSize += dwLoSize;
// just map the header for starters
if (pOpenedFile->llFileSize > 0) {
pLog->iRunidSQL = 0;
if (dwLogType == PDH_LOG_TYPE_RETIRED_BIN) {
pOpenedFile->hMappedFile = CreateFileMappingW(
pOpenedFile->hFileHandle,
NULL,
PAGE_READONLY,
dwHiSize,
dwLoSize,
szSectionName);
if (pOpenedFile->hMappedFile == NULL) {
dwHiSize = 0;
dwLoSize = PDH_LOG_HEADER_MAP_SIZE;
}
else {
pOpenedFile->pData = MapViewOfFile(
pOpenedFile->hMappedFile,
FILE_MAP_READ,
0,
0,
dwLoSize);
if (pOpenedFile->pData == NULL) {
dwHiSize = 0;
dwLoSize = PDH_LOG_HEADER_MAP_SIZE;
}
else {
pLog->iRunidSQL = 1;
}
}
}
if (pLog->iRunidSQL == 0) {
pOpenedFile->hMappedFile = CreateFileMappingW(
pOpenedFile->hFileHandle,
NULL, PAGE_READONLY,
dwHiSize, dwLoSize, szSectionName);
if (pOpenedFile->hMappedFile != NULL) {
pOpenedFile->pData = MapViewOfFile (
pOpenedFile->hMappedFile,
FILE_MAP_READ,
0, 0, dwLoSize);
if (pOpenedFile->pData == NULL) {
pdhStatus = GetLastError();
}
}
else {
pdhStatus = GetLastError();
}
}
} else {
// 0-length file
pdhStatus = ERROR_FILE_INVALID;
}
} else {
pdhStatus = GetLastError();
}
if (pdhStatus == ERROR_SUCCESS) {
// then add this to the list and return the answer
pOpenedFile->pNext = PdhipFirstLogFile;
PdhipFirstLogFile = pOpenedFile;
// init ref count
pOpenedFile->dwRefCount = 1;
*pFileEntry = pOpenedFile;
} else {
// delete it from the list and return NULL
if (pOpenedFile->pData) UnmapViewOfFile (pOpenedFile->pData);
if (pOpenedFile->hMappedFile) CloseHandle (pOpenedFile->hMappedFile);
if (pOpenedFile->hFileHandle) CloseHandle (pOpenedFile->hFileHandle);
G_FREE (pOpenedFile);
*pFileEntry = NULL;
}
} else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
} else {
*pFileEntry = pOpenedFile;
pOpenedFile->dwRefCount++;
}
RELEASE_MUTEX (hPdhContextMutex);
}
return pdhStatus;
}
DWORD
UnmapReadonlyMappedFile (
LPVOID pMemoryBase,
BOOL *bNeedToCloseHandles
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwStatus;
PPDHI_MAPPED_LOG_FILE pOpenedFile;
PPDHI_MAPPED_LOG_FILE pPrevFile = NULL;
dwStatus = WaitForSingleObject (hPdhContextMutex, 10000);
if (dwStatus == WAIT_TIMEOUT) {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
if (pdhStatus == ERROR_SUCCESS) {
// find file to close
for (pOpenedFile = PdhipFirstLogFile;
pOpenedFile != NULL;
pOpenedFile = pOpenedFile->pNext) {
if (pOpenedFile->pData == pMemoryBase) {
break;
} else {
pPrevFile = pOpenedFile;
}
}
// here pOpenedFile will either be NULL or a ponter
if (pOpenedFile != NULL) {
--pOpenedFile->dwRefCount;
if (!pOpenedFile->dwRefCount) {
// found so remove from list and close
if (pOpenedFile == PdhipFirstLogFile) {
PdhipFirstLogFile = pOpenedFile->pNext;
} else {
#pragma warning( disable: 4701 ) // pPrevFile will only be used if the opened log is not the first log
pPrevFile->pNext = pOpenedFile->pNext;
#pragma warning (default : 4701 )
}
// close open resources
if (pOpenedFile->pData) UnmapViewOfFile (pOpenedFile->pData);
if (pOpenedFile->hMappedFile) CloseHandle (pOpenedFile->hMappedFile);
if (pOpenedFile->hFileHandle) CloseHandle (pOpenedFile->hFileHandle);
G_FREE (pOpenedFile);
}
*bNeedToCloseHandles = FALSE;
} else {
// then this must be a normal mapped file
if (!UnmapViewOfFile (pMemoryBase)) {
pdhStatus = GetLastError();
}
*bNeedToCloseHandles = TRUE;
}
RELEASE_MUTEX (hPdhContextMutex);
}
return pdhStatus;
}
STATIC_BOOL
IsValidLogHandle (
IN HLOG hLog
)
/*++
Routine Description:
examines the log handle to verify it is a valid log entry. For now
the test amounts to:
the Handle is NOT NULL
the memory is accessible (i.e. it doesn't AV)
the signature array is valid
the size field is correct
if any tests fail, the handle is presumed to be invalid
Arguments:
IN HLOG hLog
the handle of the log entry to test
Return Value:
TRUE the handle passes all the tests
FALSE one of the test's failed and the handle is not a valid counter
--*/
{
BOOL bReturn = FALSE; // assume it's not a valid query
PPDHI_LOG pLog;
#if DBG
LONG lStatus = ERROR_SUCCESS;
#endif
__try {
if (hLog != NULL) {
// see if a valid signature
pLog = (PPDHI_LOG) hLog;
if ((*(DWORD *)&pLog->signature[0] == SigLog) &&
(pLog->dwLength == sizeof (PDHI_LOG))){
bReturn = TRUE;
} else {
// this is not a valid log entry because the sig is bad
// or the structure is the wrong size
}
} else {
// this is not a valid counter because the handle is NULL
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
// something failed miserably so we can assume this is invalid
#if DBG
lStatus = GetExceptionCode();
#endif
}
return bReturn;
}
STATIC_DWORD
GetLogFileType (
IN HANDLE hLogFile
)
{
CHAR cBuffer[MAX_PATH];
CHAR cType[MAX_PATH];
WCHAR wcType[MAX_PATH];
BOOL bStatus;
DWORD dwResult;
DWORD dwBytesRead;
memset (&cBuffer[0], 0, sizeof(cBuffer));
memset (&cType[0], 0, sizeof(cType));
memset (&wcType[0], 0, sizeof(wcType));
// read first log file record
SetFilePointer (hLogFile, 0, NULL, FILE_BEGIN);
bStatus = ReadFile (hLogFile,
(LPVOID)cBuffer,
dwFileHeaderLength,
&dwBytesRead,
NULL);
if (bStatus) {
// read header record to get type
lstrcpynA (cType, (LPSTR)(cBuffer+dwTypeLoc), dwFieldLength+1);
if (lstrcmpiA(cType, szTsvType) == 0) {
dwResult = PDH_LOG_TYPE_TSV;
} else if (lstrcmpiA(cType, szCsvType) == 0) {
dwResult = PDH_LOG_TYPE_CSV;
} else if (lstrcmpiA(cType, szBinaryType) == 0) {
dwResult = PDH_LOG_TYPE_RETIRED_BIN;
} else {
// perfmon log file type string is in a different
// location than sysmon logs and used wide chars.
lstrcpynW (wcType, (LPWSTR)cBuffer, dwPerfmonTypeLength+1);
if (lstrcmpiW(wcType, cszPerfmonLogSig) == 0) {
dwResult = PDH_LOG_TYPE_PERFMON;
} else {
dwResult = PDH_LOG_TYPE_UNDEFINED;
}
}
} else {
// unable to read file
dwResult = PDH_LOG_TYPE_UNDEFINED;
}
return dwResult;
}
STATIC_PDH_FUNCTION
CreateNewLogEntry (
IN LPCWSTR szLogFileName,
IN HQUERY hQuery,
IN DWORD dwMaxSize,
IN PPDHI_LOG *pLog
)
/*++
creates a new log entry and inserts it in the list of open log files
--*/
{
PPDHI_LOG pNewLog;
PPDHI_LOG pFirstLog;
PPDHI_LOG pLastLog;
DWORD dwSize;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwLogFileNameSize;
dwLogFileNameSize = lstrlenW(szLogFileName) + 1;
dwSize = dwLogFileNameSize;
dwSize *= sizeof (WCHAR);
dwSize *= 2; // double to make room for cat file name
dwSize = DWORD_MULTIPLE (dwSize); // ... rounded to the next DWORD
dwSize += sizeof (PDHI_LOG); // + room for the data block
pNewLog = G_ALLOC (dwSize); // allocate new structure
if (pNewLog == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
*pLog = NULL;
} else {
// initialize the elements in the structure
*((LPDWORD)(&pNewLog->signature[0])) = SigLog;
// create and acquire a data mutex for this
pNewLog->hLogMutex = CreateMutexW (NULL, TRUE, NULL);
assert (pNewLog->hLogMutex != NULL);
// insert this item at the end of the list
if (PdhiFirstLogEntry == NULL) {
// then this is the first entry
PdhiFirstLogEntry = pNewLog;
pNewLog->next.flink =
pNewLog->next.blink = pNewLog;
} else {
// go to the first entry and insert this one just before it
pFirstLog = PdhiFirstLogEntry;
pLastLog = pFirstLog->next.blink;
pNewLog->next.flink = pLastLog->next.flink;
pLastLog->next.flink = pNewLog;
pNewLog->next.blink = pFirstLog->next.blink;
pFirstLog->next.blink = pNewLog;
}
// set length field (this is used more for validation
// than anything else
pNewLog->dwLength = sizeof (PDHI_LOG);
// append filename strings immediately after this block
pNewLog->szLogFileName = (LPWSTR)(&pNewLog[1]);
lstrcpyW (pNewLog->szLogFileName, szLogFileName);
// locate catalog name immediately after log file name
pNewLog->szCatFileName = pNewLog->szLogFileName + dwLogFileNameSize;
//
// NOTE: Catalog should be in the logfile itself, so no need for
// yet another file extension
lstrcpyW (pNewLog->szCatFileName, szLogFileName);
// initialize the file handles
pNewLog->hLogFileHandle = INVALID_HANDLE_VALUE;
pNewLog->hCatFileHandle = INVALID_HANDLE_VALUE;
// initialize the Record Length size
pNewLog->llMaxSize = (LONGLONG) ((ULONGLONG) dwMaxSize);
pNewLog->dwRecord1Size = 0;
// assign the query
pNewLog->pQuery = (PPDHI_QUERY)hQuery;
pNewLog->dwLogFormat = 0; // for now
pNewLog->pPerfmonInfo = NULL;
*pLog = pNewLog;
}
return pdhStatus;
}
OpenSQLLog (
IN PPDHI_LOG pLog,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
pLog->dwLogFormat = PDH_LOG_TYPE_SQL;
pLog->dwLogFormat |=
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) == PDH_LOG_WRITE_ACCESS) {
pdhStatus = PdhiOpenOutputSQLLog (pLog);
} else {
pdhStatus = PdhiOpenInputSQLLog (pLog);
}
*lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
return pdhStatus;
}
STATIC_PDH_FUNCTION
OpenInputLogFile (
IN PPDHI_LOG pLog,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType
)
{
LONG Win32Error;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwFileCreate = 0;
PPDHI_MAPPED_LOG_FILE pMappedFileInfo = NULL;
// for input, the query handle is NULL
pLog->pQuery = NULL;
////////////////
// SQL goes here
///////////////
// First test whether logfile is WMI Event Trace format.
// If all logfiles are WMI Event Trace format, return immediately;
// otherwise try other formats.
//
pdhStatus = PdhiOpenInputWmiLog(pLog);
if (pdhStatus == ERROR_SUCCESS) {
pLog->dwLogFormat = PDH_LOG_TYPE_BINARY;
pLog->dwLogFormat |=
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
* lpdwLogType = PDH_LOG_TYPE_BINARY;
return pdhStatus;
}
pdhStatus = ERROR_SUCCESS;
// open file for input based on the specified access flags
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_OPEN_EXISTING:
dwFileCreate = OPEN_EXISTING;
break;
case PDH_LOG_CREATE_NEW:
case PDH_LOG_CREATE_ALWAYS:
case PDH_LOG_OPEN_ALWAYS:
// a log file to be read from must not be empty or non-existent
default:
// unrecognized value
pdhStatus = PDH_INVALID_ARGUMENT;
break;
}
if (pdhStatus == ERROR_SUCCESS) {
pLog->hLogFileHandle = CreateFileW (
pLog->szLogFileName,
GENERIC_READ, // Read Access for input
FILE_SHARE_READ | FILE_SHARE_WRITE, // allow read sharing
NULL, // default security
dwFileCreate,
FILE_ATTRIBUTE_NORMAL, // ignored
NULL); // no template file
if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
Win32Error = GetLastError();
// translate to PDH_ERROR
switch (Win32Error) {
case ERROR_FILE_NOT_FOUND:
pdhStatus = PDH_FILE_NOT_FOUND;
break;
case ERROR_ALREADY_EXISTS:
pdhStatus = PDH_FILE_ALREADY_EXISTS;
break;
default:
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_CREATE_NEW:
case PDH_LOG_CREATE_ALWAYS:
pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
break;
case PDH_LOG_OPEN_EXISTING:
case PDH_LOG_OPEN_ALWAYS:
default:
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
break;
}
break;
}
}
}
if (pdhStatus == ERROR_SUCCESS) {
// read the log header and determine the log file type
pLog->dwLogFormat = GetLogFileType (pLog->hLogFileHandle);
if (pLog->dwLogFormat != 0) {
pLog->dwLogFormat |=
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
} else {
pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
}
switch (LOWORD(pLog->dwLogFormat)) {
break;
case PDH_LOG_TYPE_RETIRED_BIN:
case PDH_LOG_TYPE_PERFMON:
// close file opened above
CloseHandle (pLog->hLogFileHandle);
pLog->iRunidSQL = 0;
pdhStatus = OpenReadonlyMappedFile (
pLog,
pLog->szLogFileName,
& pMappedFileInfo,
(DWORD) LOWORD(pLog->dwLogFormat));
if (pdhStatus == ERROR_SUCCESS) {
// then update log fields
pLog->hLogFileHandle = pMappedFileInfo->hFileHandle;
pLog->hMappedLogFile = pMappedFileInfo->hMappedFile;
pLog->lpMappedFileBase = pMappedFileInfo->pData;
pLog->llFileSize = pMappedFileInfo->llFileSize;
}
break;
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
default:
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiOpenInputTextLog (pLog);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiOpenInputBinaryLog (pLog);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiOpenInputPerfmonLog (pLog);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
*lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
OpenUpdateLogFile (
IN PPDHI_LOG pLog,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType
)
{
LONG Win32Error;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwFileCreate = 0;
// for input, the query handle is NULL
pLog->pQuery = NULL;
// open file for input based on the specified access flags
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_OPEN_EXISTING:
dwFileCreate = OPEN_EXISTING;
break;
case PDH_LOG_CREATE_NEW:
case PDH_LOG_CREATE_ALWAYS:
case PDH_LOG_OPEN_ALWAYS:
// a log file to be updated must not be empty or non-existent
default:
// unrecognized value
pdhStatus = PDH_INVALID_ARGUMENT;
break;
}
if (pdhStatus == ERROR_SUCCESS) {
pLog->hLogFileHandle = CreateFileW (
pLog->szLogFileName,
GENERIC_READ | GENERIC_WRITE, // Read & Write Access for input
FILE_SHARE_READ, // allow read sharing
NULL, // default security
dwFileCreate,
FILE_ATTRIBUTE_NORMAL, // ignored
NULL); // no template file
if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
Win32Error = GetLastError();
// translate to PDH_ERROR
switch (Win32Error) {
case ERROR_FILE_NOT_FOUND:
pdhStatus = PDH_FILE_NOT_FOUND;
break;
case ERROR_ALREADY_EXISTS:
pdhStatus = PDH_FILE_ALREADY_EXISTS;
break;
default:
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_CREATE_NEW:
case PDH_LOG_CREATE_ALWAYS:
pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
break;
case PDH_LOG_OPEN_EXISTING:
case PDH_LOG_OPEN_ALWAYS:
default:
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
break;
}
break;
}
}
}
if (pdhStatus == ERROR_SUCCESS) {
// read the log header and determine the log file type
pLog->dwLogFormat = GetLogFileType (pLog->hLogFileHandle);
if (pLog->dwLogFormat != 0) {
pLog->dwLogFormat |=
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
} else {
pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
}
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
case PDH_LOG_TYPE_BINARY:
// this will be added later
// updating a text file will be limited to appending, but that
// has it's own problems (e.g. insuring the counter list
// is the same in the new query as the one stored in the log file
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiOpenUpdateBinaryLog (pLog);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
*lpdwLogType = (DWORD)(LOWORD(pLog->dwLogFormat));
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
OpenOutputLogFile (
IN PPDHI_LOG pLog,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType
)
{
LONG Win32Error;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwFileCreate = 0;
// for output, the query handle must be valid
if (!IsValidQuery ((HQUERY)pLog->pQuery)) {
pdhStatus = PDH_INVALID_HANDLE;
}
// special handling PDH_LOG_TYPE_BINARY
//
if (* lpdwLogType == PDH_LOG_TYPE_BINARY) {
* lpdwLogType = PDH_LOG_TYPE_BINARY;
pLog->dwLogFormat =
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
pLog->dwLogFormat |=
*lpdwLogType & ~(PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
return (PdhiOpenOutputWmiLog(pLog));
}
// open file for output based on the specified access flags
if (pdhStatus == ERROR_SUCCESS) {
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_CREATE_NEW:
dwFileCreate = CREATE_NEW;
break;
case PDH_LOG_CREATE_ALWAYS:
dwFileCreate = CREATE_ALWAYS;
break;
case PDH_LOG_OPEN_EXISTING:
dwFileCreate = OPEN_EXISTING;
break;
case PDH_LOG_OPEN_ALWAYS:
dwFileCreate = OPEN_ALWAYS;
break;
default:
// unrecognized value
pdhStatus = PDH_INVALID_ARGUMENT;
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pLog->hLogFileHandle = CreateFileW (
pLog->szLogFileName,
GENERIC_WRITE | GENERIC_READ, // write access for output
FILE_SHARE_READ, // allow read sharing
NULL, // default security
dwFileCreate,
FILE_ATTRIBUTE_NORMAL,
NULL); // no template file
if (pLog->hLogFileHandle == INVALID_HANDLE_VALUE) {
Win32Error = GetLastError();
// translate to PDH_ERROR
switch (Win32Error) {
case ERROR_FILE_NOT_FOUND:
pdhStatus = PDH_FILE_NOT_FOUND;
break;
case ERROR_ALREADY_EXISTS:
pdhStatus = PDH_FILE_ALREADY_EXISTS;
break;
default:
switch (dwAccessFlags & PDH_LOG_CREATE_MASK) {
case PDH_LOG_CREATE_NEW:
case PDH_LOG_CREATE_ALWAYS:
pdhStatus = PDH_LOG_FILE_CREATE_ERROR;
break;
case PDH_LOG_OPEN_EXISTING:
case PDH_LOG_OPEN_ALWAYS:
default:
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
break;
}
break;
}
}
}
if (pdhStatus == ERROR_SUCCESS) {
// the file opened successfully so update the data structure
// this assumes the access flags are in the HIWORD and the...
pLog->dwLogFormat =
dwAccessFlags & (PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
// the type id is in the LOWORD
pLog->dwLogFormat |=
*lpdwLogType & ~(PDH_LOG_ACCESS_MASK | PDH_LOG_OPT_MASK);
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiOpenOutputTextLog(pLog);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
case PDH_LOG_TYPE_SQL:
// SQL data soruce should be handled in PdhOpenLogW() before
// it calls OpenOutputLogFile(). If it goes here, this is
// an incorrect SQL datasoruce format.
//
pdhStatus = PDH_INVALID_SQL_LOG_FORMAT;
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
WriteLogHeader (
IN PPDHI_LOG pLog,
IN LPCWSTR szUserCaption
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiWriteTextLogHeader (pLog, szUserCaption);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiWriteBinaryLogHeader (pLog, szUserCaption);
break;
case PDH_LOG_TYPE_BINARY:
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiWriteSQLLogHeader (pLog, szUserCaption);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
DeleteLogEntry (
PPDHI_LOG pLog
)
{
PDH_STATUS pdhStatus;
PPDHI_LOG pLogNext;
// assumes structure is locked
if (IsValidLogHandle ((HLOG)pLog)) {
if (PdhiFirstLogEntry == pLog) {
// then this is the first entry in the list so the
// the "first" entry will be the next forward entry
if ((pLog->next.flink == pLog->next.blink) &&
(pLog->next.flink == pLog)){
// then this is the only entry in the list so clear the first
// log entry
PdhiFirstLogEntry = NULL;
} else {
// remove this entry from the list
(pLog->next.flink)->next.blink = pLog->next.blink;
(pLog->next.blink)->next.flink = pLog->next.flink;
PdhiFirstLogEntry = pLog->next.flink;
}
} else {
// it's not the first one, so
// just remove it from the list
(pLog->next.flink)->next.blink = pLog->next.blink;
(pLog->next.blink)->next.flink = pLog->next.flink;
}
// and release the memory block;
RELEASE_MUTEX (pLog->hLogMutex);
CloseHandle (pLog->hLogMutex);
while (pLog) {
pLogNext = pLog->NextLog;
G_FREE (pLog);
pLog = pLogNext;
}
pdhStatus = ERROR_SUCCESS;
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
CloseAndDeleteLogEntry (
IN PPDHI_LOG pLog,
IN DWORD dwFlags,
IN BOOLEAN bForceDelete
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
BOOL bStatus;
BOOL bNeedToCloseHandles = TRUE;
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiCloseTextLog(pLog, dwFlags);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiCloseBinaryLog(pLog, dwFlags);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiClosePerfmonLog(pLog, dwFlags);
break;
case PDH_LOG_TYPE_BINARY:
pdhStatus = PdhiCloseWmiLog(pLog, dwFlags);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiCloseSQLLog(pLog, dwFlags);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
if (bForceDelete || pdhStatus == ERROR_SUCCESS) {
if (pLog->lpMappedFileBase != NULL) {
UnmapReadonlyMappedFile (pLog->lpMappedFileBase, &bNeedToCloseHandles);
} else {
// if this wasn't a mapped file, then delete
// the "current record" buffer
if (pLog->pLastRecordRead != NULL) {
G_FREE (pLog->pLastRecordRead);
pLog->pLastRecordRead = NULL;
}
}
if (bNeedToCloseHandles) {
if (pLog->hMappedLogFile != NULL) {
bStatus = CloseHandle (pLog->hMappedLogFile);
assert (bStatus);
pLog->hMappedLogFile = NULL;
}
if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
bStatus = CloseHandle (pLog->hLogFileHandle);
assert (bStatus);
pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
}
} else {
// the handles have already been closed so just
// clear their values
pLog->lpMappedFileBase = NULL;
pLog->hMappedLogFile = NULL;
pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
}
if (pLog->pPerfmonInfo != NULL) {
G_FREE (pLog->pPerfmonInfo);
pLog->pPerfmonInfo = NULL;
}
pLog->dwLastRecordRead = 0;
if (pLog->hCatFileHandle != INVALID_HANDLE_VALUE) {
bStatus = CloseHandle (pLog->hCatFileHandle);
assert (bStatus);
pLog->hCatFileHandle = INVALID_HANDLE_VALUE;
}
if ((dwFlags & PDH_FLAGS_CLOSE_QUERY) == PDH_FLAGS_CLOSE_QUERY) {
pdhStatus = PdhCloseQuery ((HQUERY)pLog->pQuery);
}
pdhStatus = DeleteLogEntry (pLog);
}
return pdhStatus;
}
//
// Local utility functions
//
PDH_FUNCTION
PdhiGetLogCounterInfo (
IN HLOG hLog,
IN PPDHI_COUNTER pCounter
)
// validates the counter is in the log file and initializes the data fields
{
PPDHI_LOG pLog;
PDH_STATUS pdhStatus;
if (IsValidLogHandle(hLog)) {
pLog = (PPDHI_LOG)hLog;
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiGetTextLogCounterInfo (
pLog, pCounter);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiGetBinaryLogCounterInfo (
pLog, pCounter);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiGetPerfmonLogCounterInfo (
pLog, pCounter);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiGetSQLLogCounterInfo (
pLog, pCounter);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
return pdhStatus;
}
DWORD
AddUniqueWideStringToMultiSz (
IN LPVOID mszDest,
IN LPWSTR szSource,
IN BOOL bUnicodeDest
)
/*++
Routine Description:
searches the Multi-SZ list, mszDest for szSource and appends it
to mszDest if it wasn't found
Arguments:
OUT LPVOID mszDest Multi-SZ list to get new string
IN LPWSTR szSource string to add if it's not already in list
ReturnValue:
The new length of the destination string including both
trailing NULL characters if the string was added, or 0 if the
string is already in the list.
--*/
{
LPVOID szDestElem;
DWORD dwReturnLength;
LPSTR aszSource = NULL;
DWORD dwLength;
// check arguments
if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
if (*szSource == '\0') return 0; // no source string to add
// if not a unicode list, make an ansi copy of the source string to
// compare
// and ultimately copy if it's not already in the list
if (!bUnicodeDest) {
dwLength = lstrlenW(szSource) + 1;
aszSource = G_ALLOC ((dwLength * 3 * sizeof(CHAR))); // DBCS concern
if (aszSource != NULL) {
dwReturnLength = WideCharToMultiByte(_getmbcp(),
0,
szSource,
lstrlenW(szSource),
aszSource,
dwLength,
NULL,
NULL);
} else {
// unable to allocate memory for the temp string
dwReturnLength = 0;
}
} else {
// just use the ANSI version of the source file name
dwReturnLength = 1;
}
if (dwReturnLength > 0) {
// go to end of dest string
//
for (szDestElem = mszDest;
(bUnicodeDest ? (*(LPWSTR)szDestElem != 0) :
(*(LPSTR)szDestElem != 0));
) {
if (bUnicodeDest) {
// bail out if string already in list
if (lstrcmpiW((LPCWSTR)szDestElem, szSource) == 0) {
dwReturnLength = 0;
goto AddString_Bailout;
} else {
// goto the next item
szDestElem = (LPVOID)((LPWSTR)szDestElem +
(lstrlenW((LPCWSTR)szDestElem)+1));
}
} else {
// bail out if string already in list
if (lstrcmpiA((LPSTR)szDestElem, aszSource) == 0) {
dwReturnLength = 0;
goto AddString_Bailout;
} else {
// goto the next item
szDestElem = (LPVOID)((LPSTR)szDestElem +
(lstrlenA((LPCSTR)szDestElem)+1));
}
}
}
// if here, then add string
// szDestElem is at end of list
if (bUnicodeDest) {
lstrcpyW ((LPWSTR)szDestElem, szSource);
szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(szSource) + 1);
*((LPWSTR)szDestElem) = L'\0';
dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest);
} else {
lstrcpyA ((LPSTR)szDestElem, aszSource);
szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1);
*((LPSTR)szDestElem) = '\0'; // add second NULL
dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest);
}
}
AddString_Bailout:
if (aszSource != NULL) {
G_FREE (aszSource);
}
return (DWORD)dwReturnLength;
}
DWORD
AddUniqueStringToMultiSz (
IN LPVOID mszDest,
IN LPSTR szSource,
IN BOOL bUnicodeDest
)
/*++
Routine Description:
searches the Multi-SZ list, mszDest for szSource and appends it
to mszDest if it wasn't found
Arguments:
OUT LPVOID mszDest Multi-SZ list to get new string
IN LPSTR szSource string to add if it's not already in list
ReturnValue:
The new length of the destination string including both
trailing NULL characters if the string was added, or 0 if the
string is already in the list.
--*/
{
LPVOID szDestElem;
DWORD dwReturnLength;
LPWSTR wszSource = NULL;
DWORD dwLength;
// check arguments
if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
if (*szSource == '\0') return 0; // no source string to add
// if unicode list, make a unicode copy of the source string to compare
// and ultimately copy if it's not already in the list
if (bUnicodeDest) {
dwLength = lstrlenA(szSource);
wszSource = G_ALLOC ((dwLength + 1) * sizeof(WCHAR));
if (wszSource != NULL) {
dwReturnLength = MultiByteToWideChar(
_getmbcp(),
0,
szSource,
dwLength,
(LPWSTR) wszSource,
dwLength + 1);
} else {
// unable to allocate memory for the temp string
dwReturnLength = 0;
}
} else {
// just use the ANSI version of the source file name
dwReturnLength = 1;
}
if (dwReturnLength > 0) {
// go to end of dest string
//
for (szDestElem = mszDest;
(bUnicodeDest ? (*(LPWSTR)szDestElem != 0) :
(*(LPSTR)szDestElem != 0));
) {
if (bUnicodeDest) {
// bail out if string already in lsit
if (lstrcmpiW((LPCWSTR)szDestElem, wszSource) == 0) {
dwReturnLength = 0;
goto AddString_Bailout;
} else {
// goto the next item
szDestElem = (LPVOID)((LPWSTR)szDestElem +
(lstrlenW((LPCWSTR)szDestElem)+1));
}
} else {
// bail out if string already in list
if (lstrcmpiA((LPSTR)szDestElem, szSource) == 0) {
dwReturnLength = 0;
goto AddString_Bailout;
} else {
// goto the next item
szDestElem = (LPVOID)((LPSTR)szDestElem +
(lstrlenA((LPCSTR)szDestElem)+1));
}
}
}
// if here, then add string
// szDestElem is at end of list
if (bUnicodeDest) {
lstrcpyW ((LPWSTR)szDestElem, wszSource);
szDestElem = (LPVOID)((LPWSTR)szDestElem + lstrlenW(wszSource) + 1);
*((LPWSTR)szDestElem) = L'\0';
dwReturnLength = (DWORD)((LPWSTR)szDestElem - (LPWSTR)mszDest);
} else {
lstrcpyA ((LPSTR)szDestElem, szSource);
szDestElem = (LPVOID)((LPSTR)szDestElem + lstrlenA(szDestElem) + 1);
*((LPSTR)szDestElem) = '\0'; // add second NULL
dwReturnLength = (DWORD)((LPSTR)szDestElem - (LPSTR)mszDest);
}
}
AddString_Bailout:
if (wszSource != NULL) {
G_FREE (wszSource);
}
return (DWORD) dwReturnLength;
}
//
// Exported Logging Functions
//
PDH_FUNCTION
PdhOpenLogW (
IN LPCWSTR szLogFileName,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType,
IN HQUERY hQuery,
IN DWORD dwMaxSize,
IN LPCWSTR szUserCaption,
IN HLOG *phLog
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwLocalLogType = 0;
PPDHI_LOG pLog;
WCHAR wcType[VALUE_BUFFER_SIZE];
if ((szLogFileName == NULL) ||
(lpdwLogType == NULL) ||
(phLog == NULL)) {
pdhStatus = PDH_INVALID_ARGUMENT;
} else {
__try {
if (*szLogFileName == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
dwLocalLogType = *lpdwLogType;
* lpdwLogType = dwLocalLogType;
if (szUserCaption != NULL) {
// if not NULL, it must be valid
if (*szUserCaption == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} else {
// NULL is a valid argument
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
// something failed so give up here
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (hPdhDataMutex);
if (pdhStatus == ERROR_SUCCESS) {
// create a log entry
// if successful, this also acquires the lock for this structure
pdhStatus = CreateNewLogEntry (
(LPCWSTR)szLogFileName,
hQuery,
dwMaxSize,
&pLog);
// Here we must check for SQL: in the file name, and branch off to do SQL
// Processing /end SJM/
// open the file
if (pdhStatus == ERROR_SUCCESS) {
// find out if SQL file type
ZeroMemory((LPWSTR) wcType, sizeof(WCHAR) * VALUE_BUFFER_SIZE);
lstrcpynW((LPWSTR) wcType,
(LPWSTR) szLogFileName,
lstrlenW(cszSQL) + 1);
if (lstrcmpiW((LPWSTR)wcType, (LPWSTR) cszSQL) == 0) {
dwLocalLogType = PDH_LOG_TYPE_SQL;
pLog->llMaxSize = (LONGLONG) ((ULONGLONG) dwMaxSize);
pdhStatus = OpenSQLLog(pLog, dwAccessFlags, &dwLocalLogType);
if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) == PDH_LOG_WRITE_ACCESS) {
pLog->pQuery->hOutLog = (HLOG) pLog;
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = WriteLogHeader (pLog, (LPCWSTR)szUserCaption);
}
}
// dispatch based on read/write attribute
} else if ((dwAccessFlags & PDH_LOG_READ_ACCESS) ==
PDH_LOG_READ_ACCESS) {
pdhStatus = OpenInputLogFile (pLog,
dwAccessFlags, &dwLocalLogType);
} else if ((dwAccessFlags & PDH_LOG_WRITE_ACCESS) ==
PDH_LOG_WRITE_ACCESS) {
pdhStatus = OpenOutputLogFile (pLog,
dwAccessFlags,
&dwLocalLogType);
if (pdhStatus == ERROR_SUCCESS) {
pLog->pQuery->hOutLog = (HLOG) pLog;
pdhStatus = WriteLogHeader (pLog,
(LPCWSTR)szUserCaption);
}
} else if ((dwAccessFlags & PDH_LOG_UPDATE_ACCESS) ==
PDH_LOG_UPDATE_ACCESS) {
pdhStatus = OpenUpdateLogFile (pLog,
dwAccessFlags, &dwLocalLogType);
} else {
pdhStatus = PDH_INVALID_ARGUMENT;
}
if (pdhStatus == ERROR_SUCCESS) {
__try {
// return handle to caller
*phLog = (HLOG)pLog;
*lpdwLogType = dwLocalLogType;
} __except (EXCEPTION_EXECUTE_HANDLER) {
// something failed so give up here
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
// release the lock for the next thread
if (pdhStatus != ERROR_SUCCESS) {
// unable to complete this operation so toss this entry
// since it isn't really a valid log entry.
// NOTE: DeleteLogEntry will release the mutex
DeleteLogEntry (pLog);
}
else {
RELEASE_MUTEX (pLog->hLogMutex);
}
}
RELEASE_MUTEX (hPdhDataMutex);
} else {
// unable to lock global data structures
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhOpenLogA (
IN LPCSTR szLogFileName,
IN DWORD dwAccessFlags,
IN LPDWORD lpdwLogType,
IN HQUERY hQuery,
IN DWORD dwMaxRecords,
IN LPCSTR szUserCaption,
IN HLOG *phLog
)
{
LPWSTR wszLogName = NULL;
LPWSTR wszUserCaption = NULL;
DWORD dwSize;
DWORD dwLocalLogType;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
if ((szLogFileName == NULL) ||
(lpdwLogType == NULL) ||
(phLog == NULL)) {
pdhStatus = PDH_INVALID_ARGUMENT;
} else {
__try {
if (*szLogFileName == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
dwLocalLogType = *lpdwLogType; // test read
* lpdwLogType = dwLocalLogType;
if (szUserCaption != NULL) {
// if not NULL, it must be valid
if (*szUserCaption == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} else {
// NULL is a valid argument
}
if (pdhStatus == ERROR_SUCCESS) {
// copy ANSI names to Wide Character strings
dwSize = lstrlenA (szLogFileName);
wszLogName = (LPWSTR)G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
if (wszLogName != NULL) {
MultiByteToWideChar(_getmbcp(),
0,
szLogFileName,
dwSize,
(LPWSTR) wszLogName,
dwSize + 1);
}
if (szUserCaption != NULL) {
dwSize = lstrlenA (szUserCaption);
wszUserCaption = (LPWSTR)G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
if (wszUserCaption != NULL) {
MultiByteToWideChar(_getmbcp(),
0,
szUserCaption,
dwSize,
(LPWSTR) wszUserCaption,
dwSize + 1);
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
// assume a bad parameter caused the exception
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhOpenLogW (
wszLogName,
dwAccessFlags,
&dwLocalLogType,
hQuery,
dwMaxRecords,
wszUserCaption,
phLog);
__try {
// return handle to caller
*lpdwLogType = dwLocalLogType;
} __except (EXCEPTION_EXECUTE_HANDLER) {
// something failed so give up here
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (wszLogName != NULL) {
G_FREE (wszLogName);
}
if (wszUserCaption != NULL) {
G_FREE (wszUserCaption);
}
return pdhStatus;
}
PDH_FUNCTION
PdhUpdateLogW (
IN HLOG hLog,
IN LPCWSTR szUserString
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
SYSTEMTIME st;
FILETIME ft;
PPDHI_LOG pLog;
if (szUserString != NULL) {
__try {
if (*szUserString == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} else {
//NULL is ok
}
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
// make sure it's still valid as it could have
// been deleted while we were waiting
if (IsValidLogHandle (hLog)) {
if (pLog->pQuery == NULL) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
else {
// get the timestamp and update the log's query,
// then write the data to the log file in the
// appropriate format
// update data samples
pdhStatus = PdhiCollectQueryData(
(HQUERY) pLog->pQuery, (LONGLONG *) & ft);
if (pdhStatus == ERROR_SUCCESS) {
FILETIME LocFileTime;
if (DataSourceTypeH(pLog->pQuery->hLog)
== DATA_SOURCE_REGISTRY) {
FileTimeToLocalFileTime(& ft, & LocFileTime);
}
else {
LocFileTime = ft;
}
FileTimeToSystemTime(& LocFileTime, & st);
}
else {
GetLocalTime(& st);
}
// test for end of log file in case the caller is
// reading from a log file. If this value is returned,
// then don't update the output log file any more.
if (pdhStatus != PDH_NO_MORE_DATA) {
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus =PdhiWriteTextLogRecord (
pLog,
&st,
(LPCWSTR)szUserString);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus =PdhiWriteBinaryLogRecord (
pLog,
&st,
(LPCWSTR)szUserString);
break;
case PDH_LOG_TYPE_BINARY:
pdhStatus = PdhiWriteWmiLogRecord(
pLog,
&st,
(LPCWSTR) szUserString);
break;
// add case for SQL
case PDH_LOG_TYPE_SQL:
pdhStatus =PdhiWriteSQLLogRecord (
pLog,
&st,
(LPCWSTR)szUserString);
break;
case PDH_LOG_TYPE_PERFMON:
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
// return the NO_MORE_DATA error to the caller
// so they know not to call this function any more
}
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
} // else couldn't lock the log
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhUpdateLogA (
IN HLOG hLog,
IN LPCSTR szUserString
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
LPWSTR wszLocalUserString = NULL;
DWORD dwUserStringLen;
__try {
if (szUserString != NULL) {
if (*szUserString == 0) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} else {
//NULL is ok
}
if (pdhStatus == ERROR_SUCCESS) {
if (szUserString != NULL) {
dwUserStringLen = lstrlenA(szUserString);
wszLocalUserString = (LPWSTR)G_ALLOC (
(dwUserStringLen + 1) * sizeof (WCHAR));
if (wszLocalUserString != NULL) {
MultiByteToWideChar(_getmbcp(),
0,
szUserString,
dwUserStringLen,
(LPWSTR) wszLocalUserString,
dwUserStringLen + 1);
} else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
} // else continue with NULL pointer
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhUpdateLogW (hLog, wszLocalUserString);
}
if (wszLocalUserString != NULL) {
G_FREE (wszLocalUserString);
}
return pdhStatus;
}
PDH_FUNCTION
PdhUpdateLogFileCatalog (
IN HLOG hLog
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_LOG pLog;
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
// make sure it's still valid as it could have
// been deleted while we were waiting
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_SQL:
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiUpdateBinaryLogFileCatalog (pLog);
break;
case PDH_LOG_TYPE_PERFMON:
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhCloseLog(
IN HLOG hLog,
IN DWORD dwFlags
)
{
PDH_STATUS pdhStatus;
PPDHI_LOG pLog;
if (hLog == H_REALTIME_DATASOURCE || hLog == H_WBEM_DATASOURCE) {
// return immediately if datasource is realtime or wbem
//
return ERROR_SUCCESS;
}
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
// make sure it's still valid as it could have
// been deleted while we were waiting
if (IsValidLogHandle (hLog)) {
// this will release and delete the mutex
pdhStatus = CloseAndDeleteLogEntry (pLog, dwFlags, FALSE);
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
return pdhStatus;
}
BOOL
PdhiBrowseDataSource (
IN HWND hWndParent,
IN LPVOID szFileName,
IN LPDWORD pcchFileNameSize,
IN BOOL bUnicodeString
)
{
OPENFILENAMEW ofn;
LPWSTR szTempString = NULL;
LPWSTR szDirString = NULL;
LPWSTR szTempFileName = NULL;
BOOL bReturn;
LPWSTR szMsg;
WCHAR szLogFilterString[512];
LPWSTR szLogFilter;
if (szFileName == NULL) {
SetLastError(PDH_INVALID_ARGUMENT);
return FALSE;
}
// clear last error
SetLastError (ERROR_SUCCESS);
szTempString = G_ALLOC (* pcchFileNameSize * sizeof(WCHAR) * 2);
if (szTempString == NULL) {
SetLastError (PDH_MEMORY_ALLOCATION_FAILURE);
bReturn = FALSE;
} else {
ZeroMemory(szTempString, * pcchFileNameSize * sizeof(WCHAR) * 2);
szDirString = (LPWSTR)((LPBYTE)szTempString + (*pcchFileNameSize * sizeof(WCHAR)));
// continue
// get the current filename
if (bUnicodeString) {
lstrcpyW (szTempString, (LPWSTR)szFileName);
} else {
MultiByteToWideChar(_getmbcp(),
0,
(LPSTR) szFileName,
lstrlenA((LPSTR) szFileName),
(LPWSTR) szTempString,
lstrlenA((LPSTR) szFileName) + 1);
}
// set the path up for the initial dir display
if (szTempString[0] != L'\0') {
if (SearchPathW(NULL, szTempString, NULL,
*pcchFileNameSize, szDirString, &szTempFileName) > 0) {
// then update the buffers to show file and dir path
if (szTempFileName > szDirString) {
// then we have a path with a file name so
// truncate the path at the last backslash and
// then copy the filename to the original buffer
*(szTempFileName-1) = 0;
lstrcpyW (szTempString, szTempFileName);
} else {
// no file name found so leave things as is
}
} else {
// unable to search path so leave things alone
}
}
// get the log filter string
if (MakeLogFilterInfoString (
szLogFilterString,
(sizeof(szLogFilterString)/sizeof(szLogFilterString[0]))) == ERROR_SUCCESS) {
szLogFilter = szLogFilterString;
} else {
// then use default filter string
szLogFilter = NULL;
}
// display file open dialog to browse for log files.
szMsg = GetStringResource (IDS_DSRC_SELECT);
ofn.lStructSize = sizeof (ofn);
ofn.hwndOwner = hWndParent;
ofn.hInstance = ThisDLLHandle;
ofn.lpstrFilter = szLogFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szTempString;
ofn.nMaxFile = SMALL_BUFFER_SIZE -1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = szDirString;
ofn.lpstrTitle = szMsg;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY |
OFN_PATHMUSTEXIST;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = cszBlg;
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
if (GetOpenFileNameW (&ofn)) {
// then update the return string
if (bUnicodeString) {
lstrcpyW ((LPWSTR)szFileName, szTempString);
* pcchFileNameSize = lstrlenW(szTempString) + 1;
} else {
PdhiConvertUnicodeToAnsi(_getmbcp(),
szTempString, (LPSTR) szFileName, pcchFileNameSize);
}
bReturn = TRUE;
} else {
bReturn = FALSE;
}
if (szMsg) G_FREE (szMsg);
}
if (szTempString != NULL) G_FREE (szTempString);
return bReturn;
}
PDH_FUNCTION
PdhGetDataSourceTimeRangeH (
IN HLOG hDataSource,
IN LPDWORD pdwNumEntries,
IN PPDH_TIME_INFO pInfo,
IN LPDWORD pdwBufferSize
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwLocalBufferSize = 0;
DWORD dwLocalNumEntries = 0;
PDH_TIME_INFO LocalInfo;
PPDHI_LOG pLog;
// TODO postW2k1: Capture pInfo. Most routines should be in try
if (hDataSource == H_REALTIME_DATASOURCE) {
pdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
}
else if ((pdwNumEntries == NULL) || (pInfo == NULL)
|| (pdwBufferSize == NULL)) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
else {
// test caller's buffers before trying to use them
__try {
dwLocalNumEntries = * pdwNumEntries;
dwLocalBufferSize = * pdwBufferSize;
LocalInfo.StartTime = pInfo->StartTime;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle(hDataSource)) {
pLog = (PPDHI_LOG) hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle(hDataSource)) {
// enum machines based on log type
//
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiGetTimeRangeFromTextLog(
pLog,
& dwLocalNumEntries,
& LocalInfo,
& dwLocalBufferSize);
break;
case PDH_LOG_TYPE_BINARY:
pdhStatus = PdhiGetTimeRangeFromWmiLog(
pLog,
& dwLocalNumEntries,
& LocalInfo,
& dwLocalBufferSize);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiGetTimeRangeFromBinaryLog(
pLog,
& dwLocalNumEntries,
& LocalInfo,
& dwLocalBufferSize);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiGetTimeRangeFromSQLLog(
pLog,
& dwLocalNumEntries,
& LocalInfo,
& dwLocalBufferSize);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiGetTimeRangeFromPerfmonLog(
pLog,
& dwLocalNumEntries,
& LocalInfo,
& dwLocalBufferSize);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
__try {
* pdwBufferSize = dwLocalBufferSize;
* pdwNumEntries = dwLocalNumEntries;
pInfo->StartTime = LocalInfo.StartTime;
pInfo->EndTime = LocalInfo.EndTime;
pInfo->SampleCount = LocalInfo.SampleCount;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhGetDataSourceTimeRangeW (
IN LPCWSTR szDataSource,
IN LPDWORD pdwNumEntries,
IN PPDH_TIME_INFO pInfo,
IN LPDWORD pdwBufferSize
)
{
PDH_STATUS PdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
HLOG hDataSource = NULL;
DWORD dwLogType = -1;
if (szDataSource != NULL) {
// open log file
//
PdhStatus = PdhOpenLogW (
szDataSource,
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
& dwLogType,
NULL,
0,
NULL,
& hDataSource);
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhGetDataSourceTimeRangeH(
hDataSource,
pdwNumEntries,
pInfo,
pdwBufferSize);
PdhCloseLog(hDataSource, 0);
}
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetDataSourceTimeRangeA (
IN LPCSTR szDataSource,
IN LPDWORD pdwNumEntries,
IN PPDH_TIME_INFO pInfo,
IN LPDWORD pdwBufferSize
)
{
LPWSTR wszDataSource = NULL;
DWORD dwSize;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwLocalBufferSize = 0;
DWORD dwLocalNumEntries = 0;
// TODO postW2k1: Capture pInfo. Most routines should be in try
if (szDataSource == NULL) {
// null data source == the current activity so return
pdhStatus = PDH_DATA_SOURCE_IS_REAL_TIME;
} else if ((pdwNumEntries == NULL) ||
(pInfo == NULL) ||
(pdwBufferSize == NULL)) {
pdhStatus = PDH_INVALID_ARGUMENT;
} else {
__try {
dwLocalBufferSize = *pdwBufferSize;
dwLocalNumEntries = *pdwNumEntries;
dwSize = lstrlenA(szDataSource);
wszDataSource = G_ALLOC ((dwSize + 1) * sizeof(WCHAR));
if (wszDataSource == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
} else {
MultiByteToWideChar(_getmbcp(),
0,
szDataSource,
dwSize,
(LPWSTR) wszDataSource,
dwSize + 1);
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
// assume a bad parameter caused the exception
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhGetDataSourceTimeRangeW (
wszDataSource,
&dwLocalNumEntries,
pInfo,
&dwLocalBufferSize);
// copy returned values regardless of status
__try {
*pdwBufferSize = dwLocalBufferSize;
*pdwNumEntries = dwLocalNumEntries;
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (wszDataSource != NULL) {
G_FREE (wszDataSource);
}
return pdhStatus;
}
PDH_FUNCTION
PdhGetLogFileSize (
IN HLOG hLog,
IN LONGLONG *llSize
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_LOG pLog;
UINT nErrorMode;
DWORD dwFileSizeLow = 0;
DWORD dwFileSizeHigh = 0;
LONGLONG llFileLength;
DWORD dwError;
if (llSize == NULL) {
pdhStatus = PDH_INVALID_ARGUMENT;
} else {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_SQL) {
__try {
* llSize = 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
else if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
pdhStatus = PdhiGetWmiLogFileSize(pLog, llSize);
}
else {
// disable windows error message popup
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
dwFileSizeLow = GetFileSize (pLog->hLogFileHandle, &dwFileSizeHigh);
// test for error
if ((dwFileSizeLow == 0xFFFFFFFF) &&
((dwError = GetLastError()) != NO_ERROR)) {
// then we couldn't get the file size
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
} else {
if (dwFileSizeHigh > 0) {
llFileLength = dwFileSizeHigh << (sizeof(DWORD) * 8);
} else {
llFileLength = 0;
}
llFileLength += dwFileSizeLow;
// write to the caller' buffer
__try {
*llSize = llFileLength;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
} else {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
SetErrorMode (nErrorMode); // restore old error mode
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhReadRawLogRecord (
IN HLOG hLog,
IN FILETIME ftRecord,
IN PPDH_RAW_LOG_RECORD pBuffer,
IN LPDWORD pdwBufferLength
)
{
PPDHI_LOG pLog;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwLocalBufferLength = 0;
if (pdwBufferLength == NULL) {
pdhStatus = PDH_INVALID_ARGUMENT;
} else {
__try {
CHAR TestChar;
// test read & write access to the user's buffer.
dwLocalBufferLength = *pdwBufferLength;
if (dwLocalBufferLength > 0) {
// test beginnging and end of the buffer passed in
TestChar = ((CHAR *)pBuffer)[0];
((CHAR *)pBuffer)[0] = 0;
((CHAR *)pBuffer)[0] = TestChar;
TestChar = ((CHAR *)pBuffer)[dwLocalBufferLength -1];
((CHAR *)pBuffer)[dwLocalBufferLength -1] = 0;
((CHAR *)pBuffer)[dwLocalBufferLength -1] = TestChar;
} else {
// 0 length buffer is OK
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (!IsValidLogHandle (hLog)) {
pdhStatus = PDH_INVALID_HANDLE;
} else if (pdhStatus == ERROR_SUCCESS) {
pLog = (PPDHI_LOG)hLog;
// see if the log is open, first?
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
// make sure it's still valid
if (IsValidLogHandle (hLog)) {
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiReadRawTextLogRecord (
hLog,
&ftRecord,
pBuffer,
&dwLocalBufferLength);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiReadRawBinaryLogRecord (
hLog,
&ftRecord,
pBuffer,
&dwLocalBufferLength);
break;
case PDH_LOG_TYPE_SQL:
//note this is only supported with a null buffer
// as we don't actually read the record, and
// positioning the file at the record doesn't
// mean anything for SQL
pdhStatus = PdhiReadRawSQLLogRecord (
hLog,
&ftRecord,
pBuffer,
pdwBufferLength);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiReadRawPerfmonLogRecord (
hLog,
&ftRecord,
pBuffer,
&dwLocalBufferLength);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
__try {
*pdwBufferLength = dwLocalBufferLength;
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
// return pdhStatus
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumLoggedMachines (
IN HLOG hDataSource,
IN LPVOID mszMachineList,
IN LPDWORD pcchBufferSize,
IN BOOL bUnicode
)
{
PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
PPDHI_LOG pDataSource;
DWORD dwLogType;
// enum machines based on log type
//
if (IsValidLogHandle(hDataSource)) {
pDataSource = (PPDHI_LOG) hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hDataSource)) {
dwLogType = pDataSource->dwLogFormat;
switch (LOWORD(dwLogType)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiEnumMachinesFromTextLog (
(PPDHI_LOG) hDataSource,
mszMachineList,
pcchBufferSize,
bUnicode);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiEnumMachinesFromBinaryLog (
(PPDHI_LOG) hDataSource,
mszMachineList,
pcchBufferSize,
bUnicode);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiEnumMachinesFromSQLLog (
(PPDHI_LOG)hDataSource,
mszMachineList,
pcchBufferSize,
bUnicode);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiEnumMachinesFromPerfmonLog (
(PPDHI_LOG) hDataSource,
mszMachineList,
pcchBufferSize,
bUnicode);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pDataSource->hLogMutex);
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumLoggedObjects (
IN HLOG hDataSource,
IN LPCWSTR szMachineName,
IN LPVOID mszObjectList,
IN LPDWORD pcchBufferSize,
IN DWORD dwDetailLevel,
IN BOOL bRefresh, // ignored by log files
IN BOOL bUnicode
)
{
PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
PPDHI_LOG pDataSource;
DWORD dwLogType;
UNREFERENCED_PARAMETER (bRefresh);
if (IsValidLogHandle(hDataSource)) {
pDataSource = (PPDHI_LOG)hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hDataSource)) {
dwLogType = pDataSource->dwLogFormat;
// enum objects based on log type & machine name
switch (LOWORD(dwLogType)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiEnumObjectsFromTextLog (
(PPDHI_LOG)hDataSource,
szMachineName,
mszObjectList,
pcchBufferSize,
dwDetailLevel,
bUnicode);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiEnumObjectsFromBinaryLog (
(PPDHI_LOG)hDataSource,
szMachineName,
mszObjectList,
pcchBufferSize,
dwDetailLevel,
bUnicode);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiEnumObjectsFromSQLLog (
(PPDHI_LOG)hDataSource,
szMachineName,
mszObjectList,
pcchBufferSize,
dwDetailLevel,
bUnicode);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiEnumObjectsFromPerfmonLog (
(PPDHI_LOG)hDataSource,
szMachineName,
mszObjectList,
pcchBufferSize,
dwDetailLevel,
bUnicode);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pDataSource->hLogMutex);
}
}
else {
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumLoggedObjectItems (
IN HLOG hDataSource,
IN LPCWSTR szMachineName,
IN LPCWSTR szObjectName,
IN LPVOID mszCounterList,
IN LPDWORD pdwCounterListLength,
IN LPVOID mszInstanceList,
IN LPDWORD pdwInstanceListLength,
IN DWORD dwDetailLevel,
IN DWORD dwFlags,
IN BOOL bUnicode
)
{
PDH_STATUS pdhStatus = PDH_INVALID_HANDLE;
PPDHI_LOG pDataSource;
DWORD dwLogType;
PDHI_COUNTER_TABLE CounterTable;
DWORD dwIndex;
LIST_ENTRY InstanceList;
PLIST_ENTRY pHeadInst;
PLIST_ENTRY pNextInst;
PPDHI_INSTANCE pInstance;
PPDHI_INST_LIST pInstList;
LPVOID TempBuffer = NULL;
DWORD dwNewBuffer = 0;
LPVOID LocalCounter = NULL;
DWORD LocalCounterSize = 0;
LPVOID LocalInstance = NULL;
DWORD LocalInstanceSize = 0;
DWORD dwCntrBufferUsed = 0;
DWORD dwInstBufferUsed = 0;
PdhiInitCounterHashTable(CounterTable);
InitializeListHead(& InstanceList);
LocalCounter = G_ALLOC(MEDIUM_BUFFER_SIZE);
LocalInstance = G_ALLOC(MEDIUM_BUFFER_SIZE);
if (LocalCounter == NULL || LocalInstance == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
LocalCounterSize = LocalInstanceSize = MEDIUM_BUFFER_SIZE;
if (mszCounterList != NULL)
memset(mszCounterList, 0, * pdwCounterListLength);
if (mszInstanceList != NULL)
memset(mszInstanceList, 0, * pdwInstanceListLength);
if (IsValidLogHandle(hDataSource)) {
pDataSource = (PPDHI_LOG)hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hDataSource)) {
dwLogType = pDataSource->dwLogFormat;
// enum objects based on log type & machine name
switch (LOWORD(dwLogType)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiEnumObjectItemsFromTextLog (
(PPDHI_LOG) hDataSource,
szMachineName,
szObjectName,
CounterTable,
dwDetailLevel,
dwFlags);
break;
case PDH_LOG_TYPE_BINARY:
pdhStatus = PdhiEnumObjectItemsFromWmiLog (
(PPDHI_LOG) hDataSource,
szMachineName,
szObjectName,
CounterTable,
dwDetailLevel,
dwFlags);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiEnumObjectItemsFromBinaryLog (
(PPDHI_LOG) hDataSource,
szMachineName,
szObjectName,
CounterTable,
dwDetailLevel,
dwFlags);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiEnumObjectItemsFromSQLLog (
(PPDHI_LOG) hDataSource,
szMachineName,
szObjectName,
CounterTable,
dwDetailLevel,
dwFlags);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiEnumObjectItemsFromPerfmonLog (
(PPDHI_LOG)hDataSource,
szMachineName,
szObjectName,
CounterTable,
dwDetailLevel,
dwFlags);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pDataSource->hLogMutex);
}
}
if (pdhStatus == ERROR_SUCCESS) {
dwCntrBufferUsed = 0;
for (dwIndex = 0; dwIndex < HASH_TABLE_SIZE; dwIndex ++) {
PPDHI_INSTANCE pNewInst;
pInstList = CounterTable[dwIndex];
while (pInstList != NULL) {
if (! IsListEmpty(& pInstList->InstList)) {
pHeadInst = & pInstList->InstList;
pNextInst = pHeadInst->Flink;
while (pNextInst != pHeadInst) {
pInstance = CONTAINING_RECORD(
pNextInst, PDHI_INSTANCE, Entry);
pdhStatus = PdhiFindInstance(
& InstanceList,
pInstance->szInstance,
FALSE,
& pNewInst);
if (pNewInst->dwTotal < pInstance->dwTotal) {
pNewInst->dwTotal = pInstance->dwTotal;
}
pNextInst = pNextInst->Flink;
}
}
dwNewBuffer = (lstrlenW(pInstList->szCounter) + 1)
* sizeof(WCHAR);
while ( LocalCounterSize
< (dwCntrBufferUsed + dwNewBuffer)) {
TempBuffer = LocalCounter;
LocalCounter = G_REALLOC(TempBuffer,
LocalCounterSize + MEDIUM_BUFFER_SIZE);
if (LocalCounter == NULL) {
G_FREE(TempBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
LocalCounterSize += MEDIUM_BUFFER_SIZE;
}
dwNewBuffer = AddStringToMultiSz(
(LPVOID) LocalCounter,
pInstList->szCounter,
bUnicode);
if (dwNewBuffer > 0) {
dwCntrBufferUsed = dwNewBuffer *
(bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
}
pInstList = pInstList->pNext;
}
}
dwInstBufferUsed = 0;
if (! IsListEmpty(& InstanceList)) {
pHeadInst = & InstanceList;
pNextInst = pHeadInst->Flink;
while (pNextInst != pHeadInst) {
pInstance = CONTAINING_RECORD(
pNextInst, PDHI_INSTANCE, Entry);
dwNewBuffer = (lstrlenW(pInstance->szInstance) + 1)
* sizeof(WCHAR) * pInstance->dwTotal;
while ( LocalInstanceSize
< (dwInstBufferUsed + dwNewBuffer)) {
TempBuffer = LocalInstance;
LocalInstance = G_REALLOC(TempBuffer,
LocalInstanceSize + MEDIUM_BUFFER_SIZE);
if (LocalInstance == NULL) {
G_FREE(TempBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
LocalInstanceSize += MEDIUM_BUFFER_SIZE;
}
for (dwIndex = 0; dwIndex < pInstance->dwTotal; dwIndex ++) {
dwNewBuffer = AddStringToMultiSz(
(LPVOID) LocalInstance,
pInstance->szInstance,
bUnicode);
}
if (dwNewBuffer > 0) {
dwInstBufferUsed = dwNewBuffer *
(bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
}
pNextInst = pNextInst->Flink;
}
}
if (mszCounterList && dwCntrBufferUsed <= * pdwCounterListLength) {
RtlCopyMemory(mszCounterList, LocalCounter, dwCntrBufferUsed);
}
else {
if (mszCounterList)
RtlCopyMemory(mszCounterList,
LocalCounter,
* pdwCounterListLength);
dwCntrBufferUsed += (bUnicode) ? sizeof(WCHAR)
: sizeof(CHAR);
pdhStatus = PDH_MORE_DATA;
}
*pdwCounterListLength = dwCntrBufferUsed;
if (dwInstBufferUsed > 0) {
if ( mszInstanceList
&& dwInstBufferUsed <= * pdwInstanceListLength) {
RtlCopyMemory(mszInstanceList, LocalInstance, dwInstBufferUsed);
}
else {
if (mszInstanceList)
RtlCopyMemory(mszInstanceList,
LocalInstance,
* pdwInstanceListLength);
dwInstBufferUsed += (bUnicode) ? sizeof(WCHAR)
: sizeof(CHAR);
pdhStatus = PDH_MORE_DATA;
}
}
*pdwInstanceListLength = dwInstBufferUsed;
}
Cleanup:
if (! IsListEmpty(& InstanceList)) {
pHeadInst = & InstanceList;
pNextInst = pHeadInst->Flink;
while (pNextInst != pHeadInst) {
pInstance = CONTAINING_RECORD(pNextInst, PDHI_INSTANCE, Entry);
pNextInst = pNextInst->Flink;
RemoveEntryList(& pInstance->Entry);
G_FREE(pInstance);
}
}
for (dwIndex = 0; dwIndex < HASH_TABLE_SIZE; dwIndex ++) {
PPDHI_INST_LIST pCurrent;
pInstList = CounterTable[dwIndex];
while (pInstList != NULL) {
if (! IsListEmpty(& pInstList->InstList)) {
pHeadInst = & pInstList->InstList;
pNextInst = pHeadInst->Flink;
while (pNextInst != pHeadInst) {
pInstance = CONTAINING_RECORD(
pNextInst, PDHI_INSTANCE, Entry);
pNextInst = pNextInst->Flink;
RemoveEntryList(& pInstance->Entry);
G_FREE(pInstance);
}
}
pCurrent = pInstList;
pInstList = pInstList->pNext;
G_FREE(pCurrent);
}
}
if (LocalCounter != NULL) {
G_FREE(LocalCounter);
}
if (LocalInstance != NULL) {
G_FREE(LocalInstance);
}
return pdhStatus;
}
BOOL
PdhiDataSourceHasDetailLevels (
IN LPWSTR szDataSource
)
{
if (szDataSource == NULL) {
// real-time supports them
return TRUE;
} else {
// logs don't (for now)
return FALSE;
}
}
BOOL
PdhiDataSourceHasDetailLevelsH(
IN HLOG hDataSource
)
{
return (hDataSource == H_REALTIME_DATASOURCE);
}
PDH_FUNCTION
PdhiGetMatchingLogRecord (
IN HLOG hLog,
IN LONGLONG *pStartTime,
IN LPDWORD pdwIndex
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_LOG pLog;
DWORD dwTempIndex;
__try {
dwTempIndex = *pdwIndex;
*pdwIndex = 0;
*pdwIndex = dwTempIndex;
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiGetMatchingTextLogRecord (
pLog,
pStartTime,
pdwIndex);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiGetMatchingBinaryLogRecord (
pLog,
pStartTime,
pdwIndex);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiGetMatchingSQLLogRecord (
pLog,
pStartTime,
pdwIndex);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiGetMatchingPerfmonLogRecord (
pLog,
pStartTime,
pdwIndex);
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetCounterValueFromLogFile (
IN HLOG hLog,
IN DWORD dwIndex,
IN PPDHI_COUNTER pCounter
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_LOG pLog = NULL;
PDH_RAW_COUNTER pValue;
memset (&pValue, 0, sizeof (pValue));
pCounter->LastValue = pCounter->ThisValue;
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiGetCounterValueFromTextLog (
pLog,
dwIndex,
& pCounter->plCounterInfo,
& pValue);
break;
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiGetCounterValueFromBinaryLog (
pLog,
dwIndex,
pCounter);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiGetCounterValueFromSQLLog (
pLog,
dwIndex,
pCounter,
&pValue);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PdhiGetCounterValueFromPerfmonLog (
pLog,
dwIndex,
pCounter,
& pValue);
break;
case PDH_LOG_TYPE_BINARY:
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
if ( pdhStatus == ERROR_SUCCESS
&& LOWORD(pLog->dwLogFormat) != PDH_LOG_TYPE_RETIRED_BIN
&& LOWORD(pLog->dwLogFormat) != PDH_LOG_TYPE_BINARY) {
if (pdhStatus != ERROR_SUCCESS) {
// See if this is because there's no more entries.
// If not, clear the counter value & return error
//
if (pdhStatus != PDH_NO_MORE_DATA) {
memset (& pCounter->ThisValue, 0, sizeof (PDH_RAW_COUNTER));
pCounter->ThisValue.CStatus = pdhStatus;
}
}
else {
pCounter->ThisValue = pValue;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiResetLogBuffers (
IN HLOG hLog
)
{
PDH_STATUS pdhStatus;
PPDHI_LOG pLog;
if (IsValidLogHandle(hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
pdhStatus = PdhiRewindWmiLog(pLog);
}
else {
pLog->dwLastRecordRead = 0;
if (pLog->lpMappedFileBase != NULL) {
// for mapped files we use a pointer into the buffer
// so reset it
pLog->pLastRecordRead = pLog->lpMappedFileBase;
} else {
// for other files we have a separate buffer
if (pLog->pLastRecordRead != NULL) {
G_FREE (pLog->pLastRecordRead);
pLog->pLastRecordRead = NULL;
}
}
pdhStatus = ERROR_SUCCESS;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhListLogFileHeaderW (
IN LPCWSTR szFileName,
IN LPWSTR mszHeaderList,
IN LPDWORD pcchHeaderListSize
)
{
HLOG hDataSource = NULL;
PDH_STATUS pdhStatus;
DWORD dwLogType = -1;
PPDHI_LOG pDataSource;
BOOL bUnicode = TRUE;
// open log file
pdhStatus = PdhOpenLogW (
szFileName,
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
&dwLogType,
NULL,
0,
NULL,
&hDataSource);
if (pdhStatus == ERROR_SUCCESS) {
pDataSource = (PPDHI_LOG)hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hDataSource)) {
// enum objects based on log type & machine name
switch (LOWORD(dwLogType)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiListHeaderFromTextLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiListHeaderFromBinaryLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiListHeaderFromSQLLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
PdhCloseLog (hDataSource, 0);
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pDataSource->hLogMutex);
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhListLogFileHeaderA (
IN LPCSTR szFileName,
IN LPSTR mszHeaderList,
IN LPDWORD pcchHeaderListSize
)
{
HLOG hDataSource = NULL;
PDH_STATUS pdhStatus;
DWORD dwLogType = -1;
PPDHI_LOG pDataSource;
BOOL bUnicode = FALSE;
// open log file
pdhStatus = PdhOpenLogA (
szFileName,
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
&dwLogType,
NULL,
0,
NULL,
&hDataSource);
if (pdhStatus == ERROR_SUCCESS) {
pDataSource = (PPDHI_LOG)hDataSource;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pDataSource->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hDataSource)) {
// enum objects based on log type & machine name
switch (LOWORD(dwLogType)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
pdhStatus = PdhiListHeaderFromTextLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiListHeaderFromBinaryLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_SQL:
pdhStatus = PdhiListHeaderFromSQLLog (
(PPDHI_LOG)hDataSource,
(LPVOID)mszHeaderList,
pcchHeaderListSize,
bUnicode);
break;
case PDH_LOG_TYPE_PERFMON:
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
PdhCloseLog (hDataSource, 0);
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pDataSource->hLogMutex);
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetMultiInstanceValueFromLogFile (
IN HLOG hLog,
IN DWORD dwIndex,
IN PPDHI_COUNTER pCounter,
IN OUT PPDHI_RAW_COUNTER_ITEM_BLOCK *ppValue
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_LOG pLog;
// allocates and updates the raw counter data array
// in the counter structure and returns a pointer to that
// structure in the ppvalue argument
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
pLog = (PPDHI_LOG)hLog;
pdhStatus = WAIT_FOR_AND_LOCK_MUTEX (pLog->hLogMutex);
if (pdhStatus == ERROR_SUCCESS) {
if (IsValidLogHandle (hLog)) {
// call any type-specific open functions
switch (LOWORD(pLog->dwLogFormat)) {
case PDH_LOG_TYPE_CSV:
case PDH_LOG_TYPE_TSV:
// Text files do not support this type of counter
pdhStatus = PDH_INVALID_ARGUMENT;
break;
case PDH_LOG_TYPE_BINARY:
case PDH_LOG_TYPE_RETIRED_BIN:
pdhStatus = PdhiGetCounterArrayFromBinaryLog (
pLog,
dwIndex,
pCounter,
ppValue);
break;
case PDH_LOG_TYPE_PERFMON:
// not currently implemented but it could be
pdhStatus = PDH_NOT_IMPLEMENTED;
break;
default:
pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
break;
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
RELEASE_MUTEX (pLog->hLogMutex);
}
} else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
return pdhStatus;
}
extern DWORD DataSourceTypeW(IN LPCWSTR szDataSource);
PDH_FUNCTION
PdhBindInputDataSourceW(
IN HLOG * phDataSource,
IN LPCWSTR LogFileNameList
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwDataSource = DataSourceTypeW(LogFileNameList);
LPWSTR NextLogFile = (LPWSTR) LogFileNameList;
ULONG LogFileCount = 0;
ULONG LogFileSize;
PPDHI_LOG pLogHead = NULL;
PPDHI_LOG pLogNew = NULL;
DWORD dwLogType;
HLOG hLogLocal = NULL;
WCHAR wcType[VALUE_BUFFER_SIZE];
switch (dwDataSource) {
case DATA_SOURCE_WBEM:
* phDataSource = H_WBEM_DATASOURCE;
break;
case DATA_SOURCE_REGISTRY:
* phDataSource = H_REALTIME_DATASOURCE;
break;
case DATA_SOURCE_LOGFILE:
ZeroMemory((LPWSTR) wcType, sizeof(WCHAR) * VALUE_BUFFER_SIZE);
lstrcpynW((LPWSTR) wcType,
(LPWSTR) LogFileNameList,
lstrlenW(cszSQL) + 1);
if (lstrcmpiW((LPWSTR) wcType, (LPWSTR) cszSQL) == 0) {
// special handling for SQL datasource
//
dwLogType = PDH_LOG_TYPE_SQL;
PdhStatus = PdhOpenLogW(LogFileNameList,
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
& dwLogType,
NULL,
0,
NULL,
& hLogLocal);
if (PdhStatus == ERROR_SUCCESS) {
* phDataSource = hLogLocal;
}
break;
}
__try {
while (* NextLogFile != L'\0') {
LogFileSize = sizeof(WCHAR) * (lstrlenW(NextLogFile) + 1);
LogFileSize = DWORD_MULTIPLE(LogFileSize);
//LogFileSize += sizeof(PDHI_LOG);
pLogNew = G_ALLOC(LogFileSize + sizeof(PDHI_LOG));
if (pLogNew == NULL) {
PdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
RtlZeroMemory(pLogNew, LogFileSize + sizeof(PDHI_LOG));
* ((LPDWORD)(& pLogNew->signature[0])) = SigLog;
pLogNew->dwLength = sizeof(PDHI_LOG);
pLogNew->szLogFileName = (LPWSTR) ( ((PUCHAR) pLogNew)
+ sizeof(PDHI_LOG));
lstrcpyW(pLogNew->szLogFileName, NextLogFile);
pLogNew->NextLog = pLogHead;
pLogHead = pLogNew;
LogFileCount ++;
NextLogFile += (lstrlenW(NextLogFile) + 1);
}
if (pLogHead == NULL) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
if (PdhStatus == ERROR_SUCCESS) {
pLogHead->hLogMutex = CreateMutexW(NULL, TRUE, NULL);
pLogHead->hLogFileHandle = INVALID_HANDLE_VALUE;
pLogHead->hCatFileHandle = INVALID_HANDLE_VALUE;
if (PdhiFirstLogEntry == NULL) {
PdhiFirstLogEntry = pLogHead;
pLogHead->next.flink =
pLogHead->next.blink = pLogHead;
}
else {
PPDHI_LOG pFirstLog = PdhiFirstLogEntry;
PPDHI_LOG pLastLog = pFirstLog->next.blink;
pLogHead->next.flink = pLastLog->next.flink;
pLastLog->next.flink = pLogHead;
pLogHead->next.blink = pFirstLog->next.blink;
pFirstLog->next.blink = pLogHead;
}
PdhStatus = OpenInputLogFile(
pLogHead,
PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
& dwDataSource);
if ( PdhStatus == ERROR_SUCCESS
&& (dwDataSource == PDH_LOG_TYPE_BINARY || LogFileCount == 1)) {
* phDataSource = (HLOG) pLogHead;
}
else {
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PDH_INVALID_ARGUMENT;
PdhCloseLog(pLogHead, 0);
}
DeleteLogEntry(pLogHead);
}
}
else {
while (pLogHead != NULL) {
pLogNew = pLogHead;
pLogHead = pLogNew->NextLog;
G_FREE(pLogNew);
}
}
break;
default:
PdhStatus = PDH_INVALID_ARGUMENT;
break;
}
return PdhStatus;
}
PDH_FUNCTION
PdhBindInputDataSourceA(
IN HLOG * phDataSource,
IN LPCSTR LogFileNameList
)
{
LPWSTR wLogFileNameList = NULL;
LPWSTR wNextFileName;
LPSTR aNextFileName;
ULONG LogFileListSize = 1;
PDH_STATUS PdhStatus = ERROR_SUCCESS;
if (LogFileNameList == NULL) {
wLogFileNameList = NULL;
}
else {
__try {
while ( LogFileNameList[LogFileListSize - 1] != '\0'
|| LogFileNameList[LogFileListSize] != '\0') {
LogFileListSize ++;
}
LogFileListSize = (LogFileListSize + 1) * sizeof(WCHAR);
wLogFileNameList = (LPWSTR) G_ALLOC(LogFileListSize);
if (wLogFileNameList == NULL) {
PdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
else {
aNextFileName = (LPSTR) LogFileNameList;
wNextFileName = wLogFileNameList;
while (* aNextFileName != '\0') {
LogFileListSize = lstrlenA(aNextFileName);
MultiByteToWideChar(_getmbcp(),
0,
aNextFileName,
LogFileListSize,
(LPWSTR) wNextFileName,
LogFileListSize + 1);
aNextFileName += LogFileListSize;
wNextFileName += LogFileListSize;
}
* wNextFileName = L'\0';
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhBindInputDataSourceW(phDataSource, wLogFileNameList);
}
return PdhStatus;
}
BOOL
PdhiCloseAllLoggers()
{
while (PdhiFirstLogEntry != NULL) {
PPDHI_LOG pLog = PdhiFirstLogEntry;
CloseAndDeleteLogEntry(pLog, 0, TRUE);
}
return TRUE;
}
PDH_FUNCTION PdhiCheckWmiLogFileType(IN LPCWSTR LogFileName,
IN LPDWORD LogFileType);
PDH_FUNCTION
PdhGetLogFileTypeW(
IN LPCWSTR LogFileName,
IN LPDWORD LogFileType)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
HANDLE hFile;
DWORD dwLogFormat;
if (LogFileName == NULL) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
else {
__try {
dwLogFormat = * LogFileType;
* LogFileType = dwLogFormat;
if (* LogFileName == L'\0') {
pdhStatus = PDH_INVALID_ARGUMENT;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
hFile = CreateFileW(LogFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
}
if (pdhStatus == ERROR_SUCCESS) {
dwLogFormat = GetLogFileType(hFile);
CloseHandle(hFile);
if (dwLogFormat == PDH_LOG_TYPE_UNDEFINED) {
pdhStatus = PdhiCheckWmiLogFileType(LogFileName, & dwLogFormat);
}
}
if (pdhStatus == ERROR_SUCCESS) {
* LogFileType = dwLogFormat;
}
return pdhStatus;
}
PDH_FUNCTION
PdhGetLogFileTypeA(
IN LPCSTR LogFileName,
IN LPDWORD LogFileType)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
LPWSTR wszLogFileName = NULL;
DWORD dwLogFileName = 0;
if (LogFileName == NULL) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
else {
__try {
if (* LogFileName == '\0') {
pdhStatus = PDH_INVALID_ARGUMENT;
}
else {
dwLogFileName = lstrlenA(LogFileName);
wszLogFileName = (LPWSTR)
G_ALLOC((dwLogFileName + 1) * sizeof(WCHAR));
if (wszLogFileName == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
else {
MultiByteToWideChar(_getmbcp(),
0,
LogFileName,
dwLogFileName,
(LPWSTR) wszLogFileName,
dwLogFileName + 1);
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhGetLogFileTypeW(wszLogFileName, LogFileType);
}
if (wszLogFileName != NULL) {
G_FREE(wszLogFileName);
}
return pdhStatus;
}