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.

737 lines
21 KiB

  1. // lcevents.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "eventrap.h"
  5. #include "lcevents.h"
  6. #include "settings.h"
  7. #include "source.h"
  8. #include "globals.h"
  9. #include "utils.h"
  10. #include "lcsource.h"
  11. #include "busy.h"
  12. #include "trapreg.h"
  13. #ifdef _DEBUG
  14. #undef THIS_FILE
  15. static char BASED_CODE THIS_FILE[] = __FILE__;
  16. #endif
  17. /////////////////////////////////////////////////////////////////////////////
  18. // CLcEvents
  19. CLcEvents::CLcEvents()
  20. {
  21. m_dwSortColumn = ICOL_LcEvents_LOG;
  22. m_cxWidestMessage = CX_DEFAULT_DESCRIPTION_WIDTH;
  23. }
  24. CLcEvents::~CLcEvents()
  25. {
  26. }
  27. BEGIN_MESSAGE_MAP(CLcEvents, CListCtrl)
  28. //{{AFX_MSG_MAP(CLcEvents)
  29. //}}AFX_MSG_MAP
  30. END_MESSAGE_MAP()
  31. SCODE CLcEvents::CreateWindowEpilogue()
  32. {
  33. ListView_SetExtendedListViewStyle(m_hWnd, LVS_EX_FULLROWSELECT);
  34. SetColumnHeadings();
  35. return S_OK;
  36. }
  37. /////////////////////////////////////////////////////////////////////////////
  38. // CLcEvents message handlers
  39. //***************************************************************************
  40. // CLcEvents::SelectEvents
  41. //
  42. // Select the specified events in the list control.
  43. //
  44. // Parameters:
  45. // CXEventArray& aEvents
  46. // An array of event pointers.
  47. //
  48. // Returns:
  49. // Nothing.
  50. //
  51. // Status:
  52. //
  53. //***************************************************************************
  54. void CLcEvents::SelectEvents(CXEventArray& aEventsSel)
  55. {
  56. int iItemFirstSelection = -1;
  57. LONG nItems = GetSize();
  58. for (LONG iItem = 0; iItem < nItems; ++iItem) {
  59. CXEvent* pEventTrapping = GetAt(iItem);
  60. // If the event associated with this item is in aEvents, then select the item.
  61. // Otherwise clear selection on the item.
  62. BOOL bDidFindEvent = FALSE;
  63. LONG nEventsSel = aEventsSel.GetSize();
  64. for (LONG iEventSel = 0; iEventSel < nEventsSel; ++iEventSel) {
  65. CXEvent* pEventSel;
  66. pEventSel = aEventsSel[iEventSel];
  67. if ((pEventSel->m_message.m_dwId == pEventTrapping->m_message.m_dwId) &&
  68. (pEventSel->m_pEventSource == pEventTrapping->m_pEventSource) &&
  69. (pEventSel->m_pEventSource->m_pEventLog == pEventTrapping->m_pEventSource->m_pEventLog)) {
  70. bDidFindEvent = TRUE;
  71. if (iItemFirstSelection == -1) {
  72. iItemFirstSelection = iItem;
  73. }
  74. break;
  75. }
  76. }
  77. SetItemState(iItem, bDidFindEvent ? LVIS_SELECTED : 0, LVIS_SELECTED);
  78. }
  79. // Scroll the first selected item into view.
  80. if (iItemFirstSelection > 0) {
  81. EnsureVisible(iItemFirstSelection, FALSE);
  82. }
  83. }
  84. //***************************************************************************
  85. //
  86. // CLcEvents::SetColumnHeadings
  87. //
  88. // Define's the columns for this list control. The column title, width, and
  89. // order is defined here.
  90. //
  91. // Parameters:
  92. // None.
  93. //
  94. // Returns:
  95. // Nothing.
  96. //
  97. // Status:
  98. //
  99. //***************************************************************************
  100. void CLcEvents::SetColumnHeadings()
  101. {
  102. static UINT auiResColumnTitle[ICOL_LcEvents_MAX] = {
  103. IDS_LcEvents_TITLE_LOG,
  104. IDS_LcEvents_TITLE_SOURCE,
  105. IDS_LcEvents_TITLE_ID,
  106. IDS_LcEvents_TITLE_SEVERITY,
  107. IDS_LcEvents_TITLE_COUNT,
  108. IDS_LcEvents_TITLE_TIME,
  109. IDS_LcEvents_TITLE_DESCRIPTION
  110. };
  111. static int aiColWidth[ICOL_LcEvents_MAX] = {75, 60, 60, 60, 50, 50, CX_DEFAULT_DESCRIPTION_WIDTH};
  112. // Build the columns in the AllEventsList control.
  113. LV_COLUMN lvcol;
  114. lvcol.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  115. for (int iCol=0; iCol<ICOL_LcEvents_MAX; ++iCol)
  116. {
  117. CString sColTitle;
  118. sColTitle.LoadString(auiResColumnTitle[iCol]);
  119. lvcol.pszText = sColTitle.GetBuffer(sColTitle.GetLength());
  120. lvcol.iSubItem = iCol;
  121. lvcol.cx = aiColWidth[iCol];
  122. InsertColumn(iCol, &lvcol);
  123. sColTitle.ReleaseBuffer();
  124. }
  125. }
  126. //********************************************************************
  127. // CLcEvents::AddEvents
  128. //
  129. // Add all the events for all the event sources contained in the
  130. // event-log array. The source is notified that each of these
  131. // events is being trapped.
  132. //
  133. // Parameters:
  134. // CSource& source
  135. // The message source container.
  136. //
  137. // CEventLogArray& aEventLogs
  138. // An array of event-logs.
  139. //
  140. // Returns:
  141. // Nothing.
  142. //
  143. //*******************************************************************
  144. void CLcEvents::AddEvents(CSource& source, CXEventLogArray& aEventLogs)
  145. {
  146. // Iterate though all the event logs.
  147. LONG nLogs = aEventLogs.GetSize();
  148. for (LONG iLog=0; iLog < nLogs; ++iLog) {
  149. CXEventLog* pEventLog = aEventLogs[iLog];
  150. // Iterate through all the event sources within this event log
  151. LONG nSources = pEventLog->m_aEventSources.GetSize();
  152. for (LONG iSource = 0; iSource < nSources; ++iSource) {
  153. // Add all the events for the source to this list control.
  154. CXEventSource* pEventSource = pEventLog->m_aEventSources[iSource];
  155. AddEvents(source, pEventSource->m_aEvents);
  156. }
  157. }
  158. if (GetSize() > 0 && !HasSelection())
  159. {
  160. SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
  161. }
  162. }
  163. //***************************************************************************
  164. //
  165. // CLcEvents::AddEvents
  166. //
  167. // Add an array of events to this list control. This involves the following
  168. // a. Add each event to the list control
  169. // b. Notify the CLcSource that the event has been modified so that it
  170. // can update the trapping flag.
  171. // c. Sort the events by the most recently selected column.
  172. // d. Make sure that the first item in CEventArray passed in is visible.
  173. //
  174. // Parameters:
  175. // CSource& source
  176. // A reference to the CSource object. This object must be notified
  177. // when the trapping status of an event changes.
  178. //
  179. // CEventArray& aEvents
  180. // An array containing pointers to the events to add. This list control
  181. // then becomes the owner of these events.
  182. //
  183. // Returns:
  184. // Nothing.
  185. //
  186. // Status:
  187. //
  188. //***************************************************************************
  189. void CLcEvents::AddEvents(CSource& source, CXEventArray& aEvents)
  190. {
  191. CBusy busy;
  192. // Now add them into this list control. This is where they actually
  193. LONG nEvents = aEvents.GetSize();
  194. LONG iEvent;
  195. // Unselect all the previous items first
  196. iEvent = -1;
  197. do
  198. {
  199. iEvent = GetNextItem(iEvent, LVNI_SELECTED);
  200. if (iEvent == -1)
  201. break;
  202. SetItemState(iEvent, ~LVIS_SELECTED, LVIS_SELECTED);
  203. } while (TRUE);
  204. for (iEvent = 0; iEvent < nEvents; ++iEvent) {
  205. if ((iEvent < 40 && (iEvent % 10 == 9)) ||
  206. (iEvent % 100 == 99)) {
  207. UpdateWindow();
  208. }
  209. CXEvent* pEvent = aEvents[iEvent];
  210. AddEvent(pEvent);
  211. source.NotifyTrappingChange(pEvent->m_pEventSource, pEvent->m_message.m_dwId, TRUE);
  212. }
  213. UpdateDescriptionWidth();
  214. // Sort the items by the most recently selected column, and then
  215. // make sure the first item is visible.
  216. SortItems(m_dwSortColumn);
  217. if (nEvents > 0) {
  218. iEvent = FindEvent(aEvents[0]);
  219. EnsureVisible(iEvent, TRUE);
  220. }
  221. }
  222. //***************************************************************************
  223. //
  224. // CLcEvents::AddEvent
  225. //
  226. // Add an event to the list control. This sets the text for each column in
  227. // the list view and sets the lParam field of the list-view item to pEvent
  228. //
  229. //
  230. // Parameters:
  231. // CEvent* pEvent
  232. //
  233. // Returns:
  234. // Nothing.
  235. //
  236. // Status:
  237. //
  238. //***************************************************************************
  239. LONG CLcEvents::AddEvent(CXEvent* pEvent)
  240. {
  241. // Insert a new item into this list control.
  242. LV_ITEM lvitem;
  243. lvitem.mask = LVIF_TEXT | LVIF_PARAM;
  244. lvitem.iSubItem = ICOL_LcEvents_LOG;
  245. lvitem.lParam = (LPARAM)pEvent;
  246. lvitem.cchTextMax = pEvent->m_message.m_sText.GetLength() + 1;
  247. lvitem.pszText = (LPTSTR)(void*)(LPCTSTR) (pEvent->m_message.m_sText);
  248. LONG nItem = CListCtrl::InsertItem(&lvitem);
  249. SetItem(nItem, pEvent);
  250. SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED);
  251. return nItem;
  252. }
  253. //********************************************************************
  254. // CLcEvents::SetItem
  255. //
  256. // Refresh an item from an event.
  257. //
  258. // Parameters:
  259. // LONG nItem
  260. //
  261. // CEvent* pEvent
  262. // Pointer to the event to copy the data from.
  263. //
  264. // Returns:
  265. // Nothing.
  266. //
  267. //*******************************************************************
  268. void CLcEvents::SetItem(LONG nItem, CXEvent* pEvent)
  269. {
  270. // Check the item index against the array bounds.
  271. if (nItem < 0 || nItem >= GetItemCount()) {
  272. ASSERT(FALSE);
  273. return;
  274. }
  275. ASSERT(GetItemData(nItem) == (DWORD) (void*) pEvent);
  276. // Get the pointer for brevity.
  277. CXEventSource* pEventSource = pEvent->m_pEventSource;
  278. CString sText;
  279. SetItemData(nItem, (DWORD_PTR) (void*) pEvent);
  280. SetItemText(nItem, ICOL_LcEvents_LOG, (LPTSTR) (LPCTSTR) pEventSource->m_pEventLog->m_sName);
  281. SetItemText(nItem, ICOL_LcEvents_SOURCE, (LPTSTR)(LPCTSTR) pEventSource->m_sName);
  282. pEvent->m_message.GetShortId(sText);
  283. SetItemText(nItem, ICOL_LcEvents_ID, (LPTSTR)(LPCTSTR)sText);
  284. pEvent->m_message.GetSeverity(sText);
  285. SetItemText(nItem, ICOL_LcEvents_SEVERITY, (LPTSTR)(LPCTSTR)sText);
  286. pEvent->GetCount(sText);
  287. SetItemText(nItem, ICOL_LcEvents_COUNT, (LPTSTR)(LPCTSTR)sText);
  288. pEvent->GetTimeInterval(sText);
  289. SetItemText(nItem, ICOL_LcEvents_TIME, (LPTSTR)(LPCTSTR)sText);
  290. SetItemText(nItem, ICOL_LcEvents_DESCRIPTION, (LPTSTR)(LPCTSTR)pEvent->m_message.m_sText);
  291. }
  292. //***************************************************************************
  293. //
  294. // CLcEvents::DeleteSelectedEvents.
  295. //
  296. // Delete all of the currently selected events and the corresponding items.
  297. //
  298. // Parameters:
  299. // None.
  300. //
  301. // Returns:
  302. // Nothing.
  303. //
  304. // Status:
  305. //
  306. //***************************************************************************
  307. void CLcEvents::DeleteSelectedEvents(CSource& source)
  308. {
  309. // Delete all the selected items from the list control.
  310. // Build an array of event pointers corresponding to the events that are selected
  311. // in the list control. Also notify the event source view that the event is no
  312. // longer being trapped.
  313. while (TRUE) {
  314. int iItem = GetNextItem(-1, LVNI_SELECTED);
  315. if (iItem == -1) {
  316. break;
  317. }
  318. CXEvent* pEvent = GetAt(iItem);
  319. DeleteItem(iItem);
  320. source.NotifyTrappingChange(pEvent->m_pEventSource, pEvent->m_message.m_dwId, FALSE);
  321. delete pEvent;
  322. }
  323. UpdateDescriptionWidth();
  324. }
  325. //***************************************************************************
  326. //
  327. // CLcEvents::GetAt
  328. //
  329. // This method returns the event pointer located at the given item index.
  330. // This allows CLcEvents to be used much as an array.
  331. //
  332. // Parameters:
  333. // LONG iItem
  334. // The item index.
  335. //
  336. // Returns:
  337. // A pointer to the CEvent stored at the specified index.
  338. //
  339. // Status:
  340. //
  341. //***************************************************************************
  342. CXEvent* CLcEvents::GetAt(LONG iItem)
  343. {
  344. // Setup the LV_ITEM structure to retrieve the lparam field.
  345. // This field contains the CMessage pointer.
  346. LV_ITEM lvitem;
  347. lvitem.mask = LVIF_PARAM;
  348. lvitem.iSubItem = ICOL_LcEvents_LOG;
  349. lvitem.iItem = iItem;
  350. GetItem(&lvitem);
  351. CXEvent* pEvent = (CXEvent*) (void*) lvitem.lParam;
  352. return pEvent;
  353. }
  354. //***************************************************************************
  355. //
  356. // CLcEvents::GetSelectedEvents
  357. //
  358. // Get the events corresponding to the selected items in this list control.
  359. // This list control continues to own the event pointers.
  360. //
  361. // Parameters:
  362. // CEventArray& aEvents
  363. // A reference to the event array where the event pointers are returned.
  364. //
  365. // Returns:
  366. // Nothing.
  367. //
  368. // Status:
  369. //
  370. //***************************************************************************
  371. void CLcEvents::GetSelectedEvents(CXEventArray& aEvents)
  372. {
  373. // Clear the message array
  374. aEvents.RemoveAll();
  375. // Setup the LV_ITEM structure to retrieve the lparam field.
  376. // This field contains the CMessage pointer.
  377. LV_ITEM lvitem;
  378. lvitem.mask = LVIF_PARAM;
  379. lvitem.iSubItem = ICOL_LcEvents_LOG;
  380. // Loop to find all the selected items.
  381. int nItem = -1;
  382. while (TRUE) {
  383. nItem = GetNextItem(nItem, LVNI_SELECTED);
  384. if (nItem == -1) {
  385. break;
  386. }
  387. // Get the CMessage pointer for this item and add it to the
  388. // array.
  389. lvitem.iItem = nItem;
  390. GetItem(&lvitem);
  391. CXEvent* pEvent = (CXEvent*) (void*) lvitem.lParam;
  392. aEvents.Add(pEvent);
  393. }
  394. }
  395. //***************************************************************************
  396. //
  397. // CLcEvents::FindEvent
  398. //
  399. // Find the specified event and return its item number.
  400. //
  401. // Parameters:
  402. // CEvent* pEvent
  403. // A pointer to the event to search for.
  404. //
  405. // Returns:
  406. // The item index if the item was found, otherwise -1.
  407. //
  408. // Status:
  409. //
  410. //***************************************************************************
  411. LONG CLcEvents::FindEvent(CXEvent* pEvent)
  412. {
  413. LONG nEvents = GetItemCount();
  414. for (LONG iEvent = 0; iEvent < nEvents; ++iEvent) {
  415. CXEvent* pEventTemp = GetAt(iEvent);
  416. if (pEventTemp == pEvent) {
  417. return iEvent;
  418. }
  419. }
  420. return -1;
  421. }
  422. //***************************************************************************
  423. //
  424. // CLcEvents::RefreshEvents
  425. //
  426. // This method is called when the properties of some number of events
  427. // have changed and the corresponding items in the list control need
  428. // to be updated.
  429. //
  430. // Parameters:
  431. // CEventArray& aEvents
  432. // The events that need to be refreshed.
  433. //
  434. // Returns:
  435. // Nothing.
  436. //
  437. // Status:
  438. //
  439. //***************************************************************************
  440. void CLcEvents::RefreshEvents(CXEventArray& aEvents)
  441. {
  442. // Iterate through each of the events and refresh them.
  443. LONG nEvents = aEvents.GetSize();
  444. for (LONG iEvent = 0; iEvent < nEvents; ++iEvent) {
  445. CXEvent* pEvent = aEvents[iEvent];
  446. LONG nEvent = FindEvent(pEvent);
  447. SetItem(nEvent, pEvent);
  448. }
  449. }
  450. int CALLBACK CompareEventsProc(LPARAM lParam1, LPARAM lParam2, LPARAM
  451. lParamSort)
  452. {
  453. CXEvent* pEvent1 = (CXEvent *)lParam1;
  454. CXEventSource* pEventSource1 = pEvent1->m_pEventSource;
  455. CXEvent* pEvent2 = (CXEvent *)lParam2;
  456. CXEventSource* pEventSource2 = pEvent2->m_pEventSource;
  457. ASSERT((pEvent1 != NULL) && (pEvent2 != NULL));
  458. int nResult = 0;
  459. CString sText1, sText2;
  460. switch( lParamSort)
  461. {
  462. case ICOL_LcEvents_LOG:
  463. // Sort by log, then by source, then by ID
  464. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  465. if (nResult == 0) {
  466. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  467. if (nResult == 0) {
  468. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  469. }
  470. }
  471. break;
  472. case ICOL_LcEvents_SOURCE:
  473. // Sort by source, then by Log, then by ID
  474. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  475. if (nResult == 0) {
  476. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  477. if (nResult == 0) {
  478. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  479. }
  480. }
  481. break;
  482. case ICOL_LcEvents_ID:
  483. // Sort by ID, then by log, then by source.
  484. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  485. if (nResult == 0) {
  486. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  487. if (nResult == 0) {
  488. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  489. }
  490. }
  491. break;
  492. case ICOL_LcEvents_SEVERITY:
  493. // Sort by severity, then by log, then by source, then by ID
  494. pEvent1->m_message.GetSeverity(sText1);
  495. pEvent2->m_message.GetSeverity(sText2);
  496. nResult = lstrcmp(sText1, sText2);
  497. if (nResult == 0) {
  498. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  499. if (nResult == 0) {
  500. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  501. if (nResult == 0) {
  502. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  503. }
  504. }
  505. }
  506. break;
  507. case ICOL_LcEvents_COUNT:
  508. // Sort by count, then by log, then by source, then by ID
  509. pEvent1->GetCount(sText1);
  510. pEvent2->GetCount(sText2);
  511. nResult = lstrcmp(sText1, sText2);
  512. if (nResult == 0) {
  513. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  514. if (nResult == 0) {
  515. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  516. if (nResult == 0) {
  517. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  518. }
  519. }
  520. }
  521. break;
  522. case ICOL_LcEvents_TIME:
  523. // Sort by time, then by log, then by source, then by ID
  524. pEvent1->GetTimeInterval(sText1);
  525. pEvent2->GetTimeInterval(sText2);
  526. nResult = lstrcmp(sText1, sText2);
  527. if (nResult == 0) {
  528. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  529. if (nResult == 0) {
  530. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  531. if (nResult == 0) {
  532. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  533. }
  534. }
  535. }
  536. break;
  537. case ICOL_LcEvents_DESCRIPTION:
  538. // Sort by description, then by log, then by source, then by ID
  539. nResult = lstrcmp(pEvent1->m_message.m_sText, pEvent2->m_message.m_sText);
  540. if (nResult == 0) {
  541. nResult = lstrcmp(pEventSource1->m_pEventLog->m_sName, pEventSource2->m_pEventLog->m_sName);
  542. if (nResult == 0) {
  543. nResult = lstrcmp(pEventSource1->m_sName, pEventSource2->m_sName);
  544. if (nResult == 0) {
  545. nResult = ((LONG) pEvent1->m_message.GetShortId()) - ((LONG) pEvent2->m_message.GetShortId());
  546. }
  547. }
  548. }
  549. break;
  550. default:
  551. ASSERT(FALSE);
  552. break;
  553. }
  554. if (!g_abLcEventsSortAscending[lParamSort]) {
  555. if (nResult > 0) {
  556. nResult = -1;
  557. }
  558. else if (nResult < 0) {
  559. nResult = 1;
  560. }
  561. }
  562. return nResult;
  563. }
  564. //***************************************************************************
  565. //
  566. // CLcEvents::SortItems
  567. //
  568. // Sort the items in this list control given the column index. This method
  569. // hides all details about the sort implementation from this class's clients.
  570. //
  571. // Parameters:
  572. // DWORD dwColumn
  573. // The column to use as the sort key.
  574. //
  575. // Returns:
  576. // Nothing.
  577. //
  578. // Status:
  579. //
  580. //***************************************************************************
  581. void CLcEvents::SortItems(DWORD dwColumn)
  582. {
  583. CListCtrl::SortItems(CompareEventsProc, dwColumn);
  584. m_dwSortColumn = dwColumn;
  585. }
  586. //****************************************************************************
  587. // CLcEvents::UpdateDescriptionWidth()
  588. //
  589. // Measure the message description string associated with each item and set the
  590. // width of the description column to match the widest message length plus a
  591. // little extra room for slop and appearances.
  592. //
  593. // Parameters:
  594. // None.
  595. //
  596. // Returns:
  597. // Nothing.
  598. //
  599. //*****************************************************************************
  600. void CLcEvents::UpdateDescriptionWidth()
  601. {
  602. LONG cxWidestMessage = CX_DEFAULT_DESCRIPTION_WIDTH;
  603. LONG nEvents = GetItemCount();
  604. for (LONG iEvent = 0; iEvent < nEvents; ++iEvent) {
  605. CXEvent* pEvent = GetAt(iEvent);
  606. int cx = GetStringWidth(pEvent->m_message.m_sText);
  607. if (cx > cxWidestMessage) {
  608. cxWidestMessage = cx;
  609. }
  610. }
  611. // Set the column width to the width of the widest string plus a little extra
  612. // space for slop and to make it obvious to the user that the complete string
  613. // is displayed.
  614. SetColumnWidth(ICOL_LcEvents_DESCRIPTION, cxWidestMessage + CX_DESCRIPTION_SLOP);
  615. }