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

  1. //***************************************************************************
  2. //
  3. // LOGVIEW.CPP
  4. //
  5. // Module: NLB Manager (client-side exe)
  6. //
  7. // Purpose: Implementation of the view of a log of events.
  8. //
  9. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  10. //
  11. // History:
  12. //
  13. // 08/03/01 JosephJ Adapted from now defunct RightBottomView
  14. //
  15. //***************************************************************************
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "private.h"
  19. IMPLEMENT_DYNCREATE( LogView, CListView )
  20. BEGIN_MESSAGE_MAP( LogView, CListView )
  21. ON_WM_KEYDOWN()
  22. // ON_NOTIFY(HDN_ITEMCLICK, 0, OnHeaderClock)
  23. ON_NOTIFY_REFLECT(NM_DBLCLK, OnDoubleClick)
  24. // ON_NOTIFY(NM_CLICK, 1, OnDoubleClick)
  25. // ON_NOTIFY(NM_KEYDOWN, 1, OnDoubleClick)
  26. END_MESSAGE_MAP()
  27. LogView::LogView()
  28. : m_fPrepareToDeinitialize(FALSE)
  29. {
  30. InitializeCriticalSection(&m_crit);
  31. }
  32. LogView::~LogView()
  33. {
  34. DeleteCriticalSection(&m_crit);
  35. }
  36. Document*
  37. LogView::GetDocument()
  38. {
  39. return ( Document *) m_pDocument;
  40. }
  41. void
  42. LogView::OnInitialUpdate()
  43. {
  44. CListCtrl& ctrl = GetListCtrl();
  45. //
  46. // set images for this view.
  47. //
  48. ctrl.SetImageList( GetDocument()->m_images48x48,
  49. LVSIL_SMALL );
  50. //
  51. // set the style, we only want report
  52. // view
  53. //
  54. // get present style.
  55. LONG presentStyle;
  56. presentStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  57. // Set the last error to zero to avoid confusion.
  58. // See sdk for SetWindowLong.
  59. SetLastError(0);
  60. // set new style.
  61. SetWindowLong( m_hWnd,
  62. GWL_STYLE,
  63. // presentStyle | LVS_REPORT | WS_TILED | WS_CAPTION
  64. // presentStyle | LVS_REPORT | WS_CAPTION
  65. // presentStyle | LVS_REPORT | WS_DLGFRAME
  66. presentStyle | LVS_REPORT| LVS_NOSORTHEADER
  67. );
  68. // SetWindowText(L"Log view");
  69. ctrl.InsertColumn(0,
  70. GETRESOURCEIDSTRING( IDS_HEADER_LOG_TYPE),
  71. LVCFMT_LEFT,
  72. Document::LV_COLUMN_TINY );
  73. ctrl.InsertColumn(1,
  74. GETRESOURCEIDSTRING( IDS_HEADER_LOG_DATE),
  75. LVCFMT_LEFT,
  76. Document::LV_COLUMN_SMALL );
  77. ctrl.InsertColumn(2,
  78. GETRESOURCEIDSTRING( IDS_HEADER_LOG_TIME),
  79. LVCFMT_LEFT,
  80. Document::LV_COLUMN_SMALLMEDIUM );
  81. ctrl.InsertColumn(3,
  82. GETRESOURCEIDSTRING( IDS_HEADER_LOG_CLUSTER),
  83. LVCFMT_LEFT,
  84. Document::LV_COLUMN_MEDIUM);
  85. ctrl.InsertColumn(4,
  86. GETRESOURCEIDSTRING( IDS_HEADER_LOG_HOST),
  87. LVCFMT_LEFT,
  88. Document::LV_COLUMN_LARGE);
  89. ctrl.InsertColumn(5,
  90. GETRESOURCEIDSTRING( IDS_HEADER_LOG_TEXT),
  91. LVCFMT_LEFT,
  92. Document::LV_COLUMN_GIGANTIC);
  93. ctrl.SetExtendedStyle( ctrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
  94. IUICallbacks::LogEntryHeader Header;
  95. // we will register
  96. // with the document class,
  97. // as we are the status pane
  98. // and status is reported via us.
  99. GetDocument()->registerLogView( this );
  100. //
  101. // Log a starting-nlbmgr message (needs to be after the registration,
  102. // because if file-logging is enabled and there is an error writing
  103. // the the file, that code tries to log an error message -- that message
  104. // would get dropped if we have not yet registered.
  105. //
  106. LogString(
  107. &Header,
  108. GETRESOURCEIDSTRING(IDS_LOG_NLBMANAGER_STARTED)
  109. );
  110. //
  111. // Make this initial entry the selected one. We want some row highlighted
  112. // to provide a visual cue as we move between views using keystrokes.
  113. //
  114. GetListCtrl().SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
  115. }
  116. //
  117. // Log a message in human-readable form.
  118. //
  119. void
  120. LogView::LogString(
  121. IN const IUICallbacks::LogEntryHeader *pHeader,
  122. IN const wchar_t *szText
  123. )
  124. {
  125. mfn_Lock();
  126. IUICallbacks::LogEntryType Type = pHeader->type;
  127. const wchar_t *szCluster = pHeader->szCluster;
  128. const wchar_t *szHost = pHeader->szHost;
  129. const wchar_t *szDetails = pHeader->szDetails;
  130. static LONG sSequence=0;
  131. LONG Seq;
  132. LPCWSTR szType = L"";
  133. UINT Image = 0;
  134. CListCtrl& ctrl = GetListCtrl();
  135. WCHAR szSequenceNo[64];
  136. LPCWSTR szDate = NULL;
  137. LPCWSTR szTime = NULL;
  138. _bstr_t bstrTime;
  139. _bstr_t bstrDate;
  140. INT nItem = ctrl.GetItemCount();
  141. _bstr_t bstrText = _bstr_t(szText);
  142. BOOL fLogTrimError = FALSE;
  143. if (m_fPrepareToDeinitialize)
  144. {
  145. goto end_unlock;
  146. }
  147. //
  148. // If total count exceeds our limit by 100 entries,
  149. // get rid of the first 100 entries and log a message saying we've
  150. // got rid of those entries.
  151. //
  152. #define MAX_LOG_ITEMS_IN_LIST 1000
  153. #define LOG_ITEMS_TO_DELETE 100
  154. if (nItem > MAX_LOG_ITEMS_IN_LIST)
  155. {
  156. for (int i=0;i < LOG_ITEMS_TO_DELETE;i++)
  157. {
  158. LPCWSTR szDetails = (LPCWSTR) ctrl.GetItemData(0);
  159. delete szDetails; // may be NULL
  160. ctrl.DeleteItem(0);
  161. }
  162. //
  163. // Get the updated count...
  164. //
  165. nItem = ctrl.GetItemCount();
  166. fLogTrimError = TRUE;
  167. }
  168. if (szCluster == NULL)
  169. {
  170. szCluster = L"";
  171. }
  172. if (szHost == NULL)
  173. {
  174. szHost = L"";
  175. }
  176. if (szDetails != NULL)
  177. {
  178. //
  179. // There is detail-info. We make a copy of it and save it
  180. // as the lParam structure. TODO -- copy the
  181. // interface and other info as well.
  182. //
  183. UINT uLen = wcslen(szDetails)+1; // +1 for ending NULL;
  184. WCHAR *szTmp = new WCHAR[uLen];
  185. if (szTmp!=NULL)
  186. {
  187. CopyMemory(szTmp, szDetails, uLen*sizeof(WCHAR));
  188. }
  189. szDetails = szTmp; // could be NULL on mem failure.
  190. if (szDetails != NULL)
  191. {
  192. //
  193. // We'll add a hint to the text to double click for details...
  194. //
  195. bstrText += GETRESOURCEIDSTRING( IDS_LOG_DETAILS_HINT);
  196. LPCWSTR szTmp1 = bstrText;
  197. if (szTmp1 != NULL)
  198. {
  199. szText = szTmp1;
  200. }
  201. }
  202. }
  203. GetTimeAndDate(REF bstrTime, REF bstrDate);
  204. szTime = bstrTime;
  205. szDate = bstrDate;
  206. if (szTime == NULL) szTime = L"";
  207. if (szDate == NULL) szDate = L"";
  208. Seq = InterlockedIncrement(&sSequence);
  209. StringCbPrintf(szSequenceNo, sizeof(szSequenceNo), L"%04lu", Seq);
  210. switch(Type)
  211. {
  212. case IUICallbacks::LOG_ERROR:
  213. Image = Document::ICON_ERROR;
  214. szType = GETRESOURCEIDSTRING(IDS_PARM_ERROR);
  215. break;
  216. case IUICallbacks::LOG_WARNING:
  217. Image = Document::ICON_WARNING;
  218. szType = GETRESOURCEIDSTRING(IDS_PARM_WARN);
  219. break;
  220. case IUICallbacks::LOG_INFORMATIONAL:
  221. Image = Document::ICON_INFORMATIONAL;
  222. szType = GETRESOURCEIDSTRING(IDS_LOGTYPE_INFORMATION);
  223. break;
  224. }
  225. ctrl.InsertItem(
  226. LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
  227. nItem,
  228. szSequenceNo, // text
  229. 0, // nState
  230. 0, // nStateMask
  231. Image,
  232. (LPARAM) szDetails // lParam
  233. );
  234. ctrl.SetItem(
  235. nItem,
  236. 1,// nSubItem
  237. LVIF_TEXT, // nMask
  238. szDate, // lpszItem
  239. 0, // nImage
  240. 0, // nState
  241. 0, // nStateMask
  242. 0 // lParam
  243. );
  244. ctrl.SetItem(
  245. nItem,
  246. 2,// nSubItem
  247. LVIF_TEXT, // nMask
  248. szTime, // lpszItem
  249. 0, // nImage
  250. 0, // nState
  251. 0, // nStateMask
  252. 0 // lParam
  253. );
  254. ctrl.SetItem(
  255. nItem,
  256. 3,// nSubItem
  257. LVIF_TEXT, // nMask
  258. szCluster, // lpszItem
  259. 0, // nImage
  260. 0, // nState
  261. 0, // nStateMask
  262. 0 // lParam
  263. );
  264. ctrl.SetItem(
  265. nItem,
  266. 4,// nSubItem
  267. LVIF_TEXT, // nMask
  268. szHost, // lpszItem
  269. 0, // nImage
  270. 0, // nState
  271. 0, // nStateMask
  272. 0 // lParam
  273. );
  274. ctrl.SetItem(
  275. nItem,
  276. 5,// nSubItem
  277. LVIF_TEXT, // nMask
  278. szText, // lpszItem
  279. 0, // nImage
  280. 0, // nState
  281. 0, // nStateMask
  282. 0 // lParam
  283. );
  284. ctrl.EnsureVisible(nItem, FALSE); // FALSE == partial visibility not ok.
  285. WCHAR logBuf[2*MAXSTRINGLEN];
  286. StringCbPrintf(
  287. logBuf,
  288. sizeof(logBuf),
  289. L"%ls\t%ls\t%ls\t%ls\t%ls\t%ls\t%ls\t\n",
  290. szSequenceNo, szType, szDate, szTime, szCluster, szHost, szText
  291. );
  292. GetDocument()->logStatus(logBuf);
  293. if (szDetails != NULL)
  294. {
  295. GetDocument()->logStatus((LPWSTR) szDetails);
  296. }
  297. end_unlock:
  298. mfn_Unlock();
  299. if (fLogTrimError)
  300. {
  301. static LONG ReentrancyCount;
  302. //
  303. // We're going to call ourselves recursively, better make sure that
  304. // we will NOT try to trim the log this time, or else we'll end
  305. // up in a recursive loop.
  306. //
  307. if (InterlockedIncrement(&ReentrancyCount)==1)
  308. {
  309. IUICallbacks::LogEntryHeader Header;
  310. Header.type = IUICallbacks::LOG_WARNING;
  311. this->LogString(
  312. &Header,
  313. GETRESOURCEIDSTRING(IDS_LOG_TRIMMING_LOG_ENTRIES)
  314. );
  315. }
  316. InterlockedDecrement(&ReentrancyCount);
  317. }
  318. return;
  319. }
  320. void LogView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
  321. {
  322. CListView::OnKeyDown(nChar, nRepCnt, nFlags);
  323. if (nChar == VK_TAB || nChar == VK_F6)
  324. {
  325. // if (::GetAsyncKeyState(VK_SHIFT) > 0)
  326. if (! (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
  327. {
  328. GetDocument()->SetFocusNextView(this, nChar);
  329. }
  330. else
  331. {
  332. GetDocument()->SetFocusPrevView(this, nChar);
  333. }
  334. // DummyAction(L"LogView TAB!");
  335. }
  336. else if (nChar == VK_RETURN)
  337. {
  338. POSITION pos = NULL;
  339. CListCtrl& ctrl = GetListCtrl();
  340. pos = ctrl.GetFirstSelectedItemPosition();
  341. if(pos != NULL)
  342. {
  343. int index = ctrl.GetNextSelectedItem( pos );
  344. mfn_DisplayDetails(index);
  345. }
  346. this->SetFocus();
  347. }
  348. }
  349. void LogView::OnDoubleClick(NMHDR* pNotifyStruct, LRESULT* pResult)
  350. {
  351. LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) pNotifyStruct; // to get index
  352. mfn_DisplayDetails(lpnmlv->iItem);
  353. }
  354. void
  355. LogView::mfn_DisplayDetails(int iItem)
  356. {
  357. LPCWSTR szCaption = NULL;
  358. WCHAR rgEvent[64];
  359. WCHAR rgDate[256];
  360. WCHAR rgTime[256];
  361. WCHAR rgCluster[256];
  362. WCHAR rgHost[256];
  363. WCHAR rgSummary[256];
  364. CListCtrl& ctrl = GetListCtrl();
  365. LPCWSTR szDetails = (LPCWSTR) ctrl.GetItemData(iItem);
  366. CLocalLogger logCaption;
  367. if (szDetails == NULL)
  368. {
  369. goto end;
  370. }
  371. UINT uLen;
  372. uLen = ctrl.GetItemText(iItem, 0, rgEvent, ASIZE(rgEvent)-1);
  373. rgEvent[uLen]=0;
  374. logCaption.Log(IDS_LOG_ENTRY_DETAILS, rgEvent);
  375. szCaption = logCaption.GetStringSafe();
  376. uLen = ctrl.GetItemText(iItem, 1, rgDate, ASIZE(rgDate)-1);
  377. rgDate[uLen]=0;
  378. uLen = ctrl.GetItemText(iItem, 2, rgTime, ASIZE(rgTime)-1);
  379. rgTime[uLen]=0;
  380. uLen = ctrl.GetItemText(iItem, 3, rgCluster, ASIZE(rgCluster)-1);
  381. rgTime[uLen]=0;
  382. uLen = ctrl.GetItemText(iItem, 4, rgHost, ASIZE(rgHost)-1);
  383. rgHost[uLen]=0;
  384. uLen = ctrl.GetItemText(iItem, 5, rgSummary, ASIZE(rgSummary)-1);
  385. rgTime[uLen]=0;
  386. if (szDetails != NULL)
  387. {
  388. //
  389. // We need to REMOVE the hint text we added to the summary
  390. // In the LogView list entry (see LogView::LogString, or search
  391. // for IDS_LOG_DETAILS_HINT).
  392. //
  393. _bstr_t bstrHint = GETRESOURCEIDSTRING( IDS_LOG_DETAILS_HINT);
  394. LPCWSTR szHint = bstrHint;
  395. if (szHint != NULL)
  396. {
  397. LPWSTR szLoc = wcsstr(rgSummary, szHint);
  398. if (szLoc != NULL)
  399. {
  400. //
  401. // Found the hint -- chop it off..
  402. //
  403. *szLoc = 0;
  404. }
  405. }
  406. }
  407. {
  408. DetailsDialog Details(
  409. GetDocument(),
  410. szCaption, // Caption
  411. rgDate,
  412. rgTime,
  413. rgCluster,
  414. rgHost,
  415. NULL, // TODO: rgInterface
  416. rgSummary,
  417. szDetails,
  418. this // parent
  419. );
  420. (void) Details.DoModal();
  421. }
  422. end:
  423. return;
  424. }
  425. void
  426. LogView::mfn_Lock(void)
  427. {
  428. //
  429. // See notes.txt entry
  430. // 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
  431. // for the reason for this convoluted implementation of mfn_Lock
  432. //
  433. while (!TryEnterCriticalSection(&m_crit))
  434. {
  435. ProcessMsgQueue();
  436. Sleep(100);
  437. }
  438. }
  439. void
  440. LogView::Deinitialize(void)
  441. {
  442. ASSERT(m_fPrepareToDeinitialize);
  443. // DummyAction(L"LogView::Deinitialize");
  444. }