You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
523 lines
14 KiB
523 lines
14 KiB
//***************************************************************************
|
|
//
|
|
// LOGVIEW.CPP
|
|
//
|
|
// Module: NLB Manager (client-side exe)
|
|
//
|
|
// Purpose: Implementation of the view of a log of events.
|
|
//
|
|
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// History:
|
|
//
|
|
// 08/03/01 JosephJ Adapted from now defunct RightBottomView
|
|
//
|
|
//***************************************************************************
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "private.h"
|
|
|
|
IMPLEMENT_DYNCREATE( LogView, CListView )
|
|
|
|
|
|
BEGIN_MESSAGE_MAP( LogView, CListView )
|
|
|
|
ON_WM_KEYDOWN()
|
|
// ON_NOTIFY(HDN_ITEMCLICK, 0, OnHeaderClock)
|
|
ON_NOTIFY_REFLECT(NM_DBLCLK, OnDoubleClick)
|
|
// ON_NOTIFY(NM_CLICK, 1, OnDoubleClick)
|
|
// ON_NOTIFY(NM_KEYDOWN, 1, OnDoubleClick)
|
|
|
|
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
LogView::LogView()
|
|
: m_fPrepareToDeinitialize(FALSE)
|
|
{
|
|
InitializeCriticalSection(&m_crit);
|
|
}
|
|
|
|
LogView::~LogView()
|
|
{
|
|
DeleteCriticalSection(&m_crit);
|
|
}
|
|
|
|
Document*
|
|
LogView::GetDocument()
|
|
{
|
|
return ( Document *) m_pDocument;
|
|
}
|
|
|
|
|
|
void
|
|
LogView::OnInitialUpdate()
|
|
{
|
|
CListCtrl& ctrl = GetListCtrl();
|
|
|
|
//
|
|
// set images for this view.
|
|
//
|
|
ctrl.SetImageList( GetDocument()->m_images48x48,
|
|
LVSIL_SMALL );
|
|
|
|
//
|
|
// set the style, we only want report
|
|
// view
|
|
//
|
|
|
|
// get present style.
|
|
LONG presentStyle;
|
|
|
|
presentStyle = GetWindowLong( m_hWnd, GWL_STYLE );
|
|
|
|
// Set the last error to zero to avoid confusion.
|
|
// See sdk for SetWindowLong.
|
|
SetLastError(0);
|
|
|
|
// set new style.
|
|
SetWindowLong( m_hWnd,
|
|
GWL_STYLE,
|
|
// presentStyle | LVS_REPORT | WS_TILED | WS_CAPTION
|
|
// presentStyle | LVS_REPORT | WS_CAPTION
|
|
// presentStyle | LVS_REPORT | WS_DLGFRAME
|
|
presentStyle | LVS_REPORT| LVS_NOSORTHEADER
|
|
);
|
|
|
|
// SetWindowText(L"Log view");
|
|
|
|
ctrl.InsertColumn(0,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_TYPE),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_TINY );
|
|
|
|
ctrl.InsertColumn(1,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_DATE),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_SMALL );
|
|
|
|
ctrl.InsertColumn(2,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_TIME),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_SMALLMEDIUM );
|
|
|
|
ctrl.InsertColumn(3,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_CLUSTER),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_MEDIUM);
|
|
|
|
ctrl.InsertColumn(4,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_HOST),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_LARGE);
|
|
|
|
ctrl.InsertColumn(5,
|
|
GETRESOURCEIDSTRING( IDS_HEADER_LOG_TEXT),
|
|
LVCFMT_LEFT,
|
|
Document::LV_COLUMN_GIGANTIC);
|
|
|
|
ctrl.SetExtendedStyle( ctrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
|
|
|
|
IUICallbacks::LogEntryHeader Header;
|
|
|
|
// we will register
|
|
// with the document class,
|
|
// as we are the status pane
|
|
// and status is reported via us.
|
|
GetDocument()->registerLogView( this );
|
|
|
|
//
|
|
// Log a starting-nlbmgr message (needs to be after the registration,
|
|
// because if file-logging is enabled and there is an error writing
|
|
// the the file, that code tries to log an error message -- that message
|
|
// would get dropped if we have not yet registered.
|
|
//
|
|
LogString(
|
|
&Header,
|
|
GETRESOURCEIDSTRING(IDS_LOG_NLBMANAGER_STARTED)
|
|
);
|
|
|
|
//
|
|
// Make this initial entry the selected one. We want some row highlighted
|
|
// to provide a visual cue as we move between views using keystrokes.
|
|
//
|
|
GetListCtrl().SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
|
|
|
|
}
|
|
|
|
//
|
|
// Log a message in human-readable form.
|
|
//
|
|
void
|
|
LogView::LogString(
|
|
IN const IUICallbacks::LogEntryHeader *pHeader,
|
|
IN const wchar_t *szText
|
|
)
|
|
{
|
|
|
|
mfn_Lock();
|
|
|
|
IUICallbacks::LogEntryType Type = pHeader->type;
|
|
const wchar_t *szCluster = pHeader->szCluster;
|
|
const wchar_t *szHost = pHeader->szHost;
|
|
const wchar_t *szDetails = pHeader->szDetails;
|
|
static LONG sSequence=0;
|
|
LONG Seq;
|
|
LPCWSTR szType = L"";
|
|
UINT Image = 0;
|
|
CListCtrl& ctrl = GetListCtrl();
|
|
WCHAR szSequenceNo[64];
|
|
LPCWSTR szDate = NULL;
|
|
LPCWSTR szTime = NULL;
|
|
_bstr_t bstrTime;
|
|
_bstr_t bstrDate;
|
|
INT nItem = ctrl.GetItemCount();
|
|
_bstr_t bstrText = _bstr_t(szText);
|
|
BOOL fLogTrimError = FALSE;
|
|
|
|
if (m_fPrepareToDeinitialize)
|
|
{
|
|
goto end_unlock;
|
|
}
|
|
|
|
//
|
|
// If total count exceeds our limit by 100 entries,
|
|
// get rid of the first 100 entries and log a message saying we've
|
|
// got rid of those entries.
|
|
//
|
|
#define MAX_LOG_ITEMS_IN_LIST 1000
|
|
#define LOG_ITEMS_TO_DELETE 100
|
|
if (nItem > MAX_LOG_ITEMS_IN_LIST)
|
|
{
|
|
for (int i=0;i < LOG_ITEMS_TO_DELETE;i++)
|
|
{
|
|
LPCWSTR szDetails = (LPCWSTR) ctrl.GetItemData(0);
|
|
delete szDetails; // may be NULL
|
|
ctrl.DeleteItem(0);
|
|
}
|
|
|
|
//
|
|
// Get the updated count...
|
|
//
|
|
nItem = ctrl.GetItemCount();
|
|
|
|
fLogTrimError = TRUE;
|
|
}
|
|
|
|
if (szCluster == NULL)
|
|
{
|
|
szCluster = L"";
|
|
}
|
|
|
|
if (szHost == NULL)
|
|
{
|
|
szHost = L"";
|
|
}
|
|
|
|
if (szDetails != NULL)
|
|
{
|
|
//
|
|
// There is detail-info. We make a copy of it and save it
|
|
// as the lParam structure. TODO -- copy the
|
|
// interface and other info as well.
|
|
//
|
|
UINT uLen = wcslen(szDetails)+1; // +1 for ending NULL;
|
|
WCHAR *szTmp = new WCHAR[uLen];
|
|
if (szTmp!=NULL)
|
|
{
|
|
CopyMemory(szTmp, szDetails, uLen*sizeof(WCHAR));
|
|
}
|
|
szDetails = szTmp; // could be NULL on mem failure.
|
|
|
|
if (szDetails != NULL)
|
|
{
|
|
//
|
|
// We'll add a hint to the text to double click for details...
|
|
//
|
|
bstrText += GETRESOURCEIDSTRING( IDS_LOG_DETAILS_HINT);
|
|
LPCWSTR szTmp1 = bstrText;
|
|
if (szTmp1 != NULL)
|
|
{
|
|
szText = szTmp1;
|
|
}
|
|
}
|
|
}
|
|
|
|
GetTimeAndDate(REF bstrTime, REF bstrDate);
|
|
szTime = bstrTime;
|
|
szDate = bstrDate;
|
|
if (szTime == NULL) szTime = L"";
|
|
if (szDate == NULL) szDate = L"";
|
|
|
|
Seq = InterlockedIncrement(&sSequence);
|
|
StringCbPrintf(szSequenceNo, sizeof(szSequenceNo), L"%04lu", Seq);
|
|
|
|
switch(Type)
|
|
{
|
|
case IUICallbacks::LOG_ERROR:
|
|
Image = Document::ICON_ERROR;
|
|
szType = GETRESOURCEIDSTRING(IDS_PARM_ERROR);
|
|
break;
|
|
|
|
case IUICallbacks::LOG_WARNING:
|
|
Image = Document::ICON_WARNING;
|
|
szType = GETRESOURCEIDSTRING(IDS_PARM_WARN);
|
|
break;
|
|
|
|
case IUICallbacks::LOG_INFORMATIONAL:
|
|
Image = Document::ICON_INFORMATIONAL;
|
|
szType = GETRESOURCEIDSTRING(IDS_LOGTYPE_INFORMATION);
|
|
break;
|
|
}
|
|
|
|
ctrl.InsertItem(
|
|
LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
|
|
nItem,
|
|
szSequenceNo, // text
|
|
0, // nState
|
|
0, // nStateMask
|
|
Image,
|
|
(LPARAM) szDetails // lParam
|
|
);
|
|
|
|
ctrl.SetItem(
|
|
nItem,
|
|
1,// nSubItem
|
|
LVIF_TEXT, // nMask
|
|
szDate, // lpszItem
|
|
0, // nImage
|
|
0, // nState
|
|
0, // nStateMask
|
|
0 // lParam
|
|
);
|
|
|
|
ctrl.SetItem(
|
|
nItem,
|
|
2,// nSubItem
|
|
LVIF_TEXT, // nMask
|
|
szTime, // lpszItem
|
|
0, // nImage
|
|
0, // nState
|
|
0, // nStateMask
|
|
0 // lParam
|
|
);
|
|
|
|
ctrl.SetItem(
|
|
nItem,
|
|
3,// nSubItem
|
|
LVIF_TEXT, // nMask
|
|
szCluster, // lpszItem
|
|
0, // nImage
|
|
0, // nState
|
|
0, // nStateMask
|
|
0 // lParam
|
|
);
|
|
|
|
ctrl.SetItem(
|
|
nItem,
|
|
4,// nSubItem
|
|
LVIF_TEXT, // nMask
|
|
szHost, // lpszItem
|
|
0, // nImage
|
|
0, // nState
|
|
0, // nStateMask
|
|
0 // lParam
|
|
);
|
|
|
|
ctrl.SetItem(
|
|
nItem,
|
|
5,// nSubItem
|
|
LVIF_TEXT, // nMask
|
|
szText, // lpszItem
|
|
0, // nImage
|
|
0, // nState
|
|
0, // nStateMask
|
|
0 // lParam
|
|
);
|
|
|
|
ctrl.EnsureVisible(nItem, FALSE); // FALSE == partial visibility not ok.
|
|
WCHAR logBuf[2*MAXSTRINGLEN];
|
|
StringCbPrintf(
|
|
logBuf,
|
|
sizeof(logBuf),
|
|
L"%ls\t%ls\t%ls\t%ls\t%ls\t%ls\t%ls\t\n",
|
|
szSequenceNo, szType, szDate, szTime, szCluster, szHost, szText
|
|
);
|
|
GetDocument()->logStatus(logBuf);
|
|
|
|
if (szDetails != NULL)
|
|
{
|
|
GetDocument()->logStatus((LPWSTR) szDetails);
|
|
}
|
|
|
|
end_unlock:
|
|
|
|
mfn_Unlock();
|
|
|
|
|
|
if (fLogTrimError)
|
|
{
|
|
static LONG ReentrancyCount;
|
|
//
|
|
// We're going to call ourselves recursively, better make sure that
|
|
// we will NOT try to trim the log this time, or else we'll end
|
|
// up in a recursive loop.
|
|
//
|
|
if (InterlockedIncrement(&ReentrancyCount)==1)
|
|
{
|
|
IUICallbacks::LogEntryHeader Header;
|
|
Header.type = IUICallbacks::LOG_WARNING;
|
|
this->LogString(
|
|
&Header,
|
|
GETRESOURCEIDSTRING(IDS_LOG_TRIMMING_LOG_ENTRIES)
|
|
);
|
|
}
|
|
InterlockedDecrement(&ReentrancyCount);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void LogView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
|
|
{
|
|
CListView::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
|
|
if (nChar == VK_TAB || nChar == VK_F6)
|
|
{
|
|
// if (::GetAsyncKeyState(VK_SHIFT) > 0)
|
|
if (! (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
|
|
{
|
|
GetDocument()->SetFocusNextView(this, nChar);
|
|
}
|
|
else
|
|
{
|
|
GetDocument()->SetFocusPrevView(this, nChar);
|
|
}
|
|
// DummyAction(L"LogView TAB!");
|
|
}
|
|
else if (nChar == VK_RETURN)
|
|
{
|
|
POSITION pos = NULL;
|
|
CListCtrl& ctrl = GetListCtrl();
|
|
pos = ctrl.GetFirstSelectedItemPosition();
|
|
if(pos != NULL)
|
|
{
|
|
int index = ctrl.GetNextSelectedItem( pos );
|
|
mfn_DisplayDetails(index);
|
|
}
|
|
this->SetFocus();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void LogView::OnDoubleClick(NMHDR* pNotifyStruct, LRESULT* pResult)
|
|
{
|
|
LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) pNotifyStruct; // to get index
|
|
mfn_DisplayDetails(lpnmlv->iItem);
|
|
}
|
|
void
|
|
LogView::mfn_DisplayDetails(int iItem)
|
|
{
|
|
LPCWSTR szCaption = NULL;
|
|
WCHAR rgEvent[64];
|
|
WCHAR rgDate[256];
|
|
WCHAR rgTime[256];
|
|
WCHAR rgCluster[256];
|
|
WCHAR rgHost[256];
|
|
WCHAR rgSummary[256];
|
|
CListCtrl& ctrl = GetListCtrl();
|
|
LPCWSTR szDetails = (LPCWSTR) ctrl.GetItemData(iItem);
|
|
CLocalLogger logCaption;
|
|
|
|
if (szDetails == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
UINT uLen;
|
|
uLen = ctrl.GetItemText(iItem, 0, rgEvent, ASIZE(rgEvent)-1);
|
|
rgEvent[uLen]=0;
|
|
logCaption.Log(IDS_LOG_ENTRY_DETAILS, rgEvent);
|
|
szCaption = logCaption.GetStringSafe();
|
|
|
|
uLen = ctrl.GetItemText(iItem, 1, rgDate, ASIZE(rgDate)-1);
|
|
rgDate[uLen]=0;
|
|
|
|
uLen = ctrl.GetItemText(iItem, 2, rgTime, ASIZE(rgTime)-1);
|
|
rgTime[uLen]=0;
|
|
|
|
uLen = ctrl.GetItemText(iItem, 3, rgCluster, ASIZE(rgCluster)-1);
|
|
rgTime[uLen]=0;
|
|
|
|
uLen = ctrl.GetItemText(iItem, 4, rgHost, ASIZE(rgHost)-1);
|
|
rgHost[uLen]=0;
|
|
|
|
uLen = ctrl.GetItemText(iItem, 5, rgSummary, ASIZE(rgSummary)-1);
|
|
rgTime[uLen]=0;
|
|
|
|
if (szDetails != NULL)
|
|
{
|
|
//
|
|
// We need to REMOVE the hint text we added to the summary
|
|
// In the LogView list entry (see LogView::LogString, or search
|
|
// for IDS_LOG_DETAILS_HINT).
|
|
//
|
|
_bstr_t bstrHint = GETRESOURCEIDSTRING( IDS_LOG_DETAILS_HINT);
|
|
LPCWSTR szHint = bstrHint;
|
|
if (szHint != NULL)
|
|
{
|
|
LPWSTR szLoc = wcsstr(rgSummary, szHint);
|
|
if (szLoc != NULL)
|
|
{
|
|
//
|
|
// Found the hint -- chop it off..
|
|
//
|
|
*szLoc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
DetailsDialog Details(
|
|
GetDocument(),
|
|
szCaption, // Caption
|
|
rgDate,
|
|
rgTime,
|
|
rgCluster,
|
|
rgHost,
|
|
NULL, // TODO: rgInterface
|
|
rgSummary,
|
|
szDetails,
|
|
this // parent
|
|
);
|
|
|
|
(void) Details.DoModal();
|
|
}
|
|
|
|
end:
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
LogView::mfn_Lock(void)
|
|
{
|
|
//
|
|
// See notes.txt entry
|
|
// 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
|
|
// for the reason for this convoluted implementation of mfn_Lock
|
|
//
|
|
|
|
while (!TryEnterCriticalSection(&m_crit))
|
|
{
|
|
ProcessMsgQueue();
|
|
Sleep(100);
|
|
}
|
|
}
|
|
|
|
void
|
|
LogView::Deinitialize(void)
|
|
{
|
|
ASSERT(m_fPrepareToDeinitialize);
|
|
// DummyAction(L"LogView::Deinitialize");
|
|
}
|