PropEvents.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /////////////////////////////////////////////////////////////////////////////
  2. // PropEvents.cpp : implementation file
  3. //
  4. #include "stdafx.h"
  5. #include "srvconfig.h"
  6. #include "PropEvents.h"
  7. #include <AllSrvModuleIDL.h>
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. /////////////////////////////////////////////////////////////////////////////
  14. // Globals
  15. CAGCModule _AGCModule;
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CPropEvents property page
  18. IMPLEMENT_DYNCREATE(CPropEvents, CPropertyPage)
  19. /////////////////////////////////////////////////////////////////////////////
  20. // Message Map
  21. BEGIN_MESSAGE_MAP(CPropEvents, CPropertyPage)
  22. //{{AFX_MSG_MAP(CPropEvents)
  23. ON_NOTIFY(TVN_DELETEITEM, IDC_EVENTS, OnDeleteItemEvents)
  24. ON_NOTIFY(TVN_KEYDOWN, IDC_EVENTS, OnKeyDownEvents)
  25. ON_NOTIFY(TVN_SELCHANGED, IDC_EVENTS, OnSelChangedEvents)
  26. ON_BN_CLICKED(IDC_BY_GROUP, OnByGroup)
  27. ON_BN_CLICKED(IDC_FLAT_LIST, OnFlatList)
  28. ON_NOTIFY(LVN_DELETEITEM, IDC_EVENTS_LIST, OnDeleteItemEventsList)
  29. ON_NOTIFY(LVN_COLUMNCLICK, IDC_EVENTS_LIST, OnColumnClickEventsList)
  30. //}}AFX_MSG_MAP
  31. END_MESSAGE_MAP()
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Construction / Destruction
  34. CPropEvents::CPropEvents() :
  35. CPropertyPage(CPropEvents::IDD),
  36. m_bstrEvent(L"Event"),
  37. m_bstrEventGroup(L"EventGroup"),
  38. m_bstrName(L"Name"),
  39. m_bstrDisplayName(L"DisplayName"),
  40. m_bstrSeverity(L"Severity"),
  41. m_bstrID(L"id"),
  42. m_bstrLowerBound(L"LowerBound"),
  43. m_bstrUpperBound(L"UpperBound"),
  44. m_bstrDescription(L"Description"),
  45. m_bstrLogAsNTEvent(L"LogAsNTEvent"),
  46. m_bstrLogAsDBEvent(L"LogAsDBEvent"),
  47. m_bstrCanChangeLogAsNTEvent(L"CanChangeLogAsNTEvent"),
  48. m_bstrCanChangeLogAsDBEvent(L"CanChangeLogAsDBEvent"),
  49. m_lParamSelected(NULL),
  50. m_bLoggerObjectIsAlive(false),
  51. m_nSortDirection(1),
  52. m_nSortColumn(1)
  53. {
  54. //{{AFX_DATA_INIT(CPropEvents)
  55. //}}AFX_DATA_INIT
  56. }
  57. CPropEvents::~CPropEvents()
  58. {
  59. // Terminate the logger object appropriate to how we created it
  60. if (NULL != m_spEventLogger)
  61. {
  62. if (!m_bLoggerObjectIsAlive)
  63. {
  64. IAGCEventLoggerPrivatePtr spPrivate(m_spEventLogger);
  65. if (NULL != spPrivate)
  66. spPrivate->Terminate();
  67. }
  68. m_spEventLogger = NULL;
  69. }
  70. // Terminate AGC
  71. _AGCModule.Term();
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. // Attributes
  75. bool CPropEvents::IsDisplayable()
  76. {
  77. // Determine if AGC is properly registered or not
  78. if (!_AGCModule.IsRegistered())
  79. return false;
  80. // Attempt to create AGCEventIDRanges objects
  81. if (FAILED(m_spRangesNT.CreateInstance("AGC.EventIDRanges")))
  82. return false;
  83. if (FAILED(m_spRangesDB.CreateInstance("AGC.EventIDRanges")))
  84. return false;
  85. // Attempt to create an instance of the MSXML component
  86. if (FAILED(m_spXMLDoc.CreateInstance(L"Microsoft.XMLDOM")))
  87. return false;
  88. // Create the AGCEventLogger (either live or static)
  89. return SUCCEEDED(GetEventLogger());
  90. }
  91. /////////////////////////////////////////////////////////////////////////////
  92. // Overrides
  93. void CPropEvents::OnOK()
  94. {
  95. // Save any changes made to the currently-selected node's attributes
  96. UpdateNodeFromItem(m_lParamSelected);
  97. // Inspect the <Event> nodes of the document
  98. if (NULL != m_spXMLDoc)
  99. {
  100. // Get all of the <Event> nodes in the document
  101. IXMLDOMNodeListPtr spNodeList;
  102. VERIFY(SUCCEEDED(m_spXMLDoc->getElementsByTagName(m_bstrEvent,
  103. &spNodeList)));
  104. // Process each node
  105. IXMLDOMNodePtr spNode;
  106. do
  107. {
  108. // Get the next node of the child list
  109. VERIFY(SUCCEEDED(spNodeList->nextNode(&spNode)));
  110. if (NULL != spNode)
  111. {
  112. // Query for the IXMLDOMElement interface
  113. IXMLDOMElementPtr spElement(spNode);
  114. ASSERT(NULL != spElement);
  115. // Get the event id attribute
  116. CComVariant varEventID;
  117. spElement->getAttribute(m_bstrID, &varEventID);
  118. VERIFY(SUCCEEDED(varEventID.ChangeType(VT_I4)));
  119. AGCEventID idEventBegin = (AGCEventID)(V_UI4(&varEventID));
  120. AGCEventID idEventEnd = (AGCEventID)(idEventBegin + 1);
  121. // Get the LogAsNTEvent attribute
  122. IXMLDOMAttributePtr spAttrNT;
  123. if (S_OK == spElement->getAttributeNode(m_bstrLogAsNTEvent, &spAttrNT))
  124. {
  125. CComVariant varLog2NT;
  126. spAttrNT->get_value(&varLog2NT);
  127. VERIFY(SUCCEEDED(varLog2NT.ChangeType(VT_BOOL)));
  128. // Add this event id to the range, if it should be logged
  129. if (V_BOOL(&varLog2NT))
  130. m_spRangesNT->AddByValues(idEventBegin, idEventEnd);
  131. }
  132. // Get the LogAsDBEvent attribute
  133. IXMLDOMAttributePtr spAttrDB;
  134. if (S_OK == spElement->getAttributeNode(m_bstrLogAsDBEvent, &spAttrDB))
  135. {
  136. CComVariant varLog2DB;
  137. spAttrDB->get_value(&varLog2DB);
  138. VERIFY(SUCCEEDED(varLog2DB.ChangeType(VT_BOOL)));
  139. // Add this event id to the range, if it should be logged
  140. if (V_BOOL(&varLog2DB))
  141. m_spRangesDB->AddByValues(idEventBegin, idEventEnd);
  142. }
  143. }
  144. } while (NULL != spNode);
  145. // Set the enabled ranges of the event logger object
  146. VERIFY(SUCCEEDED(m_spEventLogger->put_EnabledNTEvents(m_spRangesNT)));
  147. VERIFY(SUCCEEDED(m_spEventLogger->put_EnabledDBEvents(m_spRangesDB)));
  148. }
  149. // Perform default processing
  150. CPropertyPage::OnOK();
  151. }
  152. void CPropEvents::DoDataExchange(CDataExchange* pDX)
  153. {
  154. // Perform default processing
  155. CPropertyPage::DoDataExchange(pDX);
  156. //{{AFX_DATA_MAP(CPropEvents)
  157. DDX_Control(pDX, IDC_EVENTS_LIST, m_listEvents);
  158. DDX_Control(pDX, IDC_LOG2DB, m_btnLogToDB);
  159. DDX_Control(pDX, IDC_LOG2NT, m_btnLogToNT);
  160. DDX_Control(pDX, IDC_DESCRIPTION, m_staticDescription);
  161. DDX_Control(pDX, IDC_EVENT_ID, m_staticID);
  162. DDX_Control(pDX, IDC_EVENT_TYPE, m_staticType);
  163. DDX_Control(pDX, IDC_EVENTS, m_tree);
  164. //}}AFX_DATA_MAP
  165. }
  166. /////////////////////////////////////////////////////////////////////////////
  167. // Implementation
  168. HRESULT CPropEvents::GetEventLogger()
  169. {
  170. // Determine if AllSrv is running
  171. if (IsAllSrvRunning())
  172. {
  173. // Attempt to create an instance of the Admin.Session object
  174. IAdminSessionPtr spSession;
  175. if (SUCCEEDED(spSession.CreateInstance("AllSrv.AdminSession")))
  176. {
  177. // Attempt to get the session's EventLog property
  178. if (SUCCEEDED(spSession->get_EventLog(&m_spEventLogger)))
  179. {
  180. // Indicate that this is a "live" instance
  181. m_bLoggerObjectIsAlive = true;
  182. // Indicate success
  183. return S_OK;
  184. }
  185. }
  186. }
  187. // Initialize AGC
  188. RETURN_FAILED(_AGCModule.Init());
  189. // Create the set of available AGCEventID ranges
  190. CComPtr<IAGCEventIDRanges> spRanges;
  191. RETURN_FAILED(spRanges.CoCreateInstance(L"AGC.EventIDRanges"));
  192. /////////////////////////////////////////////////////////////////////////
  193. // NOTE: The following ranges should be kept in-sync with the ranges
  194. // used by AllSrv. See CServiceModule::InitAGC() in AllSrvModule.cpp.
  195. // Add our ranges to it
  196. RETURN_FAILED(spRanges->AddByValues(EventID_AGC_LowerBound, EventID_AGC_UpperBound));
  197. RETURN_FAILED(spRanges->AddByValues(AllsrvEventID_Allsrv_LowerBound, AllsrvEventID_Allsrv_UpperBound));
  198. RETURN_FAILED(spRanges->AddByValues(EventID_Admin_LowerBound, EventID_Admin_UpperBound));
  199. // Set the ranges of available events
  200. GetAGCGlobal()->SetAvailableEventIDRanges(spRanges);
  201. // Create the event logger object
  202. RETURN_FAILED(m_spEventLogger.CreateInstance("AGC.EventLogger"));
  203. IAGCEventLoggerPrivatePtr spPrivate(m_spEventLogger);
  204. if (NULL == spPrivate)
  205. return E_UNEXPECTED;
  206. // Keep from firing any events for this static instance
  207. RETURN_FAILED(spPrivate->put_LoggingToNTEnabled(VARIANT_FALSE));
  208. RETURN_FAILED(spPrivate->put_LoggingToDBEnabled(VARIANT_FALSE));
  209. // Initialize the event logger object
  210. CComBSTR bstrEventSource(L"AllSrv");
  211. CComBSTR bstrRegKey("HKLM\\" HKLM_FedSrv);
  212. RETURN_FAILED(spPrivate->Initialize(bstrEventSource, bstrRegKey));
  213. // Indicate success
  214. return S_OK;
  215. }
  216. void CPropEvents::InitEventTree()
  217. {
  218. // Load the image list
  219. if (!m_images.GetSafeHandle())
  220. m_images.Create(IDB_IMAGES, 16, 0, RGB(0, 255, 0));
  221. m_tree.SetImageList(&m_images, TVSIL_NORMAL);
  222. // Clear the tree's current contents, if any
  223. m_tree.DeleteAllItems();
  224. }
  225. void CPropEvents::InitEventList()
  226. {
  227. // Set the control's extended styles
  228. m_listEvents.SetExtendedStyle(LVS_EX_FULLROWSELECT | 0x4000);
  229. // Load the image list
  230. if (!m_images.GetSafeHandle())
  231. m_images.Create(IDB_IMAGES, 16, 0, RGB(0, 255, 0));
  232. m_listEvents.SetImageList(&m_images, LVSIL_SMALL);
  233. // Clear the list's current contents, if any
  234. m_listEvents.DeleteAllItems();
  235. // TODO: Delete all columns, if any
  236. // Insert columns
  237. CString strColumn;
  238. LVCOLUMN lvcol = {LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT};
  239. // Insert Type column
  240. lvcol.iSubItem = 0;
  241. lvcol.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
  242. strColumn.LoadString(IDS_COLUMN_TYPE);
  243. lvcol.pszText = const_cast<LPTSTR>((LPCSTR)strColumn);
  244. m_listEvents.InsertColumn(lvcol.iSubItem, &lvcol);
  245. m_cxMaxType = m_listEvents.GetStringWidth(strColumn + " + ");
  246. // Insert EventID column
  247. lvcol.iSubItem = 1;
  248. lvcol.fmt = LVCFMT_RIGHT;
  249. strColumn.LoadString(IDS_COLUMN_EVENTID);
  250. lvcol.pszText = const_cast<LPTSTR>((LPCSTR)strColumn);
  251. m_listEvents.InsertColumn(lvcol.iSubItem, &lvcol);
  252. m_cxMaxID = m_listEvents.GetStringWidth(strColumn + " + ");
  253. // Insert Name column
  254. lvcol.iSubItem = 2;
  255. lvcol.fmt = LVCFMT_LEFT;
  256. strColumn.LoadString(IDS_COLUMN_NAME);
  257. lvcol.pszText = const_cast<LPTSTR>((LPCSTR)strColumn);
  258. m_listEvents.InsertColumn(lvcol.iSubItem, &lvcol);
  259. }
  260. HRESULT CPropEvents::PopulateTreeAndList()
  261. {
  262. // Get the XML text of the logger's current status
  263. CComBSTR bstrEventList;
  264. RETURN_FAILED(m_spEventLogger->get_EventList(&bstrEventList));
  265. // Load the XML text into the XMLDOM object
  266. VARIANT_BOOL bSucceeded;
  267. RETURN_FAILED(m_spXMLDoc->loadXML(bstrEventList, &bSucceeded));
  268. if (!bSucceeded)
  269. return E_FAIL;
  270. // Get the root element
  271. IXMLDOMElementPtr spRoot;
  272. RETURN_FAILED(m_spXMLDoc->get_documentElement(&spRoot));
  273. #ifdef _DEBUG
  274. {
  275. // Ensure that the root element tag is <AGCEvents>
  276. CComBSTR bstrRoot;
  277. ASSERT(SUCCEEDED(spRoot->get_tagName(&bstrRoot)));
  278. ASSERT(0 == wcscmp(bstrRoot, L"AGCEvents"));
  279. }
  280. #endif // _DEBUG
  281. // Recursively process the children of each group
  282. RETURN_FAILED(AddXMLNodeToTree(spRoot, TVI_ROOT));
  283. // Caculate the column widths
  284. m_cxMaxType += 16 + 2; // Adjust for icon and padding
  285. int cxScroll = GetSystemMetrics(SM_CXVSCROLL);
  286. // Get the width of the list control's client area
  287. CRect rect;
  288. m_listEvents.GetClientRect(rect);
  289. // Compute the Name column to fit the maximum width
  290. int cxTotal = m_cxMaxType + m_cxMaxID + cxScroll;
  291. int cxName = rect.Width() - cxTotal;
  292. // Set the column widths
  293. LVCOLUMN lvcol = {LVCF_WIDTH};
  294. lvcol.cx = m_cxMaxType;
  295. m_listEvents.SetColumn(0, &lvcol);
  296. lvcol.cx = m_cxMaxID;
  297. m_listEvents.SetColumn(1, &lvcol);
  298. lvcol.cx = cxName;
  299. m_listEvents.SetColumn(2, &lvcol);
  300. // Indicate success
  301. return S_OK;
  302. }
  303. HRESULT CPropEvents::AddXMLNodeToTree(IXMLDOMNode* pNode, HTREEITEM hParent)
  304. {
  305. // Get the list of child nodes
  306. IXMLDOMNodeListPtr spChildren;
  307. RETURN_FAILED(pNode->get_childNodes(&spChildren));
  308. // Process each child node
  309. IXMLDOMNodePtr spChild;
  310. do
  311. {
  312. // Get the next node of the child list
  313. RETURN_FAILED(spChildren->nextNode(&spChild));
  314. if (NULL != spChild)
  315. {
  316. // Get the child node's tagname
  317. int iImage;
  318. CString strType;
  319. CString strID;
  320. bool bIsGroup, bIsEvent;
  321. CComBSTR bstrText;
  322. IXMLDOMElementPtr spElement(spChild);
  323. if (NULL != spElement)
  324. {
  325. CComBSTR bstrTagName;
  326. RETURN_FAILED(spElement->get_tagName(&bstrTagName));
  327. if (bstrTagName.Length())
  328. {
  329. // Accept the Event and EventGroup tag names
  330. if (0 == wcscmp(bstrTagName, m_bstrEvent))
  331. {
  332. bIsGroup = false;
  333. bIsEvent = true;
  334. }
  335. else if (0 == wcscmp(bstrTagName, m_bstrEventGroup))
  336. {
  337. bIsGroup = true;
  338. bIsEvent = false;
  339. }
  340. // Get the display attributes if this is a group or event node
  341. if (bIsGroup || bIsEvent)
  342. {
  343. // Get the type of the element
  344. CComBSTR bstrSeverity;
  345. GetElementSeverity(spElement, &bstrSeverity);
  346. iImage = ImageFromSeverity(bstrSeverity);
  347. strType = TypeFromSeverity(bstrSeverity);
  348. // Get the id of the element
  349. CComBSTR bstrID;
  350. GetElementID(spElement, &bstrID);
  351. strID = bstrID;
  352. // Get the name of the element
  353. RETURN_FAILED(GetElementDisplayName(spElement, &bstrText));
  354. }
  355. }
  356. }
  357. // Add the node to the tree and list controls
  358. if (bstrText.Length())
  359. {
  360. // Typecast the element pointer as an LPARAM
  361. IXMLDOMElement* pElement = spElement.Detach();
  362. LPARAM lParam = reinterpret_cast<LPARAM>(pElement);
  363. // Insert the element into the tree
  364. USES_CONVERSION;
  365. LPCTSTR pszText = OLE2CT(bstrText);
  366. UINT mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  367. HTREEITEM hItem = m_tree.InsertItem(mask, pszText, iImage, iImage,
  368. 0, 0, lParam, hParent, TVI_LAST);
  369. // Insert the element into the list, if its not an <EventGroup>
  370. if (!bIsGroup)
  371. {
  372. int iItem = m_listEvents.GetItemCount();
  373. iItem = m_listEvents.InsertItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM,
  374. iItem, strType, 0, 0, iImage, lParam);
  375. if (-1 != iItem)
  376. {
  377. // Keep a reference on the element pointer in the LPARAM
  378. pElement->AddRef();
  379. // Keep track of maximum widths
  380. int cx = m_listEvents.GetStringWidth(strType + " ");
  381. m_cxMaxType = max(m_cxMaxType, cx);
  382. cx = m_listEvents.GetStringWidth(strID + " ");
  383. m_cxMaxID = max(m_cxMaxID, cx);
  384. // Set the subitems
  385. m_listEvents.SetItem(iItem, 1, LVIF_TEXT, strID, 0, 0, 0, 0);
  386. m_listEvents.SetItem(iItem, 2, LVIF_TEXT, pszText, 0, 0, 0, 0);
  387. }
  388. }
  389. // Recurse into node, if it's a group
  390. if (bIsGroup)
  391. {
  392. RETURN_FAILED(AddXMLNodeToTree(spChild, hItem));
  393. }
  394. }
  395. }
  396. } while (NULL != spChild);
  397. // Indicate success
  398. return S_OK;
  399. }
  400. HRESULT CPropEvents::GetElementSeverity(IXMLDOMElement* pElem, BSTR* pbstr)
  401. {
  402. // Get the Severity attribute
  403. CComVariant var;
  404. pElem->getAttribute(m_bstrSeverity, &var);
  405. var.ChangeType(VT_BSTR);
  406. *pbstr = V_BSTR(&var);
  407. V_VT(&var) = VT_EMPTY;
  408. return S_OK;
  409. }
  410. HRESULT CPropEvents::GetElementDisplayName(IXMLDOMElement* pElem, BSTR* pbstr)
  411. {
  412. // Get the DisplayName or Name attribute, in that order
  413. CComVariant var;
  414. if (FAILED(pElem->getAttribute(m_bstrDisplayName, &var)) ||
  415. FAILED(var.ChangeType(VT_BSTR)) ||
  416. !V_BSTR(&var) ||
  417. !SysStringLen(V_BSTR(&var)))
  418. {
  419. RETURN_FAILED(pElem->getAttribute(m_bstrName, &var));
  420. RETURN_FAILED(var.ChangeType(VT_BSTR));
  421. }
  422. *pbstr = V_BSTR(&var);
  423. V_VT(&var) = VT_EMPTY;
  424. return S_OK;
  425. }
  426. HRESULT CPropEvents::GetElementID(IXMLDOMElement* pElem, BSTR* pbstr)
  427. {
  428. // Get the id or LowerBound attribute, in that order
  429. CComVariant var;
  430. if (FAILED(pElem->getAttribute(m_bstrID, &var)) ||
  431. FAILED(var.ChangeType(VT_I4)) ||
  432. FAILED(var.ChangeType(VT_BSTR)))
  433. {
  434. RETURN_FAILED(pElem->getAttribute(m_bstrLowerBound, &var));
  435. RETURN_FAILED(var.ChangeType(VT_I4));
  436. RETURN_FAILED(var.ChangeType(VT_BSTR));
  437. }
  438. *pbstr = V_BSTR(&var);
  439. V_VT(&var) = VT_EMPTY;
  440. return S_OK;
  441. }
  442. HRESULT CPropEvents::GetElementID(IXMLDOMElement* pElem, int* pID)
  443. {
  444. // Get the id or LowerBound attribute, in that order
  445. CComVariant var;
  446. if (FAILED(pElem->getAttribute(m_bstrID, &var)) ||
  447. FAILED(var.ChangeType(VT_I4)))
  448. {
  449. RETURN_FAILED(pElem->getAttribute(m_bstrLowerBound, &var));
  450. RETURN_FAILED(var.ChangeType(VT_I4));
  451. }
  452. *pID = V_I4(&var);
  453. return S_OK;
  454. }
  455. HRESULT CPropEvents::UpdateNodeFromItem(LPARAM lNode)
  456. {
  457. // Typecast the tree item's param as an XML element pointer
  458. IXMLDOMElement* pElement = reinterpret_cast<IXMLDOMElement*>(lNode);
  459. if (!pElement)
  460. return S_FALSE;
  461. // Determine if the node is a group element or an event
  462. CComBSTR bstrTagName;
  463. VERIFY(SUCCEEDED(pElement->get_tagName(&bstrTagName)));
  464. bool bIsEvent = 0 == wcscmp(bstrTagName, m_bstrEvent);
  465. bool bIsGroup = !bIsEvent && 0 == wcscmp(bstrTagName, m_bstrEventGroup);
  466. ASSERT(bIsEvent || bIsGroup);
  467. if (bIsEvent)
  468. {
  469. // Set the LogAsNTEvent attribute
  470. if (GetDlgItem(IDC_LOG2NT)->IsWindowEnabled())
  471. {
  472. CComVariant varLog2NT(!!IsDlgButtonChecked(IDC_LOG2NT));
  473. pElement->setAttribute(m_bstrLogAsNTEvent, varLog2NT);
  474. }
  475. // Set the LogAsDBEvent attribute
  476. if (GetDlgItem(IDC_LOG2DB)->IsWindowEnabled())
  477. {
  478. CComVariant varLog2DB(!!IsDlgButtonChecked(IDC_LOG2DB));
  479. pElement->setAttribute(m_bstrLogAsDBEvent, varLog2DB);
  480. }
  481. }
  482. else
  483. {
  484. // TODO: Work-out how to best support indeterminate checkbox state
  485. }
  486. // Indicate success
  487. return S_OK;
  488. }
  489. HRESULT CPropEvents::UpdateItemFromNode(LPARAM lNode)
  490. {
  491. USES_CONVERSION;
  492. // Typecast the tree item's param as an XML element pointer
  493. IXMLDOMElement* pElement = reinterpret_cast<IXMLDOMElement*>(lNode);
  494. if (!pElement)
  495. return S_FALSE;
  496. // Use to enable/disable the check boxes
  497. bool bEnableLog2NT = false;
  498. bool bEnableLog2DB = false;
  499. // Determine if the node is a group element or an event
  500. CComBSTR bstrTagName;
  501. VERIFY(SUCCEEDED(pElement->get_tagName(&bstrTagName)));
  502. bool bIsEvent = 0 == wcscmp(bstrTagName, m_bstrEvent);
  503. bool bIsGroup = !bIsEvent && 0 == wcscmp(bstrTagName, m_bstrEventGroup);
  504. ASSERT(bIsEvent || bIsGroup);
  505. if (bIsEvent)
  506. {
  507. // Get the Severity attribute
  508. CComVariant varSeverity;
  509. pElement->getAttribute(m_bstrSeverity, &varSeverity);
  510. VERIFY(SUCCEEDED(varSeverity.ChangeType(VT_BSTR)));
  511. SetDlgItemText(IDC_EVENT_TYPE, TypeFromSeverity(V_BSTR(&varSeverity)));
  512. // Get the event id attribute
  513. CComVariant varEventID;
  514. pElement->getAttribute(m_bstrID, &varEventID);
  515. VERIFY(SUCCEEDED(varEventID.ChangeType(VT_I4)));
  516. SetDlgItemInt(IDC_EVENT_ID, V_I4(&varEventID));
  517. // Get the CanChangeLogAsNTEvent attribute
  518. IXMLDOMAttributePtr spAttrNT;
  519. if (S_OK == pElement->getAttributeNode(m_bstrCanChangeLogAsNTEvent, &spAttrNT))
  520. {
  521. CComVariant varCanChange;
  522. spAttrNT->get_value(&varCanChange);
  523. VERIFY(SUCCEEDED(varCanChange.ChangeType(VT_BOOL)));
  524. bEnableLog2NT = !!V_BOOL(&varCanChange);
  525. }
  526. else
  527. {
  528. // When not specified, the default is true
  529. bEnableLog2NT = true;
  530. }
  531. // Get the LogAsNTEvent attribute
  532. CComVariant varLog2NT;
  533. pElement->getAttribute(m_bstrLogAsNTEvent, &varLog2NT);
  534. VERIFY(SUCCEEDED(varLog2NT.ChangeType(VT_BOOL)));
  535. CheckDlgButton(IDC_LOG2NT, V_BOOL(&varLog2NT));
  536. // Get the CanChangeLogAsDBEvent attribute
  537. IXMLDOMAttributePtr spAttrDB;
  538. if (S_OK == pElement->getAttributeNode(m_bstrCanChangeLogAsDBEvent, &spAttrDB))
  539. {
  540. CComVariant varCanChange;
  541. spAttrDB->get_value(&varCanChange);
  542. VERIFY(SUCCEEDED(varCanChange.ChangeType(VT_BOOL)));
  543. bEnableLog2DB = !!V_BOOL(&varCanChange);
  544. }
  545. else
  546. {
  547. // When not specified, the default is true
  548. bEnableLog2DB = true;
  549. }
  550. // Get the LogAsDBEvent attribute
  551. CComVariant varLog2DB;
  552. pElement->getAttribute(m_bstrLogAsDBEvent, &varLog2DB);
  553. VERIFY(SUCCEEDED(varLog2DB.ChangeType(VT_BOOL)));
  554. CheckDlgButton(IDC_LOG2DB, V_BOOL(&varLog2DB));
  555. }
  556. else
  557. {
  558. // Always show the type as "Group"
  559. CString strGroup;
  560. strGroup.LoadString(IDS_TYPE_GROUP);
  561. SetDlgItemText(IDC_EVENT_TYPE, strGroup);
  562. // Get the group LowerBound attribute
  563. CComVariant varLowerBound;
  564. pElement->getAttribute(m_bstrLowerBound, &varLowerBound);
  565. VERIFY(SUCCEEDED(varLowerBound.ChangeType(VT_UI4)));
  566. // Get the group UpperBound attribute
  567. CComVariant varUpperBound;
  568. pElement->getAttribute(m_bstrUpperBound, &varUpperBound);
  569. VERIFY(SUCCEEDED(varUpperBound.ChangeType(VT_UI4)));
  570. // Format the group's range into a string
  571. TCHAR szID[_MAX_PATH];
  572. wsprintf(szID, TEXT("%u - %u"), V_UI4(&varLowerBound),
  573. V_UI4(&varUpperBound));
  574. SetDlgItemText(IDC_EVENT_ID, szID);
  575. // TODO: Work-out how to best support indeterminate checkbox state
  576. CheckDlgButton(IDC_LOG2NT, false);
  577. CheckDlgButton(IDC_LOG2DB, false);
  578. }
  579. // Get the event/group Description attribute
  580. CComVariant varDescription;
  581. pElement->getAttribute(m_bstrDescription, &varDescription);
  582. VERIFY(SUCCEEDED(varDescription.ChangeType(VT_BSTR)));
  583. SetDlgItemText(IDC_DESCRIPTION, OLE2CT(V_BSTR(&varDescription)));
  584. // Enable/disable checkboxes
  585. GetDlgItem(IDC_LOG2NT)->EnableWindow(bEnableLog2NT);
  586. GetDlgItem(IDC_LOG2DB)->EnableWindow(bEnableLog2DB);
  587. // Uncheck checkboxes that are disabled
  588. if (!bEnableLog2NT)
  589. CheckDlgButton(IDC_LOG2NT, false);
  590. if (!bEnableLog2DB)
  591. CheckDlgButton(IDC_LOG2DB, false);
  592. // Indicate success
  593. return S_OK;
  594. }
  595. int CPropEvents::ImageFromSeverity(BSTR bstrSeverity)
  596. {
  597. if (!bstrSeverity || L'\0' == bstrSeverity[0])
  598. return 0;
  599. switch (bstrSeverity[0])
  600. {
  601. case L'E':
  602. case L'e':
  603. return 3;
  604. case L'W':
  605. case L'w':
  606. return 2;
  607. case L'I':
  608. case L'i':
  609. default:
  610. return 1;
  611. }
  612. }
  613. CString CPropEvents::TypeFromSeverity(BSTR bstrSeverity)
  614. {
  615. UINT idRes;
  616. if (!bstrSeverity || L'\0' == bstrSeverity[0])
  617. {
  618. idRes = IDS_TYPE_GROUP;
  619. }
  620. else
  621. {
  622. switch (bstrSeverity[0])
  623. {
  624. case L'E':
  625. case L'e':
  626. idRes = IDS_TYPE_ERROR;
  627. break;
  628. case L'W':
  629. case L'w':
  630. idRes = IDS_TYPE_WARNING;
  631. break;
  632. case L'I':
  633. case L'i':
  634. idRes = IDS_TYPE_INFORMATION;
  635. break;
  636. case L'S':
  637. case L's':
  638. default:
  639. idRes = IDS_TYPE_SUCCESS;
  640. break;
  641. }
  642. }
  643. CString str;
  644. str.LoadString(idRes);
  645. return str;
  646. }
  647. void CPropEvents::ToggleCheckBox(UINT id)
  648. {
  649. CWnd* pwndCheckBox = GetDlgItem(id);
  650. if (!pwndCheckBox->IsWindowEnabled())
  651. MessageBeep(static_cast<DWORD>(-1));
  652. else
  653. {
  654. bool bChecked = BST_CHECKED == IsDlgButtonChecked(id);
  655. CheckDlgButton(id, bChecked ? BST_UNCHECKED : BST_CHECKED);
  656. }
  657. }
  658. PFNLVCOMPARE CPropEvents::SortProcFromColumn(int iSubItem)
  659. {
  660. switch (m_nSortColumn)
  661. {
  662. case 0 : return CompareType;
  663. case 1 : return CompareID ;
  664. case 2 : return CompareName;
  665. default: ASSERT(false); return NULL;
  666. }
  667. }
  668. int CALLBACK CPropEvents::CompareType(LPARAM lp1, LPARAM lp2, LPARAM lpThis)
  669. {
  670. // Typecast the sort parameters
  671. IXMLDOMElement* pElem1 = reinterpret_cast<IXMLDOMElement*>(lp1);
  672. IXMLDOMElement* pElem2 = reinterpret_cast<IXMLDOMElement*>(lp2);
  673. CPropEvents* pThis = reinterpret_cast<CPropEvents*>(lpThis);
  674. // Get the type image index for element 1
  675. CComBSTR bstrSeverity1;
  676. pThis->GetElementSeverity(pElem1, &bstrSeverity1);
  677. int iImage1 = pThis->ImageFromSeverity(bstrSeverity1);
  678. // Get the type image index for element 2
  679. CComBSTR bstrSeverity2;
  680. pThis->GetElementSeverity(pElem2, &bstrSeverity2);
  681. int iImage2 = pThis->ImageFromSeverity(bstrSeverity2);
  682. // Compute the difference, return if not equal
  683. int nDiff = iImage1 - iImage2;
  684. return nDiff ? pThis->m_nSortDirection * nDiff
  685. : CompareID(lp1, lp2, lpThis);
  686. }
  687. int CALLBACK CPropEvents::CompareID(LPARAM lp1, LPARAM lp2, LPARAM lpThis)
  688. {
  689. // Typecast the sort parameters
  690. IXMLDOMElement* pElem1 = reinterpret_cast<IXMLDOMElement*>(lp1);
  691. IXMLDOMElement* pElem2 = reinterpret_cast<IXMLDOMElement*>(lp2);
  692. CPropEvents* pThis = reinterpret_cast<CPropEvents*>(lpThis);
  693. // Get the id for element 1
  694. int id1;
  695. VERIFY(SUCCEEDED(pThis->GetElementID(pElem1, &id1)));
  696. // Get the id for element 2
  697. int id2;
  698. VERIFY(SUCCEEDED(pThis->GetElementID(pElem2, &id2)));
  699. // Return the difference
  700. return pThis->m_nSortDirection * (id1 - id2);
  701. }
  702. int CALLBACK CPropEvents::CompareName(LPARAM lp1, LPARAM lp2, LPARAM lpThis)
  703. {
  704. // Typecast the sort parameters
  705. IXMLDOMElement* pElem1 = reinterpret_cast<IXMLDOMElement*>(lp1);
  706. IXMLDOMElement* pElem2 = reinterpret_cast<IXMLDOMElement*>(lp2);
  707. CPropEvents* pThis = reinterpret_cast<CPropEvents*>(lpThis);
  708. // Get the name for element 1
  709. CComBSTR bstrName1;
  710. VERIFY(SUCCEEDED(pThis->GetElementDisplayName(pElem1, &bstrName1)));
  711. // Get the name for element 2
  712. CComBSTR bstrName2;
  713. VERIFY(SUCCEEDED(pThis->GetElementDisplayName(pElem2, &bstrName2)));
  714. // Return the case-insensitive comparison
  715. int nDiff = _wcsicmp(bstrName1, bstrName2);
  716. return nDiff ? pThis->m_nSortDirection * nDiff
  717. : CompareID(lp1, lp2, lpThis);
  718. }
  719. /////////////////////////////////////////////////////////////////////////////
  720. // Message Handlers
  721. BOOL CPropEvents::OnInitDialog()
  722. {
  723. // Perform default processing
  724. CPropertyPage::OnInitDialog();
  725. // Get the instance of the AGCEventLogger on which we will operate
  726. if (NULL != m_spEventLogger && NULL != m_spXMLDoc)
  727. {
  728. // Initialize the tree and list controls
  729. InitEventTree();
  730. InitEventList();
  731. // Populate the tree and list controls with the event hierarchy
  732. PopulateTreeAndList();
  733. }
  734. else
  735. {
  736. // FORNOW: Disable the whole window
  737. EnableWindow(false);
  738. }
  739. // Select the Tree control view
  740. CheckDlgButton(IDC_BY_GROUP, BST_CHECKED);
  741. OnByGroup();
  742. // Return true to set the focus to the first tabstop control
  743. return true;
  744. }
  745. void CPropEvents::OnDeleteItemEvents(NMHDR* pNMHDR, LRESULT* pResult)
  746. {
  747. // Typecast the specified notification structure
  748. NM_TREEVIEW* pTV = reinterpret_cast<NM_TREEVIEW*>(pNMHDR);
  749. // Typecast the tree item's param as an XML element pointer
  750. IXMLDOMElement* pElement =
  751. reinterpret_cast<IXMLDOMElement*>(pTV->itemOld.lParam);
  752. // Release the XML element pointer associated with the tree item
  753. if (pElement)
  754. pElement->Release();
  755. // Clear the result
  756. *pResult = 0;
  757. }
  758. void CPropEvents::OnKeyDownEvents(NMHDR* pNMHDR, LRESULT* pResult)
  759. {
  760. // Typecast the specified notification structure
  761. TV_KEYDOWN* pTVKD = reinterpret_cast<TV_KEYDOWN*>(pNMHDR);
  762. // Check for alphanum key
  763. if (isalnum(pTVKD->wVKey))
  764. {
  765. // Check for check-box accelerator keys
  766. if ('e' == pTVKD->wVKey || 'E' == pTVKD->wVKey)
  767. ToggleCheckBox(IDC_LOG2NT);
  768. if ('d' == pTVKD->wVKey || 'D' == pTVKD->wVKey)
  769. ToggleCheckBox(IDC_LOG2DB);
  770. // Exclude the key from further processing
  771. *pResult = true;
  772. return;
  773. }
  774. // Clear the result
  775. *pResult = 0;
  776. }
  777. void CPropEvents::OnSelChangedEvents(NMHDR* pNMHDR, LRESULT* pResult)
  778. {
  779. // Typecast the specified notification structure
  780. NM_TREEVIEW* pNMTV = reinterpret_cast<NM_TREEVIEW*>(pNMHDR);
  781. // Save any changes made to the previously-selected node's attributes
  782. UpdateNodeFromItem(pNMTV->itemOld.lParam);
  783. // Update the controls from the newly-selected node
  784. m_lParamSelected = pNMTV->itemNew.lParam;
  785. UpdateItemFromNode(pNMTV->itemNew.lParam);
  786. // Clear the result
  787. *pResult = 0;
  788. }
  789. void CPropEvents::OnByGroup()
  790. {
  791. // Do nothing if tree view is already visible
  792. if (GetDlgItem(IDC_EVENTS)->IsWindowVisible())
  793. return;
  794. // TODO: Add your control notification handler code here
  795. // TODO: Select the currently selected list item in the tree
  796. // Hide the list control and show the tree control
  797. GetDlgItem(IDC_EVENTS_LIST)->ShowWindow(SW_HIDE);
  798. GetDlgItem(IDC_EVENTS )->ShowWindow(SW_SHOW);
  799. }
  800. void CPropEvents::OnFlatList()
  801. {
  802. // Do nothing if list view is already visible
  803. if (GetDlgItem(IDC_EVENTS_LIST)->IsWindowVisible())
  804. return;
  805. // Save any changes made to the currently-selected node's attributes
  806. UpdateNodeFromItem(m_lParamSelected);
  807. // TODO: Select the currently selected tree item in the list
  808. // Hide the tree control and show the list control
  809. GetDlgItem(IDC_EVENTS )->ShowWindow(SW_HIDE);
  810. GetDlgItem(IDC_EVENTS_LIST)->ShowWindow(SW_SHOW);
  811. }
  812. void CPropEvents::OnDeleteItemEventsList(NMHDR* pNMHDR, LRESULT* pResult)
  813. {
  814. // Typecast the specified notification structure
  815. NM_LISTVIEW* pLV = reinterpret_cast<NM_LISTVIEW*>(pNMHDR);
  816. // Typecast the item's param as an XML element pointer
  817. IXMLDOMElement* pElement =
  818. reinterpret_cast<IXMLDOMElement*>(pLV->lParam);
  819. // Release the XML element pointer associated with the item
  820. if (pElement)
  821. pElement->Release();
  822. // Clear the result
  823. *pResult = 0;
  824. }
  825. void CPropEvents::OnColumnClickEventsList(NMHDR* pNMHDR, LRESULT* pResult)
  826. {
  827. // Typecast the specified notification structure
  828. NM_LISTVIEW* pLV = reinterpret_cast<NM_LISTVIEW*>(pNMHDR);
  829. // Reverse the sort order if column is the same as current sort column
  830. if (pLV->iSubItem == m_nSortColumn)
  831. m_nSortDirection *= -1;
  832. else
  833. m_nSortDirection = 1;
  834. // Save the new sort order
  835. m_nSortColumn = pLV->iSubItem;
  836. // Sort the items in the list
  837. m_listEvents.SortItems(SortProcFromColumn(m_nSortColumn),
  838. reinterpret_cast<DWORD>(this));
  839. // Clear the result
  840. *pResult = 0;
  841. }