Leaked source code of windows server 2003
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

//***************************************************************************
//
// 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");
}