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.

493 lines
14 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright: Microsoft Corp. 1997-1999. All rights reserved
  4. //
  5. /////////////////////////////////////////////////////////////////////////////
  6. // Event.cpp : Implementation of CEvent
  7. #include "stdafx.h"
  8. #include "Evntutl.h"
  9. #include "Event.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CEvent
  12. STDMETHODIMP CEvent::InterfaceSupportsErrorInfo(REFIID riid)
  13. {
  14. static const IID* arr[] =
  15. {
  16. &IID_IEvent
  17. };
  18. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  19. {
  20. if (InlineIsEqualGUID(*arr[i],riid))
  21. return S_OK;
  22. }
  23. return S_FALSE;
  24. }
  25. /*
  26. Function: get_Server
  27. Inputs: empty BSTR
  28. Outputs: BSTR containing the Description for the Event (calculated)
  29. Purpose: Allows user to access the description for an Event
  30. */
  31. STDMETHODIMP CEvent::get_Description(BSTR *pVal)
  32. {
  33. HRESULT hr = S_OK;
  34. unsigned int i;
  35. if (pVal)
  36. {
  37. if (m_Description.length() == 0)
  38. {
  39. hr = CheckDefaultDescription(m_ppArgList);
  40. if (SUCCEEDED(hr)) *pVal = m_Description.copy();
  41. if (m_ppArgList)
  42. {
  43. // delete the ArgList
  44. for (i=0;i<m_NumberOfStrings;i++)
  45. delete [] m_ppArgList[i];
  46. delete []m_ppArgList;
  47. m_ppArgList = NULL;
  48. }
  49. }
  50. }
  51. else hr = E_POINTER;
  52. return hr;
  53. }
  54. /*
  55. Function: get_Source
  56. Inputs: empty BSTR
  57. Outputs: BSTR containing the name of the component which caused the Event
  58. Purpose: Allows user to access the name of the component which caused the Event
  59. */
  60. STDMETHODIMP CEvent::get_Source(BSTR *pVal)
  61. {
  62. HRESULT hr = S_OK;
  63. if (pVal) *pVal = m_SourceName.copy();
  64. else hr = E_POINTER;
  65. return hr;
  66. }
  67. /*
  68. Function: get_User
  69. Inputs: empty BSTR
  70. Outputs: BSTR containing the name and domain of the user who caused the Event
  71. Purpose: Allows user to access the name and domain of the user who caused the Event
  72. Notes: The first time this function is called, it will do a SID lookup
  73. */
  74. STDMETHODIMP CEvent::get_User(BSTR *pVal)
  75. {
  76. HRESULT hr = S_OK;
  77. if (pVal)
  78. {
  79. if (m_UserName.length() == 0)
  80. {
  81. SetUser();
  82. }
  83. *pVal = m_UserName.copy();
  84. }
  85. else hr = E_POINTER;
  86. return hr;
  87. }
  88. /*
  89. Function: get_ComputerName
  90. Inputs: empty BSTR
  91. Outputs: BSTR containing the name of the server on which the Event occured
  92. Purpose: Allows user to access the name of the the server on which the Event occured
  93. */
  94. STDMETHODIMP CEvent::get_ComputerName(BSTR *pVal)
  95. {
  96. HRESULT hr = S_OK;
  97. if (pVal) *pVal = m_ComputerName.copy();
  98. else hr = E_POINTER;
  99. return hr;
  100. }
  101. /*
  102. Function: get_EventID
  103. Inputs: empty long
  104. Outputs: long containing the ID of the Event
  105. Purpose: Allows user to access the ID which can be used to lookup a message for the event
  106. Notes: Since description is provided, this function is not very useful, however,
  107. it is provided for completeness
  108. */
  109. STDMETHODIMP CEvent::get_EventID(long *pVal)
  110. {
  111. HRESULT hr = S_OK;
  112. // m_EventID = m_EventID & 0xFFFF; // The EventLog viewer uses this mask before displaying ID's
  113. if (pVal) *pVal = m_EventID;
  114. else hr = E_POINTER;
  115. return hr;
  116. }
  117. /*
  118. Function: get_Category
  119. Inputs: empty long
  120. Outputs: long containing the category ID for the event
  121. Purpose: Allows user to access the category ID for the event
  122. */
  123. STDMETHODIMP CEvent::get_Category(long *pVal)
  124. {
  125. HRESULT hr = S_OK;
  126. if (pVal) *pVal = m_EventCategory;
  127. else hr = E_POINTER;
  128. return hr;
  129. }
  130. /*
  131. Function: get_EventType
  132. Inputs: empty enumeration
  133. Outputs: enumeration containing the type of event that occured
  134. Purpose: Allows user to access the type of event that occured
  135. */
  136. STDMETHODIMP CEvent::get_EventType(eEventType *pVal)
  137. {
  138. HRESULT hr = S_OK;
  139. if (pVal) *pVal = m_EventType;
  140. else hr = E_POINTER;
  141. return hr;
  142. }
  143. /*
  144. Function: get_OccurenceTime
  145. Inputs: empty DATE structure
  146. Outputs: DATE structure containing the local system time when the event occured
  147. Purpose: Allows user to access the time when the event occured
  148. */
  149. STDMETHODIMP CEvent::get_OccurrenceTime(DATE *pVal)
  150. {
  151. HRESULT hr = S_OK;
  152. if (pVal) *pVal = m_OccurrenceTime;
  153. else hr = E_POINTER;
  154. return hr;
  155. }
  156. /*
  157. Function: get_Data
  158. Inputs: empty variant
  159. Outputs: variant containing an array of bytes
  160. Purpose: Allows user to access the data set by the event. This may or may not be set,
  161. and is frequently not useful
  162. */
  163. STDMETHODIMP CEvent::get_Data(VARIANT *pVal)
  164. {
  165. HRESULT hr = S_OK;
  166. if (pVal)
  167. {
  168. pVal->vt = VT_ARRAY | VT_UI1;
  169. pVal->parray = m_pDataArray;
  170. }
  171. else hr = E_POINTER;
  172. return hr;
  173. }
  174. /*
  175. Function: Init
  176. Inputs: pointer to an EVENTLOGRECORD structure
  177. Outputs: does not modify input
  178. Purpose: fill Event object properties which do not require loading external libs
  179. */
  180. HRESULT CEvent::Init(EVENTLOGRECORD* pEventStructure, const LPCTSTR szEventLogName)
  181. {
  182. HRESULT hr = S_OK;
  183. m_EventLogName = szEventLogName;
  184. hr = ParseEventBlob(pEventStructure);
  185. return hr;
  186. }
  187. /*
  188. Function: ParseEventBlob
  189. Inputs: pointer to an EVENTLOGRECORD structure
  190. Outputs: does not modify input
  191. Purpose: Parse an EVENTLOGRECORD and set the appropriate internal structures of Event
  192. */
  193. HRESULT CEvent::ParseEventBlob(EVENTLOGRECORD* pEventStructure)
  194. {
  195. HRESULT hr = S_OK;
  196. wchar_t* wTempString;
  197. BYTE* pSourceName;
  198. BYTE* pComputerName;
  199. SAFEARRAYBOUND rgsabound[1];
  200. ULONG StringsToRetrieve = 0, CharsRead = 0, i = 0;
  201. long Index[1];
  202. BYTE pTemp;
  203. m_EventID = pEventStructure->EventID;
  204. m_EventCategory = pEventStructure->EventCategory;
  205. switch (pEventStructure->EventType)
  206. {
  207. case EVENTLOG_ERROR_TYPE:
  208. m_EventType = ErrorEvent;
  209. break;
  210. case EVENTLOG_WARNING_TYPE:
  211. m_EventType = WarningEvent;
  212. break;
  213. case EVENTLOG_INFORMATION_TYPE:
  214. m_EventType = InformationEvent;
  215. break;
  216. case EVENTLOG_AUDIT_SUCCESS:
  217. m_EventType = AuditSuccess;
  218. break;
  219. case EVENTLOG_AUDIT_FAILURE:
  220. m_EventType = AuditFailure;
  221. break;
  222. default:
  223. hr = E_FAIL;
  224. }
  225. // parse strings from the memory blob
  226. // Set source name
  227. pSourceName = (BYTE*) &(pEventStructure->DataOffset) + sizeof(pEventStructure->DataOffset);
  228. wTempString = (wchar_t*)pSourceName;
  229. m_SourceName = wTempString;
  230. // Set computer name
  231. pComputerName = (BYTE*)pSourceName + ((wcslen(wTempString)+1) * sizeof(wchar_t));
  232. wTempString = (wchar_t*)pComputerName;
  233. m_ComputerName = wTempString;
  234. // Set SID
  235. if ((pEventStructure->StringOffset - pEventStructure->UserSidOffset) != 0)
  236. {
  237. m_pSid = new BYTE[pEventStructure->UserSidLength]; // scope = CEvent, deleted in ~CEvent() or SetSID() whichever comes first
  238. if (m_pSid != NULL) {
  239. for (i = 0; i<pEventStructure->UserSidLength; i++)
  240. m_pSid[i] = (BYTE)(*((BYTE*)pEventStructure + pEventStructure->UserSidOffset + i * sizeof(BYTE)));
  241. }
  242. }
  243. // Set Occurence time
  244. // this code is copied from MSDN
  245. FILETIME FileTime, LocalFileTime;
  246. SYSTEMTIME SysTime;
  247. __int64 lgTemp;
  248. __int64 SecsTo1970 = 116444736000000000;
  249. lgTemp = Int32x32To64(pEventStructure->TimeGenerated,10000000) + SecsTo1970;
  250. FileTime.dwLowDateTime = (DWORD) lgTemp;
  251. FileTime.dwHighDateTime = (DWORD)(lgTemp >> 32);
  252. FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
  253. FileTimeToSystemTime(&LocalFileTime, &SysTime);
  254. if(!SystemTimeToVariantTime(&SysTime, &m_OccurrenceTime)) hr = GetLastError();
  255. // Set Data (create and fill a SafeArray)
  256. if (pEventStructure->DataLength>0)
  257. {
  258. rgsabound[0].lLbound = 0;
  259. rgsabound[0].cElements = pEventStructure->DataLength;
  260. m_pDataArray = SafeArrayCreate(VT_UI1, 1, rgsabound);
  261. for (i=0;i<pEventStructure->DataLength;i++)
  262. {
  263. Index[0] = i;
  264. pTemp = (BYTE) (pEventStructure->DataOffset + i * sizeof(BYTE));
  265. hr = SafeArrayPutElement(m_pDataArray, Index, &pTemp);
  266. if (FAILED(hr)) i = pEventStructure->DataLength;
  267. }
  268. }
  269. // Set the description
  270. m_Description = "";
  271. if (m_SourceName.length() != 0)
  272. {
  273. // prepare the ArgList
  274. m_NumberOfStrings = pEventStructure->NumStrings;
  275. m_ppArgList = new wchar_t*[m_NumberOfStrings]; // scope = CEvent, deleted when ~CEvent or get_Description is called whichever is first
  276. for (i=0;i<m_NumberOfStrings;i++)
  277. m_ppArgList[i] = new wchar_t[(pEventStructure->DataOffset - pEventStructure->StringOffset)]; // can't be larger than the length of all the strings we got
  278. for (i=0;i<m_NumberOfStrings;i++)
  279. {
  280. wTempString = (wchar_t*) (((BYTE*)(pEventStructure)) + pEventStructure->StringOffset + CharsRead * sizeof(wchar_t));
  281. wcscpy(m_ppArgList[i], wTempString);
  282. CharsRead = CharsRead + wcslen(wTempString) + 1; // + 1 for the null
  283. }
  284. }
  285. else // if there is no module to load a default description, just put all the string args in the description
  286. {
  287. StringsToRetrieve = pEventStructure->NumStrings;
  288. while (StringsToRetrieve > 0)
  289. {
  290. wTempString = (wchar_t*) (((BYTE*)(pEventStructure)) + pEventStructure->StringOffset + CharsRead * sizeof(wchar_t));
  291. m_Description = m_Description + " " + wTempString;
  292. CharsRead = CharsRead + wcslen(wTempString) + 1; // + 1 for the null
  293. StringsToRetrieve--;
  294. }
  295. }
  296. return hr;
  297. }
  298. /*
  299. Function: CheckDefaultDescription
  300. Inputs: pointer pointer to a wide character
  301. Outputs: does not modify input
  302. Purpose: format a message from an EventID, set of input strings, and a source module
  303. */
  304. HRESULT CEvent::CheckDefaultDescription(wchar_t** Arguments)
  305. {
  306. HRESULT hr = S_OK;
  307. BYTE* wMessagePath = NULL;
  308. ULONG BufferSize = 40000;
  309. ULONG* lPathLength = NULL;
  310. wchar_t* wOrigionalPath = NULL;
  311. wchar_t* wExpandedPath = NULL;
  312. wchar_t* pBuffer = NULL;
  313. _bstr_t btRegKey;
  314. _bstr_t btTempString;
  315. HMODULE hiLib;
  316. HKEY hKey;
  317. try{
  318. lPathLength = new ULONG;
  319. if (lPathLength)
  320. {
  321. *lPathLength = 256*2;
  322. wMessagePath = new BYTE[*lPathLength];
  323. if (wMessagePath)
  324. {
  325. // get registry value for Source module path
  326. btRegKey = "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\" + m_EventLogName;
  327. btRegKey = btRegKey + "\\";
  328. btRegKey = btRegKey + m_SourceName;
  329. hr = RegOpenKey(HKEY_LOCAL_MACHINE, btRegKey, &hKey);
  330. if (hKey)
  331. {
  332. hr = RegQueryValueEx(hKey, L"EventMessageFile", NULL, NULL, wMessagePath, lPathLength);
  333. if (hr == 0)
  334. {
  335. wOrigionalPath = (wchar_t*) wMessagePath;
  336. wExpandedPath = new wchar_t[(int)*lPathLength];
  337. if (wExpandedPath)
  338. {
  339. ExpandEnvironmentStrings(wOrigionalPath, wExpandedPath, *lPathLength);
  340. btTempString = wExpandedPath;
  341. // open the Source module
  342. hiLib = LoadLibraryEx(btTempString, NULL, LOAD_LIBRARY_AS_DATAFILE);
  343. hr = GetLastError();
  344. if (hiLib)
  345. {
  346. pBuffer = new wchar_t[BufferSize];
  347. if (pBuffer)
  348. {
  349. SetLastError(0);
  350. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM |
  351. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  352. hiLib, m_EventID, 0, pBuffer, BufferSize,
  353. reinterpret_cast<va_list*>(Arguments));
  354. hr = HRESULT_FROM_WIN32(GetLastError());
  355. m_Description = m_Description + pBuffer;
  356. delete []pBuffer;
  357. pBuffer = NULL;
  358. }
  359. else hr = E_OUTOFMEMORY;
  360. FreeLibrary(hiLib);
  361. }
  362. delete [] wExpandedPath;
  363. wExpandedPath = NULL;
  364. }
  365. else hr = E_OUTOFMEMORY;
  366. }
  367. else hr = HRESULT_FROM_WIN32(hr);
  368. RegCloseKey(hKey);
  369. }
  370. else hr = HRESULT_FROM_WIN32(hr);
  371. delete []wMessagePath;
  372. wMessagePath = NULL;
  373. }
  374. else hr = E_OUTOFMEMORY;
  375. delete lPathLength;
  376. lPathLength = NULL;
  377. }
  378. else hr = E_OUTOFMEMORY;
  379. } catch(...){
  380. if (lPathLength != NULL) {
  381. delete lPathLength;
  382. }
  383. if (wMessagePath != NULL) {
  384. delete []wMessagePath;
  385. }
  386. if (wExpandedPath != NULL) {
  387. delete [] wExpandedPath;
  388. }
  389. if (pBuffer != NULL) {
  390. delete []pBuffer;
  391. }
  392. }
  393. return hr;
  394. }
  395. /*
  396. Function: SetUser
  397. Inputs: none
  398. Outputs: HRESULT indicating what error if any occured
  399. Purpose: finds alias and domain for a given SID
  400. */
  401. HRESULT CEvent::SetUser()
  402. {
  403. HRESULT hr = S_OK;
  404. SID_NAME_USE SidNameUse;
  405. wchar_t* wUserName;
  406. wchar_t* wDomainName;
  407. SID* pSid;
  408. unsigned long UserNameLength = 256;
  409. // Set user name and sid
  410. if (m_pSid !=NULL)
  411. {
  412. pSid = (SID*)m_pSid;
  413. wUserName = new wchar_t[UserNameLength];
  414. if (wUserName)
  415. {
  416. wDomainName = new wchar_t[UserNameLength];
  417. if (wDomainName)
  418. {
  419. m_UserName = "";
  420. if (LookupAccountSid(NULL, pSid, wUserName, &UserNameLength, wDomainName,
  421. &UserNameLength, &SidNameUse))
  422. m_UserName = m_UserName + wDomainName + L"\\" + wUserName;
  423. else hr = HRESULT_FROM_WIN32(GetLastError());
  424. delete []wDomainName;
  425. }
  426. else hr = E_OUTOFMEMORY;
  427. delete []wUserName;
  428. }
  429. else hr = E_OUTOFMEMORY;
  430. delete []m_pSid;
  431. m_pSid = NULL;
  432. }
  433. return hr;
  434. }