Source code of Windows XP (NT5)
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.

633 lines
16 KiB

  1. #include "stdafx.h"
  2. #include "source.h"
  3. #include "lcsource.h"
  4. #include "regkey.h"
  5. #include "source.h"
  6. #include "utils.h"
  7. #include "globals.h"
  8. #include "busy.h"
  9. #include "trapreg.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CLcSource
  12. CLcSource::CLcSource()
  13. {
  14. }
  15. CLcSource::~CLcSource()
  16. {
  17. }
  18. //***************************************************************************
  19. //
  20. // CLcSource::AddMessage
  21. //
  22. // Add a message to the list control. This sets the text for each column in
  23. // the list view and sets the lParam field of the list-view item to pMessage.
  24. //
  25. //
  26. // Parameters:
  27. // CMessage* pMessage
  28. //
  29. // Returns:
  30. // Nothing.
  31. //
  32. // Status:
  33. //
  34. //***************************************************************************
  35. void CLcSource::AddMessage(CXMessage* pMessage)
  36. {
  37. CString sText;
  38. pMessage->GetShortId(sText);
  39. // Insert a new item into this list control.
  40. LV_ITEM lvitem;
  41. lvitem.mask = LVIF_TEXT | LVIF_PARAM;
  42. lvitem.iSubItem = ICOL_LcSource_EVENTID;
  43. lvitem.cchTextMax = MAX_STRING;
  44. lvitem.lParam = (LPARAM)pMessage;
  45. lvitem.pszText = (LPTSTR)(LPCTSTR)sText;
  46. int nItem = InsertItem(&lvitem);
  47. if (nItem >= 0)
  48. {
  49. CXEventSource* pEventSource = pMessage->m_pEventSource;
  50. // Now set the string value for each sub-item.
  51. pMessage->GetSeverity(sText);
  52. SetItemText(nItem, ICOL_LcSource_SEVERITY, (LPTSTR)(LPCTSTR) sText);
  53. pMessage->IsTrapping(sText);
  54. SetItemText(nItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sText);
  55. SetItemText(nItem, ICOL_LcSource_DESCRIPTION, (LPTSTR)(LPCTSTR) pMessage->m_sText);
  56. }
  57. }
  58. //*******************************************************************
  59. // CXMessageArray::SetDescriptionWidth
  60. //
  61. // Set the width of the description field so that it is wide enough to
  62. // hold the widest message.
  63. //
  64. // Parameters:
  65. // CXMessageArray& aMessages
  66. // The message array that will be used to fill the list control.
  67. //
  68. // Returns:
  69. // Nothing.
  70. //
  71. //*******************************************************************
  72. void CLcSource::SetDescriptionWidth(CXMessageArray& aMessages)
  73. {
  74. LONG cxWidestMessage = CX_DEFAULT_DESCRIPTION_WIDTH;
  75. LONG nMessages = aMessages.GetSize();
  76. for (LONG iMessage = 0; iMessage < nMessages; ++iMessage) {
  77. CXMessage* pMessage = aMessages[iMessage];
  78. int cx = GetStringWidth(pMessage->m_sText);
  79. if (cx > cxWidestMessage) {
  80. cxWidestMessage = cx;
  81. }
  82. }
  83. // Set the column width to the width of the widest string plus a little extra
  84. // space for slop and to make it obvious to the user that the complete string
  85. // is displayed.
  86. SetColumnWidth(ICOL_LcSource_DESCRIPTION, cxWidestMessage + CX_DESCRIPTION_SLOP);
  87. }
  88. //***************************************************************************
  89. //
  90. // CLcSource::LoadMessages
  91. //
  92. // Load the messages from the message library module and insert them into
  93. // this list control.
  94. //
  95. // Parameters:
  96. // CMessage* pMessage
  97. //
  98. // Returns:
  99. // Nothing.
  100. //
  101. // Status:
  102. //
  103. //***************************************************************************
  104. SCODE CLcSource::SetEventSource(CXEventSource* pEventSource)
  105. {
  106. CBusy busy;
  107. DeleteAllItems();
  108. if (pEventSource == NULL) {
  109. return S_OK;
  110. }
  111. UpdateWindow();
  112. //!!!CR: Should do something with the return code in case the
  113. //!!!CR: messages weren't loaded.
  114. SCODE sc = pEventSource->LoadMessages();
  115. // Iterate through each of the messages and insert them into
  116. // the list control.
  117. CXMessageArray& aMessages = pEventSource->m_aMessages;
  118. // Set the width of the description field so that it is wide enough to contain
  119. // the widest message.
  120. SetDescriptionWidth(aMessages);
  121. LONG nMessages = aMessages.GetSize();
  122. for (LONG iMessage=0; iMessage < nMessages; ++iMessage) {
  123. if ((iMessage < 40 && (iMessage % 10 == 9)) ||
  124. (iMessage % 100 == 99)) {
  125. // Update the window often for the first few messages and less frequently
  126. // thereafter for a good response time.
  127. UpdateWindow();
  128. }
  129. AddMessage(aMessages[iMessage]);
  130. }
  131. SortItems(ICOL_LcSource_EVENTID);
  132. SetRedraw(TRUE);
  133. UpdateWindow();
  134. EnsureVisible(0, FALSE);
  135. if (GetSize())
  136. SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
  137. return S_OK;
  138. }
  139. BEGIN_MESSAGE_MAP(CLcSource, CListCtrl)
  140. //{{AFX_MSG_MAP(CLcSource)
  141. //}}AFX_MSG_MAP
  142. END_MESSAGE_MAP()
  143. /////////////////////////////////////////////////////////////////////////////
  144. // CLcSource message handlers
  145. //***************************************************************************
  146. //
  147. // CLcSource::CreateWindowEpilogue()
  148. //
  149. // This method is called after a window has been created for this list
  150. // control. Final initialization is done here.
  151. //
  152. // Parameters:
  153. // None.
  154. //
  155. // Returns:
  156. // SCODE
  157. // S_OK if the initialization was successful, otherwise E_FAIL.
  158. //
  159. // Status:
  160. //
  161. //***************************************************************************
  162. SCODE CLcSource::CreateWindowEpilogue()
  163. {
  164. ListView_SetExtendedListViewStyle(m_hWnd, LVS_EX_FULLROWSELECT);
  165. SetColumnHeadings();
  166. return S_OK;
  167. }
  168. //***************************************************************************
  169. //
  170. // CLcSource::SetColumnHeadings
  171. //
  172. // Define's the columns for this list control. The column title, width, and
  173. // order is defined here.
  174. //
  175. // Parameters:
  176. // None.
  177. //
  178. // Returns:
  179. // Nothing.
  180. //
  181. // Status:
  182. //
  183. //***************************************************************************
  184. void CLcSource::SetColumnHeadings()
  185. {
  186. static UINT auiResColumnTitle[ICOL_LcSource_MAX] = {
  187. IDS_LcSource_TITLE_EVENT_ID,
  188. IDS_LcSource_TITLE_SEVERITY,
  189. IDS_LcSource_TITLE_TRAPPING,
  190. IDS_LcSource_TITLE_DESCRIPTION
  191. };
  192. static int aiColWidth[ICOL_LcSource_MAX] = {60, 75, 60, CX_DEFAULT_DESCRIPTION_WIDTH};
  193. // Build the columns in the AllEventsList control.
  194. LV_COLUMN lvcol;
  195. lvcol.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  196. for (int iCol=0; iCol<ICOL_LcSource_MAX; ++iCol)
  197. {
  198. CString sColTitle;
  199. sColTitle.LoadString(auiResColumnTitle[iCol]);
  200. lvcol.pszText = sColTitle.GetBuffer(sColTitle.GetLength());
  201. lvcol.iSubItem = iCol;
  202. lvcol.cx = aiColWidth[iCol];
  203. InsertColumn(iCol, &lvcol);
  204. sColTitle.ReleaseBuffer();
  205. }
  206. }
  207. //******************************************************************
  208. // CLcSource::Find
  209. //
  210. // Find the specified event source in this list control.
  211. //
  212. // Parameters:
  213. // CString& sText
  214. // A string containing the text to search for.
  215. //
  216. // BOOL bWholeWord
  217. // TRUE if this is a "whole word" search. False if it
  218. // is OK to match a partial word.
  219. //
  220. // BOOL bMatchCase
  221. // TRUE if a case-sensitive comparison should be used.
  222. //
  223. // Returns:
  224. // BOOL
  225. // TRUE if the string was found, FALSE otherwise. If the specified
  226. // text is found, then the selection is set on the corresponding
  227. // list control item, the item is scrolled into view and the focus
  228. // is set on the item.
  229. //
  230. //******************************************************************
  231. BOOL CLcSource::Find(CString sText, BOOL bWholeWord, BOOL bMatchCase)
  232. {
  233. // Don't do anything if the list is empty.
  234. if (GetSize() == 0)
  235. return FALSE;
  236. if (!bMatchCase)
  237. sText.MakeUpper();
  238. // Get the selected item.
  239. LONG iItem = GetNextItem(-1, LVNI_SELECTED);
  240. // Nothing selected; start from the top of the list.
  241. if (iItem == -1)
  242. iItem = 0;
  243. // Iterate through all of the items starting at one item past
  244. // the currently selected item.
  245. CXMessage* pMessage;
  246. CString sDescription;
  247. BOOL bFound = FALSE;
  248. LONG nItems = GetSize();
  249. LONG iItemStart = iItem;
  250. for (long i=0; !bFound && i<nItems; ++i) {
  251. // Bump the item index to the next one and wrap it if its past the
  252. // last item.
  253. iItem = (iItem + 1) % nItems;
  254. // Get the message description for this item.
  255. pMessage = GetAt(iItem);
  256. sDescription = pMessage->m_sText;
  257. if (!bMatchCase)
  258. sDescription.MakeUpper();
  259. if (bWholeWord) {
  260. // Compare the whole word.
  261. bFound = (FindWholeWord(sText, sDescription) != -1);
  262. }
  263. else {
  264. // Look for a substring.
  265. if (sDescription.Find(sText) >= 0)
  266. bFound = TRUE;
  267. }
  268. }
  269. // Found a match.
  270. if (bFound)
  271. {
  272. // Unselect the selected item and select the found item.
  273. SetItemState(iItemStart, 0, LVIS_SELECTED | LVIS_FOCUSED);
  274. SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  275. EnsureVisible(iItem, FALSE);
  276. return TRUE;
  277. }
  278. return FALSE;
  279. }
  280. //***************************************************************************
  281. //
  282. // fnCompareCLcSource
  283. //
  284. // This the item comparison callback method that is called from CLcSource::SortItems.
  285. //
  286. // Parameters:
  287. // LPARAM lParam1
  288. // This is the lparam for the first item to compare. This is a pointer to
  289. // the associated CMessage object.
  290. //
  291. // LPARAM lParam2
  292. // This is the lparam for the second item to compare. This is a pointer to
  293. // the associated CMessage object.
  294. //
  295. // LPARAM lColumn
  296. // This is the second parameter that was passed to CListCtrl::SortItems. This
  297. // happens to be the list control column index.
  298. //
  299. // Returns:
  300. // Nothing.
  301. //
  302. // Status:
  303. //
  304. //***************************************************************************
  305. int CALLBACK fnCompareCLcSource(LPARAM lParam1, LPARAM lParam2, LPARAM lColumn)
  306. {
  307. // !!!CR: The LPARAM parameters are not event pointers in all cases because
  308. // !!!CR: each subitem has its own LPARAM. What should I do?
  309. CXMessage *pmsg1 = (CXMessage *)lParam1;
  310. CXMessage *pmsg2 = (CXMessage *)lParam2;
  311. int nResult = 0;
  312. CString s1, s2;
  313. if (pmsg1 && pmsg2)
  314. {
  315. switch( lColumn)
  316. {
  317. case ICOL_LcSource_EVENTID:
  318. nResult = ((LONG) pmsg1->GetShortId()) - ((LONG)pmsg2->GetShortId());
  319. break;
  320. case ICOL_LcSource_SEVERITY:
  321. pmsg1->GetSeverity(s1);
  322. pmsg2->GetSeverity(s2);
  323. nResult = lstrcmpi(s1, s2);
  324. break;
  325. case ICOL_LcSource_TRAPPING:
  326. pmsg1->IsTrapping(s1);
  327. pmsg2->IsTrapping(s2);
  328. nResult = lstrcmpi(s1, s2);
  329. break;
  330. case ICOL_LcSource_DESCRIPTION:
  331. nResult = lstrcmpi(pmsg1->m_sText, pmsg2->m_sText);
  332. break;
  333. default:
  334. ASSERT(FALSE);
  335. nResult = 0;
  336. break;
  337. }
  338. }
  339. if (!g_abLcSourceSortAscending[lColumn]) {
  340. if (nResult > 0) {
  341. nResult = -1;
  342. }
  343. else if (nResult < 0) {
  344. nResult = 1;
  345. }
  346. }
  347. return(nResult);
  348. }
  349. //***************************************************************************
  350. //
  351. // CLcSource::SortItems
  352. //
  353. // Sort the items in this list control given the column index. This method
  354. // hides all details about the sort implementation from this class's clients.
  355. //
  356. // Parameters:
  357. // DWORD dwColumn
  358. // The column to use as the sort key.
  359. //
  360. // Returns:
  361. // Nothing.
  362. //
  363. // Status:
  364. //
  365. //***************************************************************************
  366. void CLcSource::SortItems(DWORD dwColumn)
  367. {
  368. CListCtrl::SortItems(fnCompareCLcSource, dwColumn);
  369. }
  370. //***************************************************************************
  371. //
  372. // CLcSource::GetSelectedMessages
  373. //
  374. // Fill a message array with pointers to the messages that correspond to
  375. // the selected items in this list control.
  376. //
  377. // Note: This list control continues to own the returned pointers. The
  378. // caller should not delete them.
  379. //
  380. // Parameters:
  381. // CMessageArray& amsg
  382. // The message array where the pointers to the selected messages are
  383. // returned.
  384. //
  385. // Returns:
  386. // The message array is filled with pointers to the selected messages. Do
  387. // not delete them, because they are owned by this object.
  388. //
  389. // Status:
  390. //
  391. //***************************************************************************
  392. void CLcSource::GetSelectedMessages(CXMessageArray& amsg)
  393. {
  394. // Clear the message array
  395. amsg.RemoveAll();
  396. // Setup the LV_ITEM structure to retrieve the lparam field.
  397. // This field contains the CMessage pointer.
  398. LV_ITEM lvitem;
  399. lvitem.mask = LVIF_PARAM;
  400. lvitem.iSubItem = ICOL_LcSource_EVENTID;
  401. // Loop to find all the selected items.
  402. int nItem = -1;
  403. while (TRUE) {
  404. nItem = GetNextItem(nItem, LVNI_SELECTED);
  405. if (nItem == -1) {
  406. break;
  407. }
  408. // Get the CMessage pointer for this item and add it to the
  409. // array.
  410. lvitem.iItem = nItem;
  411. GetItem(&lvitem);
  412. CXMessage* pmsg = (CXMessage*) (void*) lvitem.lParam;
  413. amsg.Add(pmsg);
  414. }
  415. }
  416. //***************************************************************************
  417. //
  418. // CLcSource::FindItem
  419. //
  420. // Search through this list-controls's items to find the one with the
  421. // specified message ID.
  422. //
  423. // Parameters:
  424. // DWORD dwMessageId
  425. // The message ID to search for.
  426. //
  427. // Returns:
  428. // The index of the item with the specified message ID. If no such message ID
  429. // was found, -1 is returned.
  430. //
  431. // Status:
  432. //
  433. //***************************************************************************
  434. LONG CLcSource::FindItem(DWORD dwMessageId)
  435. {
  436. LONG nItems = GetItemCount();
  437. for (LONG iItem = 0; iItem < nItems; ++iItem) {
  438. CXMessage* pMessage = GetAt(iItem);
  439. if (pMessage->m_dwId == dwMessageId) {
  440. return iItem;
  441. }
  442. }
  443. return -1;
  444. }
  445. //***************************************************************************
  446. //
  447. // CLcSource::RefreshItem
  448. //
  449. // This method is called when some aspect of the message has changed and
  450. // the display needs to be updated. This occurs when the trapping status
  451. // of an event changes.
  452. //
  453. // Parameters:
  454. // DWORD dwMessageId
  455. // The message ID to search for.
  456. //
  457. // Returns:
  458. // The index of the item with the specified message ID. If no such message ID
  459. // was found, -1 is returned.
  460. //
  461. // Status:
  462. //
  463. //***************************************************************************
  464. void CLcSource::RefreshItem(LONG iItem)
  465. {
  466. CXMessage* pMessage = GetAt(iItem);
  467. CString sText;
  468. // Now set the text value for each column in the list control.
  469. pMessage->GetSeverity(sText);
  470. SetItemText(iItem, ICOL_LcSource_SEVERITY, (LPTSTR)(LPCTSTR) sText);
  471. // Check if we are trapping this event.
  472. pMessage->IsTrapping(sText);
  473. SetItemText(iItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sText);
  474. SetItemText(iItem, ICOL_LcSource_DESCRIPTION, (LPTSTR)(LPCTSTR)pMessage->m_sText);
  475. }
  476. //***************************************************************************
  477. //
  478. // CLcSource::GetAt
  479. //
  480. // This method returns the message pointer located at the given item index.
  481. // This allows CLcSource to be used much as an array.
  482. //
  483. // Parameters:
  484. // LONG iItem
  485. // The item index.
  486. //
  487. // Returns:
  488. // A pointer to the CMessage stored at the specified index.
  489. //
  490. // Status:
  491. //
  492. //***************************************************************************
  493. CXMessage* CLcSource::GetAt(LONG iItem)
  494. {
  495. // Setup the LV_ITEM structure to retrieve the lparam field.
  496. // This field contains the CMessage pointer.
  497. LV_ITEM lvitem;
  498. lvitem.mask = LVIF_PARAM;
  499. lvitem.iSubItem = ICOL_LcSource_EVENTID;
  500. lvitem.iItem = iItem;
  501. GetItem(&lvitem);
  502. CXMessage* pMessage = (CXMessage*) (void*) lvitem.lParam;
  503. return pMessage;
  504. }
  505. //***************************************************************************
  506. // CLcSource::NotifyTrappingChange
  507. //
  508. // This method is called when a message's trapping status changes. A message
  509. // is considered trapped if it appears in the CLcEvents listbox.
  510. //
  511. // Parameters:
  512. // DWORD dwMessageId
  513. // The ID of the message who's trapping status is changing.
  514. //
  515. // BOOL bIsTrapping
  516. // TRUE if the message is being trapped, FALSE otherwise.
  517. //
  518. // Returns:
  519. // Nothing.
  520. //
  521. //***************************************************************************
  522. void CLcSource::NotifyTrappingChange(DWORD dwMessageId, BOOL bIsTrapping)
  523. {
  524. LONG iItem = FindItem(dwMessageId);
  525. ASSERT(iItem != -1);
  526. if (iItem != -1) {
  527. CString sTrapping;
  528. sTrapping.LoadString(bIsTrapping ? IDS_IS_TRAPPING : IDS_NOT_TRAPPING);
  529. SetItemText(iItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sTrapping);
  530. }
  531. }