|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Abstract:
Log Engine implementation.
Author:
Souren Aghajanyan (sourenag) 24-Sep-2001
Revision History:
<alias> <date> <comments>
--*/
#include "pch.h"
#include "log_man.h"
#define GET_SECTION_PTR(addr, pSharedInfo) (((BYTE *)addr) + pSharedInfo.FirstElementOffset)
#define LOG_MANAGER_MUTEX_DEFAULT_SPIN_COUNT 1000
#define LOGMANAGER_CANNOT_CONVERT_PARAMETER L"Log: Cannot convert to ansi->unicode"
#define LOG_MANAGER_CONVERSION_BUFFER_DEFAULT_SIZE (1<<10)
UINT GetOffsetForNewItem( PLOG_SHARED_STRUCTURES_INFO pSharedInfo, UINT Size ) { ASSERT(pSharedInfo && Size); if(Size > (pSharedInfo->MaxSizeOfMemory - pSharedInfo->SizeOfUsedMemory)){ return 0; }
pSharedInfo->SizeOfUsedMemory += Size;
return pSharedInfo->FirstElementOffset + pSharedInfo->SizeOfUsedMemory - Size; }
VOID UpdateForRemovedItem( PLOG_SHARED_STRUCTURES_INFO pSharedInfo, UINT Size ) { ASSERT(pSharedInfo && Size); if(Size > pSharedInfo->SizeOfUsedMemory){ return; }
pSharedInfo->SizeOfUsedMemory -= Size; }
BOOL CLogManager::CreateConversionBuffers( UINT NumberOfConversionBuffers ) { if(!NumberOfConversionBuffers){ ASSERT(NumberOfConversionBuffers); return FALSE; }
if(m_ConversionBuffers){ ASSERT(!m_ConversionBuffers); DestroyConversionBuffers(); }
m_ConversionBuffers = new CBuffer[NumberOfConversionBuffers]; if(!m_ConversionBuffers){ ASSERT(m_ConversionBuffers); return FALSE; } m_ConversionBuffersNumber = NumberOfConversionBuffers; for(UINT i = 0; i < NumberOfConversionBuffers; i++){ m_ConversionBuffers[i].PreAllocate(LOG_MANAGER_CONVERSION_BUFFER_DEFAULT_SIZE); }
return TRUE; }
VOID CLogManager::DestroyConversionBuffers( VOID ) { if(!m_ConversionBuffers){ return; } delete[m_ConversionBuffersNumber] m_ConversionBuffers;
m_ConversionBuffers = NULL; m_ConversionBuffersNumber = 0; }
CLogManager::CLogManager() : m_SharedMemory(), m_Mutex(), m_StackList() { m_SharedData = NULL;
m_FieldsValue = NULL; m_FieldsNumber = NULL;
m_ConversionBuffers = NULL; m_ConversionBuffersNumber = NULL; }
CLogManager::~CLogManager() { Close(); }
BOOL CLogManager::InitSharedData( UINT SizeForAllSharedData ) { ASSERT(m_SharedData && SizeForAllSharedData > HEADER_SIZE); memset(m_SharedData, 0, SizeForAllSharedData);
PLOG_SHARED_STRUCTURES_INFO pSharedStructure; UINT offset;
if(((HEADER_SIZE/SHARED_DATA_STRUCTURE_ALIGMENT) * SHARED_DATA_STRUCTURE_ALIGMENT + (HEADER_SIZE%SHARED_DATA_STRUCTURE_ALIGMENT? 1: 0)*SHARED_DATA_STRUCTURE_ALIGMENT) + (SHARED_DATA_STRUCTURE_ALIGMENT * 2) > SizeForAllSharedData){ ASSERT(FALSE); return FALSE; }
pSharedStructure = &((PLOG_SHARED_DATA)m_SharedData)->Fields;
pSharedStructure->FirstElementOffset = ALIGN_DATA(HEADER_SIZE, SHARED_DATA_STRUCTURE_ALIGMENT); pSharedStructure->SizeOfUsedMemory = 0; pSharedStructure->MaxSizeOfMemory = ALIGN_DATA((SizeForAllSharedData - pSharedStructure->FirstElementOffset) / 2, SHARED_DATA_STRUCTURE_ALIGMENT);
offset = pSharedStructure->FirstElementOffset + pSharedStructure->MaxSizeOfMemory;
pSharedStructure = &((PLOG_SHARED_DATA)m_SharedData)->Filters;
pSharedStructure->FirstElementOffset = offset; pSharedStructure->SizeOfUsedMemory = 0; pSharedStructure->MaxSizeOfMemory = SizeForAllSharedData - pSharedStructure->FirstElementOffset;
return TRUE; }
BOOL CLogManager::GetSharedData( IN PCWSTR pLogName ) { BOOL alreadyExist = FALSE;
CBuffer SectionName; SectionName.Allocate((wcslen(pLogName) + wcslen(L"Section") + 1) * sizeof(WCHAR)); PWSTR pSectionName = (PWSTR)SectionName.GetBuffer(); wcscpy(pSectionName, pLogName); wcscat(pSectionName, L"Section");
if(!m_SharedMemory.Open(pSectionName, INITIAL_SIZE_OF_SHARED_SECTION, &alreadyExist)){ return FALSE; }
m_SharedData = (PLOG_SHARED_DATA)m_SharedMemory.GetMapOfView();
if(!alreadyExist){ InitSharedData(INITIAL_SIZE_OF_SHARED_SECTION); }
return TRUE; }
BOOL CLogManager::ReleaseSharedData( VOID ) { m_SharedMemory.Close(); m_SharedData = NULL;
m_Mutex.Close();
if(m_FieldsValue){ FREE(m_FieldsValue); m_FieldsValue = NULL; m_FieldsNumber= 0; }
return TRUE; }
BOOL CLogManager::Init( PCWSTR pLogName, LOG_FIELD_INFO * pFields, UINT NumberOfFields ) { BOOL bResult;
if(!pLogName || !pFields || !NumberOfFields){ ASSERT(pLogName && pFields && NumberOfFields); return FALSE; }
if(!m_Mutex.Open(pLogName, TRUE, LOG_MANAGER_MUTEX_DEFAULT_SPIN_COUNT)){ return FALSE; }
bResult = FALSE;
__try{ if(!GetSharedData(pLogName)){ __leave; } if(!ValidateAndAddFieldsIfOk(pFields, NumberOfFields)){ __leave; }
m_FieldsValue = (PLOG_FIELD_VALUE)MALLOC(sizeof(LOG_FIELD_VALUE) * NumberOfFields); if(!m_FieldsValue){ __leave; } m_FieldsNumber = NumberOfFields;
memset(m_FieldsValue, 0, sizeof(LOG_FIELD_VALUE) * NumberOfFields); for(UINT i = 0, iStringNumber = 0; i < NumberOfFields; i++){ wcscpy(m_FieldsValue[i].Name, pFields[i].Name); m_FieldsValue[i].bMandatory = pFields[i].bMandatory; m_FieldsValue[i].Value.Type = pFields[i].Type;
if(LT_SZ == pFields[i].Type){ iStringNumber++; } }
if(iStringNumber && !CreateConversionBuffers(iStringNumber)){ __leave; }
bResult = TRUE; } __finally{ if(!bResult){ RemoveFields(); } }
m_Mutex.Release();
if(!bResult){ Close(); }
return bResult; }
BOOL CLogManager::ValidateAndAddFieldsIfOk( PLOG_FIELD_INFO pFields, UINT NumberOfFields ) { ASSERT(pFields && NumberOfFields);
PLOG_FIELD_INFO_WITH_REF_COUNT pSharedFields = (PLOG_FIELD_INFO_WITH_REF_COUNT)(m_SharedData->Fields.FirstElementOffset + (BYTE*)m_SharedData); UINT NumberOfSharedFields = m_SharedData->Fields.SizeOfUsedMemory / sizeof(LOG_FIELD_INFO_WITH_REF_COUNT);
for(UINT j = 0; j < NumberOfSharedFields; j++){ PLOG_FIELD_INFO_WITH_REF_COUNT pSharedField = pSharedFields + j;
for(UINT i = 0; i < NumberOfFields; i++){ PLOG_FIELD_INFO pField = pFields + i;
if(!wcscmp(pSharedField->FieldDescription.Name, pField->Name)){ if(pSharedField->FieldDescription.Type != pField->Type || pSharedField->FieldDescription.bMandatory != pField->bMandatory){ return FALSE; } break; } }
if(i == NumberOfFields && pSharedField->FieldDescription.bMandatory){ return FALSE; } }
for(UINT i = 0; i < NumberOfFields; i++){ PLOG_FIELD_INFO pField = pFields + i;
BOOL bPresent = FALSE; for(UINT j = 0; j < NumberOfSharedFields; j++){ PLOG_FIELD_INFO_WITH_REF_COUNT pSharedField = pSharedFields + j;
if(!wcscmp(pSharedField->FieldDescription.Name, pField->Name)){ pSharedField->ReferenceCount++; bPresent = TRUE; break; } }
if(!bPresent){ UINT offset = GetOffsetForNewItem(&m_SharedData->Fields, sizeof(LOG_FIELD_INFO_WITH_REF_COUNT)); if(!offset){ return FALSE; } PLOG_FIELD_INFO_WITH_REF_COUNT pNewSharedField; pNewSharedField = (PLOG_FIELD_INFO_WITH_REF_COUNT)(offset + (BYTE*)m_SharedData); pNewSharedField->ReferenceCount = 1; wcscpy(pNewSharedField->FieldDescription.Name, pField->Name); pNewSharedField->FieldDescription.Type = pField->Type; pNewSharedField->FieldDescription.bMandatory = pField->bMandatory; bPresent = TRUE; } }
return TRUE; }
BOOL CLogManager::RemoveFields( ) { if(!m_SharedData || !m_FieldsValue){ return FALSE; }
ASSERT(m_FieldsValue && m_FieldsNumber); PLOG_FIELD_INFO_WITH_REF_COUNT pSharedFields = (PLOG_FIELD_INFO_WITH_REF_COUNT)(m_SharedData->Fields.FirstElementOffset + (BYTE*)m_SharedData); UINT NumberOfSharedFields = m_SharedData->Fields.SizeOfUsedMemory / sizeof(LOG_FIELD_INFO_WITH_REF_COUNT);
for(int i = m_FieldsNumber - 1; i >= 0 ; i--){ PLOG_FIELD_VALUE pField = m_FieldsValue + i;
UINT HowBytesToCopy = 0; for(int j = NumberOfSharedFields - 1; j >= 0; j--){ PLOG_FIELD_INFO_WITH_REF_COUNT pSharedField = pSharedFields + j;
if(!wcscmp(pSharedField->FieldDescription.Name, pField->Name)){ pSharedField->ReferenceCount--; if(!pSharedField->ReferenceCount){ if(HowBytesToCopy){ memcpy(pSharedField, pSharedField + 1, HowBytesToCopy); } UpdateForRemovedItem(&m_SharedData->Fields, sizeof(LOG_FIELD_INFO_WITH_REF_COUNT)); break; } }
HowBytesToCopy += sizeof(LOG_FIELD_INFO_WITH_REF_COUNT); } }
return TRUE; }
VOID CLogManager::Close() { m_Mutex.Acquiry();
RemoveFields();
//walk through list
for(PLOG_OUTPUT_STACK pLogStack = m_StackList.BeginEnum(); pLogStack; pLogStack = m_StackList.Next()){ ASSERT(pLogStack); DestroyStack(pLogStack); }
m_Mutex.Release();
m_StackList.RemoveAll();
ReleaseSharedData();
DestroyConversionBuffers(); }
BOOL CLogManager::AddStack( const GUID * guidFilter, PVOID pFilterData, const GUID * guidFormater, PVOID pFormaterData, const GUID * guidDevice, PVOID pDeviceData, PVOID * pvHandle ) { ILogProvider * pDevice = NULL; ILogProvider * pFormater = NULL; ILogProvider * pFilter = NULL; PLOG_OUTPUT_STACK pNewStack = NULL;
BOOL bResult = FALSE; BOOL bDestAlreadyExist = FALSE;
if(!guidFormater){ return FALSE; }
m_Mutex.Acquiry();
__try{ if(guidDevice){ pDevice = LogiCreateProvider(guidDevice); if(!pDevice || LOG_DEVICE_TYPE != pDevice->GetType()){ __leave; } LOGRESULT logResult = pDevice->Init(pDeviceData, this); if(logError == logResult){ __leave; } bDestAlreadyExist = (logAlreadyExist == logResult); }
pFormater = LogiCreateProvider(guidFormater); if(!pFormater || LOG_FORMATTER_TYPE != pFormater->GetType() || logError == pFormater->Init(pFormaterData, this)){ __leave; }
if(guidFilter){ pFilter = LogiCreateProvider(guidFilter); if(!pFilter || LOG_FILTER_TYPE != pFilter->GetType() || logError == pFilter->Init(pFilterData, this)){ __leave; } }
pNewStack = (PLOG_OUTPUT_STACK)MALLOC(sizeof(LOG_OUTPUT_STACK)); if(!pNewStack){ __leave; }
pNewStack->m_Device = pDevice; pNewStack->m_Filter = pFilter; pNewStack->m_Formater = pFormater;
if(pDevice){ if(!ShareStack(guidFormater, pDevice->ToString(), bDestAlreadyExist)){ __leave; } }
{ AllocBuffer(0, 0); if(pFilter){ pFilter->PreProcess(this, !bDestAlreadyExist); } pFormater->PreProcess(this, !bDestAlreadyExist); if(pDevice){ pDevice->PreProcess(this, !bDestAlreadyExist); } FreeBuffer(); }
//append to list
m_StackList.Add(pNewStack);
bResult = TRUE; } __finally{ if(!bResult){ if(pNewStack){ FREE(pNewStack); } if(pFilter){ LogiDestroyProvider(pFilter); } if(pFormater){ LogiDestroyProvider(pFormater); } if(pDevice){ UnShareStack(guidFormater, pDevice->ToString()); LogiDestroyProvider(pDevice); } } if(pvHandle){ *pvHandle = bResult? (PVOID)pNewStack: NULL; } }
m_Mutex.Release();
return bResult; }
BOOL CLogManager::RemoveStack( IN PVOID pvHandle ) { m_Mutex.Acquiry();
//walk through list
for(PLOG_OUTPUT_STACK pLogStack = m_StackList.BeginEnum(); pLogStack; pLogStack = m_StackList.Next()){ ASSERT(pLogStack); if(((PVOID)pLogStack) == pvHandle){ if(DestroyStack(pLogStack)){ m_StackList.Remove(pLogStack); break; } } }
m_Mutex.Release();
return TRUE; }
BOOL CLogManager::DestroyStack( IN PLOG_OUTPUT_STACK pLogStack ) { BOOL bLastInstance = FALSE; PLOG_FILTER_WITH_REF_COUNT pSharedFilterData; GUID guidDevice;
if(pLogStack->m_Device){ pLogStack->m_Formater->GetGUID(&guidDevice); if(FindSharedStack(&guidDevice, pLogStack->m_Device->ToString(), &pSharedFilterData)){ bLastInstance = 1 == pSharedFilterData->ReferenceCount; } }
AllocBuffer(0, 0);
if(pLogStack->m_Filter){ pLogStack->m_Filter->PreDestroy(this, bLastInstance); LogiDestroyProvider(pLogStack->m_Filter); }
pLogStack->m_Formater->PreDestroy(this, bLastInstance); LogiDestroyProvider(pLogStack->m_Formater);
if(pLogStack->m_Device){ pLogStack->m_Device->PreDestroy(this, bLastInstance); if(!UnShareStack(&guidDevice, pLogStack->m_Device->ToString())){ return FALSE; } LogiDestroyProvider(pLogStack->m_Device); }
FreeBuffer();
FREE(pLogStack);
return TRUE; }
BOOL CLogManager::FindSharedStack( IN const GUID *pFormaterGUID, IN PCWSTR UniqueDestString, PLOG_FILTER_WITH_REF_COUNT * ppFilterData ) { PLOG_FILTER_WITH_REF_COUNT pSharedFilterData; ASSERT(pFormaterGUID && UniqueDestString && ppFilterData);
BYTE * pData = GET_SECTION_PTR(m_SharedData, m_SharedData->Filters); UINT offset = 0;
while(offset < m_SharedData->Filters.SizeOfUsedMemory){ pSharedFilterData = (PLOG_FILTER_WITH_REF_COUNT)(pData + offset); if(!wcscmp(pSharedFilterData->UniqueDestinationString, UniqueDestString)){//must be wcsicmp
if(InlineIsEqualGUID(&pSharedFilterData->FormatterGUID, pFormaterGUID)){ *ppFilterData = pSharedFilterData; return TRUE; } else{ return FALSE; } } offset += pSharedFilterData->Size; };
*ppFilterData = NULL;
return TRUE; }
BOOL CLogManager::ShareStack( IN const GUID * pFormaterGUID, IN PCWSTR UniqueDestString, IN BOOL bDestAlreadyExist ) { PLOG_FILTER_WITH_REF_COUNT pSharedFilterData; UINT offset; UINT size;
if(!FindSharedStack(pFormaterGUID, UniqueDestString, &pSharedFilterData)){ return FALSE; }
if(!pSharedFilterData){ if(bDestAlreadyExist){ return FALSE; }
size = sizeof(LOG_FILTER_WITH_REF_COUNT) + (wcslen(UniqueDestString) + 1/*'\0'*/) * sizeof(WCHAR);
offset = GetOffsetForNewItem(&m_SharedData->Filters, size); if(!offset){ return FALSE; }
pSharedFilterData = (PLOG_FILTER_WITH_REF_COUNT)(offset + (BYTE*)m_SharedData); pSharedFilterData->ReferenceCount = 1; pSharedFilterData->FormatterGUID = *pFormaterGUID; wcscpy(pSharedFilterData->UniqueDestinationString, UniqueDestString); pSharedFilterData->Size = size; } else{ pSharedFilterData->ReferenceCount++; }
return TRUE; }
BOOL CLogManager::UnShareStack( IN const GUID * pFormaterGUID, IN PCWSTR UniqueDestString ) { PLOG_FILTER_WITH_REF_COUNT pSharedFilterData; PLOG_FILTER_WITH_REF_COUNT pSharedNextFilterData; UINT_PTR offset; UINT size;
if(!FindSharedStack(pFormaterGUID, UniqueDestString, &pSharedFilterData)){ return FALSE; }
if(pSharedFilterData){ pSharedFilterData->ReferenceCount--; if(!pSharedFilterData->ReferenceCount){ size = pSharedFilterData->Size; offset = ((BYTE *)pSharedFilterData) - GET_SECTION_PTR(m_SharedData, m_SharedData->Filters) + size; pSharedNextFilterData = (PLOG_FILTER_WITH_REF_COUNT)(GET_SECTION_PTR(m_SharedData, m_SharedData->Filters) + offset); if(offset < m_SharedData->Filters.SizeOfUsedMemory){ memcpy(pSharedFilterData, pSharedNextFilterData, m_SharedData->Filters.SizeOfUsedMemory - offset); } UpdateForRemovedItem(&m_SharedData->Filters, size); } }
return TRUE; }
LOGRESULT CLogManager::LogMessage() { LOGRESULT logResult; BOOL bBreakPoint = FALSE; BOOL bAbortProcess = FALSE;
ASSERT(0 != m_StackList.GetSize());
logResult = logError;
__try{ //walk through list
for(PLOG_OUTPUT_STACK pLogStack = m_StackList.BeginEnum(); pLogStack; pLogStack = m_StackList.Next()){ ASSERT(pLogStack);
if(!pLogStack){ ASSERT(pLogStack); continue; }
FreeBuffer();
if(pLogStack->m_Filter){ logResult = pLogStack->m_Filter->Process(this);
if(logOk != logResult){ if(logBreakPoint == logResult){ bBreakPoint = TRUE; } else if(logAbortProcess == logResult){ bAbortProcess = TRUE; } else{ continue; } } }
logResult = pLogStack->m_Formater->Process(this); if(logOk != logResult){ continue; }
if(pLogStack->m_Device){ logResult = pLogStack->m_Device->Process(this); if(logOk != logResult){ continue; } } }
if(bAbortProcess){ logResult = logAbortProcess; } else{ logResult = bBreakPoint? logBreakPoint: logOk; }
} __finally{ }
return logResult; }
LOGRESULT STDMETHODCALLTYPE CLogManager::LogA( IN UINT NumberOfFieldsToLog IN ... ) { PCSTR pTempStr; LOGRESULT logResult; PLOG_VALUE pFieldValue; va_list argList;
if(NumberOfFieldsToLog > m_FieldsNumber){ NumberOfFieldsToLog = m_FieldsNumber; }
m_Mutex.Acquiry();
logResult = logError;
__try{ va_start(argList, NumberOfFieldsToLog);
for(UINT i = 0, iStringNumber = 0; i < NumberOfFieldsToLog; i++){ pFieldValue = &m_FieldsValue[i].Value;
#ifdef DEBUG
//
// init value union
//
memset(&pFieldValue->Binary, 0, sizeof(pFieldValue->Binary)); #endif
switch(pFieldValue->Type){ case LT_DWORD: pFieldValue->Dword = va_arg(argList, DWORD); break; case LT_SZ: ASSERT(m_ConversionBuffers); pTempStr = va_arg(argList, PCSTR); if(pTempStr){ if(!m_ConversionBuffers || !(m_ConversionBuffers[iStringNumber].ReAllocate((strlen(pTempStr) + 1) * sizeof(WCHAR)))){ pFieldValue->String = LOGMANAGER_CANNOT_CONVERT_PARAMETER; break; } pFieldValue->String = (PCWSTR)m_ConversionBuffers[iStringNumber].GetBuffer(); swprintf((PWSTR)pFieldValue->String, L"%S", pTempStr); } else{ pFieldValue->String = NULL; } iStringNumber++; break; case LT_BINARY: pFieldValue->Binary.Buffer = va_arg(argList, BYTE *); pFieldValue->Binary.Size = va_arg(argList, DWORD); break; default: ASSERT(FALSE); }; } for(; i < m_FieldsNumber; i++){ pFieldValue = &m_FieldsValue[i].Value; //
// init value union
//
memset(&pFieldValue->Binary, 0, sizeof(pFieldValue->Binary)); }
va_end(argList);
logResult = LogMessage(); } __finally{ m_Mutex.Release(); }
return logResult; }
LOGRESULT STDMETHODCALLTYPE CLogManager::LogW( IN UINT NumberOfFieldsToLog IN ... ) { LOGRESULT logResult; PLOG_VALUE pFieldValue; va_list argList;
if(NumberOfFieldsToLog > m_FieldsNumber){ NumberOfFieldsToLog = m_FieldsNumber; }
m_Mutex.Acquiry();
logResult = logError;
__try{ va_start(argList, NumberOfFieldsToLog);
for(UINT i = 0; i < NumberOfFieldsToLog; i++){ pFieldValue = &m_FieldsValue[i].Value;
#ifdef DEBUG
//
// init value union
//
memset(&pFieldValue->Binary, 0, sizeof(pFieldValue->Binary)); #endif
switch(pFieldValue->Type){ case LT_DWORD: pFieldValue->Dword = va_arg(argList, DWORD); break; case LT_SZ: pFieldValue->String = va_arg(argList, PCWSTR); break; case LT_BINARY: pFieldValue->Binary.Buffer = va_arg(argList, BYTE *); pFieldValue->Binary.Size = va_arg(argList, DWORD); break; default: ASSERT(FALSE); }; }
for(; i < m_FieldsNumber; i++){ pFieldValue = &m_FieldsValue[i].Value; //
// init value union
//
memset(&pFieldValue->Binary, 0, sizeof(pFieldValue->Binary)); } va_end(argList);
logResult = LogMessage(); } __finally{ m_Mutex.Release(); }
return logResult; }
// interface ILogContext
BOOL CLogManager::GetFieldIndexFromName( IN PCWSTR pFieldName, IN UINT* puiFieldIndex ) { ASSERT(pFieldName && pFieldName);
if(!pFieldName){ return FALSE; }
for(UINT i = 0; i < m_FieldsNumber; i++){ if(!wcscmp(m_FieldsValue[i].Name, pFieldName)){//must be wcsicmp
if(puiFieldIndex){ *puiFieldIndex = i; } return TRUE; } }
return FALSE; }
ILogManager * LogCreateLog( IN PCWSTR pLogName, IN PLOG_FIELD_INFO pFields, IN UINT NumberOfFields ) { CLogManager * pLogManager = new CLogManager;
ASSERT(pLogManager); if(!pLogManager){ return NULL; }
if(!pLogManager->Init(pLogName, pFields, NumberOfFields)){ delete pLogManager; return NULL; }
return (ILogManager *)pLogManager; }
VOID LogDestroyLog( IN ILogManager * pLog ) { ASSERT(pLog); if(!pLog){ return; }
delete (CLogManager *)pLog; }
|