[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / System / System.Diagnostics / Win32EventLog.cs
blobb5ca3ec090f5174d74961cb01758ad2b0c9d10b4
1 //
2 // System.Diagnostics.Win32EventLog.cs
3 //
4 // Author:
5 // Gert Driesen <driesen@users.sourceforge.net>
6 //
7 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
8 //
9 //
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Collections.Generic;
31 using System.ComponentModel;
32 using System.Diagnostics;
33 using System.Globalization;
34 using System.IO;
35 using System.Runtime.InteropServices;
36 using System.Text;
37 using System.Threading;
39 using Microsoft.Win32;
41 namespace System.Diagnostics
43 internal class Win32EventLog : EventLogImpl
45 private const int MESSAGE_NOT_FOUND = 317;
46 private ManualResetEvent _notifyResetEvent;
47 private IntPtr _readHandle;
48 private Thread _notifyThread;
49 private int _lastEntryWritten;
50 private Object _eventLock = new object();
52 public Win32EventLog (EventLog coreEventLog)
53 : base (coreEventLog)
57 public override void BeginInit ()
61 public override void Clear ()
63 int ret = PInvoke.ClearEventLog (ReadHandle, null);
64 if (ret != 1)
65 throw new Win32Exception (Marshal.GetLastWin32Error ());
68 public override void Close ()
70 lock (_eventLock) {
71 if (_readHandle != IntPtr.Zero) {
72 CloseEventLog (_readHandle);
73 _readHandle = IntPtr.Zero;
78 public override void CreateEventSource (EventSourceCreationData sourceData)
80 using (RegistryKey eventLogKey = GetEventLogKey (sourceData.MachineName, true)) {
81 if (eventLogKey == null)
82 throw new InvalidOperationException ("EventLog registry key is missing.");
84 bool logKeyCreated = false;
85 RegistryKey logKey = null;
86 try {
87 logKey = eventLogKey.OpenSubKey (sourceData.LogName, true);
88 if (logKey == null) {
89 ValidateCustomerLogName (sourceData.LogName,
90 sourceData.MachineName);
92 logKey = eventLogKey.CreateSubKey (sourceData.LogName);
93 logKey.SetValue ("Sources", new string [] { sourceData.LogName,
94 sourceData.Source });
95 UpdateLogRegistry (logKey);
97 using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.LogName)) {
98 UpdateSourceRegistry (sourceKey, sourceData);
101 logKeyCreated = true;
104 if (sourceData.LogName != sourceData.Source) {
105 if (!logKeyCreated) {
106 string [] sources = (string []) logKey.GetValue ("Sources");
107 if (sources == null) {
108 logKey.SetValue ("Sources", new string [] { sourceData.LogName,
109 sourceData.Source });
110 } else {
111 bool found = false;
112 for (int i = 0; i < sources.Length; i++) {
113 if (sources [i] == sourceData.Source) {
114 found = true;
115 break;
118 if (!found) {
119 string [] newSources = new string [sources.Length + 1];
120 Array.Copy (sources, 0, newSources, 0, sources.Length);
121 newSources [sources.Length] = sourceData.Source;
122 logKey.SetValue ("Sources", newSources);
126 using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.Source)) {
127 UpdateSourceRegistry (sourceKey, sourceData);
130 } finally {
131 if (logKey != null)
132 logKey.Close ();
137 public override void Delete (string logName, string machineName)
139 using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
140 if (eventLogKey == null)
141 throw new InvalidOperationException ("The event log key does not exist.");
143 using (RegistryKey logKey = eventLogKey.OpenSubKey (logName, false)) {
144 if (logKey == null)
145 throw new InvalidOperationException (string.Format (
146 CultureInfo.InvariantCulture, "Event Log '{0}'"
147 + " does not exist on computer '{1}'.", logName,
148 machineName));
150 // remove all eventlog entries for specified log
151 CoreEventLog.Clear ();
153 // remove file holding event log entries
154 string file = (string) logKey.GetValue ("File");
155 if (file != null) {
156 try {
157 File.Delete (file);
158 } catch (Exception) {
159 // .NET seems to ignore failures here
164 eventLogKey.DeleteSubKeyTree (logName);
168 public override void DeleteEventSource (string source, string machineName)
170 using (RegistryKey logKey = FindLogKeyBySource (source, machineName, true)) {
171 if (logKey == null) {
172 throw new ArgumentException (string.Format (
173 CultureInfo.InvariantCulture, "The source '{0}' is not"
174 + " registered on computer '{1}'.", source, machineName));
177 logKey.DeleteSubKeyTree (source);
179 string [] sources = (string []) logKey.GetValue ("Sources");
180 if (sources != null) {
181 var temp = new List<string> ();
182 for (int i = 0; i < sources.Length; i++)
183 if (sources [i] != source)
184 temp.Add (sources [i]);
185 string [] newSources = temp.ToArray ();
186 logKey.SetValue ("Sources", newSources);
191 public override void Dispose (bool disposing)
193 Close ();
196 public override void EndInit ()
200 public override bool Exists (string logName, string machineName)
202 using (RegistryKey logKey = FindLogKeyByName (logName, machineName, false)) {
203 return (logKey != null);
207 [MonoTODO] // ParameterResourceFile ??
208 protected override string FormatMessage (string source, uint messageID, string [] replacementStrings)
210 string formattedMessage = null;
212 string [] msgResDlls = GetMessageResourceDlls (source, "EventMessageFile");
213 for (int i = 0; i < msgResDlls.Length; i++) {
214 formattedMessage = FetchMessage (msgResDlls [i],
215 messageID, replacementStrings);
216 if (formattedMessage != null)
217 break;
220 return formattedMessage != null ? formattedMessage : string.Join (
221 ", ", replacementStrings);
224 private string FormatCategory (string source, int category)
226 string formattedCategory = null;
228 string [] msgResDlls = GetMessageResourceDlls (source, "CategoryMessageFile");
229 for (int i = 0; i < msgResDlls.Length; i++) {
230 formattedCategory = FetchMessage (msgResDlls [i],
231 (uint) category, new string [0]);
232 if (formattedCategory != null)
233 break;
236 return formattedCategory != null ? formattedCategory : "(" +
237 category.ToString (CultureInfo.InvariantCulture) + ")";
240 protected override int GetEntryCount ()
242 int entryCount = 0;
243 int retVal = PInvoke.GetNumberOfEventLogRecords (ReadHandle, ref entryCount);
244 if (retVal != 1)
245 throw new Win32Exception (Marshal.GetLastWin32Error ());
246 return entryCount;
249 protected override EventLogEntry GetEntry (int index)
251 // http://msdn.microsoft.com/library/en-us/eventlog/base/readeventlog.asp
252 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp
253 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html
255 index += OldestEventLogEntry;
257 int bytesRead = 0;
258 int minBufferNeeded = 0;
259 byte [] buffer = new byte [0x7ffff]; // according to MSDN this is the max size of the buffer
261 ReadEventLog (index, buffer, ref bytesRead, ref minBufferNeeded);
263 MemoryStream ms = new MemoryStream (buffer);
264 BinaryReader br = new BinaryReader (ms, Encoding.Unicode);
266 // skip first 8 bytes
267 br.ReadBytes (8);
269 int recordNumber = br.ReadInt32 (); // 8
271 int timeGeneratedSeconds = br.ReadInt32 (); // 12
272 int timeWrittenSeconds = br.ReadInt32 (); // 16
273 uint instanceID = br.ReadUInt32 ();
274 int eventID = EventLog.GetEventID (instanceID);
275 short eventType = br.ReadInt16 (); // 24
276 short numStrings = br.ReadInt16 (); ; // 26
277 short categoryNumber = br.ReadInt16 (); ; // 28
278 // skip reservedFlags
279 br.ReadInt16 (); // 30
280 // skip closingRecordNumber
281 br.ReadInt32 (); // 32
282 int stringOffset = br.ReadInt32 (); // 36
283 int userSidLength = br.ReadInt32 (); // 40
284 int userSidOffset = br.ReadInt32 (); // 44
285 int dataLength = br.ReadInt32 (); // 48
286 int dataOffset = br.ReadInt32 (); // 52
288 DateTime timeGenerated = new DateTime (1970, 1, 1).AddSeconds (
289 timeGeneratedSeconds);
291 DateTime timeWritten = new DateTime (1970, 1, 1).AddSeconds (
292 timeWrittenSeconds);
294 StringBuilder sb = new StringBuilder ();
295 while (br.PeekChar () != '\0')
296 sb.Append (br.ReadChar ());
297 br.ReadChar (); // skip the null-char
299 string sourceName = sb.ToString ();
301 sb.Length = 0;
302 while (br.PeekChar () != '\0')
303 sb.Append (br.ReadChar ());
304 br.ReadChar (); // skip the null-char
305 string machineName = sb.ToString ();
307 sb.Length = 0;
308 while (br.PeekChar () != '\0')
309 sb.Append (br.ReadChar ());
310 br.ReadChar (); // skip the null-char
312 string userName = null;
313 if (userSidLength != 0) {
314 // TODO: lazy init ?
315 ms.Position = userSidOffset;
316 byte [] sid = br.ReadBytes (userSidLength);
317 userName = LookupAccountSid (machineName, sid);
320 ms.Position = stringOffset;
321 string [] replacementStrings = new string [numStrings];
322 for (int i = 0; i < numStrings; i++) {
323 sb.Length = 0;
324 while (br.PeekChar () != '\0')
325 sb.Append (br.ReadChar ());
326 br.ReadChar (); // skip the null-char
327 replacementStrings [i] = sb.ToString ();
330 byte [] data = new byte [dataLength];
331 ms.Position = dataOffset;
332 br.Read (data, 0, dataLength);
334 // TODO: lazy fetch ??
335 string message = this.FormatMessage (sourceName, instanceID, replacementStrings);
336 string category = FormatCategory (sourceName, categoryNumber);
338 return new EventLogEntry (category, (short) categoryNumber, recordNumber,
339 eventID, sourceName, message, userName, machineName,
340 (EventLogEntryType) eventType, timeGenerated, timeWritten,
341 data, replacementStrings, instanceID);
344 [MonoTODO]
345 protected override string GetLogDisplayName ()
347 return CoreEventLog.Log;
350 protected override string [] GetLogNames (string machineName)
352 using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
353 if (eventLogKey == null)
354 return new string [0];
356 return eventLogKey.GetSubKeyNames ();
360 public override string LogNameFromSourceName (string source, string machineName)
362 using (RegistryKey logKey = FindLogKeyBySource (source, machineName, false)) {
363 if (logKey == null)
364 return string.Empty;
366 return GetLogName (logKey);
370 public override bool SourceExists (string source, string machineName)
372 RegistryKey logKey = FindLogKeyBySource (source, machineName, false);
373 if (logKey != null) {
374 logKey.Close ();
375 return true;
377 return false;
380 public override void WriteEntry (string [] replacementStrings, EventLogEntryType type, uint instanceID, short category, byte [] rawData)
382 IntPtr hEventLog = RegisterEventSource ();
383 try {
384 int ret = PInvoke.ReportEvent (hEventLog, (ushort) type,
385 (ushort) category, instanceID, IntPtr.Zero,
386 (ushort) replacementStrings.Length,
387 (uint) rawData.Length, replacementStrings, rawData);
388 if (ret != 1) {
389 throw new Win32Exception (Marshal.GetLastWin32Error ());
391 } finally {
392 DeregisterEventSource (hEventLog);
396 private static void UpdateLogRegistry (RegistryKey logKey)
398 // TODO: write other Log values:
399 // - MaxSize
400 // - Retention
401 // - AutoBackupLogFiles
403 if (logKey.GetValue ("File") == null) {
404 string logName = GetLogName (logKey);
405 string file;
406 if (logName.Length > 8) {
407 file = logName.Substring (0, 8) + ".evt";
408 } else {
409 file = logName + ".evt";
411 string configPath = Path.Combine (Environment.GetFolderPath (
412 Environment.SpecialFolder.System), "config");
413 logKey.SetValue ("File", Path.Combine (configPath, file));
417 private static void UpdateSourceRegistry (RegistryKey sourceKey, EventSourceCreationData data)
419 if (data.CategoryCount > 0)
420 sourceKey.SetValue ("CategoryCount", data.CategoryCount);
422 if (data.CategoryResourceFile != null && data.CategoryResourceFile.Length > 0)
423 sourceKey.SetValue ("CategoryMessageFile", data.CategoryResourceFile);
425 if (data.MessageResourceFile != null && data.MessageResourceFile.Length > 0) {
426 sourceKey.SetValue ("EventMessageFile", data.MessageResourceFile);
427 } else {
428 // FIXME: write default once we have approval for shipping EventLogMessages.dll
431 if (data.ParameterResourceFile != null && data.ParameterResourceFile.Length > 0)
432 sourceKey.SetValue ("ParameterMessageFile", data.ParameterResourceFile);
435 private static string GetLogName (RegistryKey logKey)
437 string logName = logKey.Name;
438 return logName.Substring (logName.LastIndexOf ("\\") + 1);
441 private void ReadEventLog (int index, byte [] buffer, ref int bytesRead, ref int minBufferNeeded)
443 const int max_retries = 3;
445 // if the eventlog file changed since the handle was
446 // obtained, then we need to re-try multiple times
447 for (int i = 0; i < max_retries; i++) {
448 int ret = PInvoke.ReadEventLog (ReadHandle,
449 ReadFlags.Seek | ReadFlags.ForwardsRead,
450 index, buffer, buffer.Length, ref bytesRead,
451 ref minBufferNeeded);
452 if (ret != 1) {
453 int error = Marshal.GetLastWin32Error ();
454 if (i < (max_retries - 1)) {
455 CoreEventLog.Reset ();
456 } else {
457 throw new Win32Exception (error);
464 [MonoTODO ("Support remote machines")]
465 private static RegistryKey GetEventLogKey (string machineName, bool writable)
467 return Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Services\EventLog", writable);
470 private static RegistryKey FindSourceKeyByName (string source, string machineName, bool writable)
472 if (source == null || source.Length == 0)
473 return null;
475 RegistryKey eventLogKey = null;
476 try {
477 eventLogKey = GetEventLogKey (machineName, writable);
478 if (eventLogKey == null)
479 return null;
481 string [] subKeys = eventLogKey.GetSubKeyNames ();
482 for (int i = 0; i < subKeys.Length; i++) {
483 using (RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable)) {
484 if (logKey == null)
485 break;
487 RegistryKey sourceKey = logKey.OpenSubKey (source, writable);
488 if (sourceKey != null)
489 return sourceKey;
492 return null;
493 } finally {
494 if (eventLogKey != null)
495 eventLogKey.Close ();
499 private static RegistryKey FindLogKeyByName (string logName, string machineName, bool writable)
501 using (RegistryKey eventLogKey = GetEventLogKey (machineName, writable)) {
502 if (eventLogKey == null) {
503 return null;
506 return eventLogKey.OpenSubKey (logName, writable);
510 private static RegistryKey FindLogKeyBySource (string source, string machineName, bool writable)
512 if (source == null || source.Length == 0)
513 return null;
515 RegistryKey eventLogKey = null;
516 try {
517 eventLogKey = GetEventLogKey (machineName, writable);
518 if (eventLogKey == null)
519 return null;
521 string [] subKeys = eventLogKey.GetSubKeyNames ();
522 for (int i = 0; i < subKeys.Length; i++) {
523 RegistryKey sourceKey = null;
524 try {
525 RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable);
526 if (logKey != null) {
527 sourceKey = logKey.OpenSubKey (source, writable);
528 if (sourceKey != null)
529 return logKey;
531 } finally {
532 if (sourceKey != null)
533 sourceKey.Close ();
536 return null;
537 } finally {
538 if (eventLogKey != null)
539 eventLogKey.Close ();
543 private int OldestEventLogEntry {
544 get {
545 int oldestEventLogEntry = 0;
546 int ret = PInvoke.GetOldestEventLogRecord (ReadHandle, ref oldestEventLogEntry);
547 if (ret != 1) {
548 throw new Win32Exception (Marshal.GetLastWin32Error ());
550 return oldestEventLogEntry;
554 private void CloseEventLog (IntPtr hEventLog)
556 int ret = PInvoke.CloseEventLog (hEventLog);
557 if (ret != 1) {
558 throw new Win32Exception (Marshal.GetLastWin32Error ());
562 private void DeregisterEventSource (IntPtr hEventLog)
564 int ret = PInvoke.DeregisterEventSource (hEventLog);
565 if (ret != 1) {
566 throw new Win32Exception (Marshal.GetLastWin32Error ());
570 private static string LookupAccountSid (string machineName, byte [] sid)
572 // http://www.pinvoke.net/default.aspx/advapi32/LookupAccountSid.html
573 // http://msdn.microsoft.com/library/en-us/secauthz/security/lookupaccountsid.asp
575 StringBuilder name = new StringBuilder ();
576 uint cchName = (uint) name.Capacity;
577 StringBuilder referencedDomainName = new StringBuilder ();
578 uint cchReferencedDomainName = (uint) referencedDomainName.Capacity;
579 SidNameUse sidUse;
581 string accountName = null;
583 while (accountName == null) {
584 bool retOk = PInvoke.LookupAccountSid (machineName, sid, name, ref cchName,
585 referencedDomainName, ref cchReferencedDomainName,
586 out sidUse);
587 if (!retOk) {
588 int err = Marshal.GetLastWin32Error ();
589 if (err == PInvoke.ERROR_INSUFFICIENT_BUFFER) {
590 name.EnsureCapacity ((int) cchName);
591 referencedDomainName.EnsureCapacity ((int) cchReferencedDomainName);
592 } else {
593 // TODO: write warning ?
594 accountName = string.Empty;
596 } else {
597 accountName = string.Format ("{0}\\{1}", referencedDomainName.ToString (),
598 name.ToString ());
601 return accountName;
604 private static string FetchMessage (string msgDll, uint messageID, string [] replacementStrings)
606 // http://msdn.microsoft.com/library/en-us/debug/base/formatmessage.asp
607 // http://msdn.microsoft.com/msdnmag/issues/02/08/CQA/
608 // http://msdn.microsoft.com/netframework/programming/netcf/cffaq/default.aspx
610 IntPtr msgDllHandle = PInvoke.LoadLibraryEx (msgDll, IntPtr.Zero,
611 LoadFlags.LibraryAsDataFile);
612 if (msgDllHandle == IntPtr.Zero)
613 // TODO: write warning
614 return null;
616 IntPtr lpMsgBuf = IntPtr.Zero;
617 IntPtr [] arguments = new IntPtr [replacementStrings.Length];
619 try {
620 for (int i = 0; i < replacementStrings.Length; i++) {
621 arguments [i] = Marshal.StringToHGlobalAuto (
622 replacementStrings [i]);
625 int ret = PInvoke.FormatMessage (FormatMessageFlags.ArgumentArray |
626 FormatMessageFlags.FromHModule | FormatMessageFlags.AllocateBuffer,
627 msgDllHandle, messageID, 0, ref lpMsgBuf, 0, arguments);
628 if (ret != 0) {
629 string sRet = Marshal.PtrToStringAuto (lpMsgBuf);
630 lpMsgBuf = PInvoke.LocalFree (lpMsgBuf);
631 // remove trailing whitespace (CRLF)
632 return sRet.TrimEnd (null);
633 } else {
634 int err = Marshal.GetLastWin32Error ();
635 if (err == MESSAGE_NOT_FOUND) {
636 // do not consider this a failure (or even warning) as
637 // multiple message resource DLLs may have been configured
638 // and as such we just need to try the next library if
639 // the current one does not contain a message for this
640 // ID
641 } else {
642 // TODO: report warning
645 } finally {
646 // release unmanaged memory allocated for replacement strings
647 for (int i = 0; i < arguments.Length; i++) {
648 IntPtr argument = arguments [i];
649 if (argument != IntPtr.Zero)
650 Marshal.FreeHGlobal (argument);
653 PInvoke.FreeLibrary (msgDllHandle);
655 return null;
658 private string [] GetMessageResourceDlls (string source, string valueName)
660 // Some event sources (such as Userenv) have multiple message
661 // resource DLLs, delimited by a semicolon.
663 RegistryKey sourceKey = FindSourceKeyByName (source,
664 CoreEventLog.MachineName, false);
665 if (sourceKey != null) {
666 string value = sourceKey.GetValue (valueName) as string;
667 if (value != null) {
668 string [] msgResDlls = value.Split (';');
669 return msgResDlls;
672 return new string [0];
675 private IntPtr ReadHandle {
676 get {
677 if (_readHandle != IntPtr.Zero)
678 return _readHandle;
680 string logName = CoreEventLog.GetLogName ();
681 _readHandle = PInvoke.OpenEventLog (CoreEventLog.MachineName,
682 logName);
683 if (_readHandle == IntPtr.Zero)
684 throw new InvalidOperationException (string.Format (
685 CultureInfo.InvariantCulture, "Event Log '{0}' on computer"
686 + " '{1}' cannot be opened.", logName, CoreEventLog.MachineName),
687 new Win32Exception ());
688 return _readHandle;
692 private IntPtr RegisterEventSource ()
694 IntPtr hEventLog = PInvoke.RegisterEventSource (
695 CoreEventLog.MachineName, CoreEventLog.Source);
696 if (hEventLog == IntPtr.Zero) {
697 throw new InvalidOperationException (string.Format (
698 CultureInfo.InvariantCulture, "Event source '{0}' on computer"
699 + " '{1}' cannot be opened.", CoreEventLog.Source,
700 CoreEventLog.MachineName), new Win32Exception ());
702 return hEventLog;
705 public override void DisableNotification ()
707 lock (_eventLock) {
708 if (_notifyResetEvent != null) {
709 _notifyResetEvent.Close ();
710 _notifyResetEvent = null;
712 _notifyThread = null;
716 public override void EnableNotification ()
718 lock (_eventLock) {
719 if (_notifyResetEvent != null)
720 return;
722 _notifyResetEvent = new ManualResetEvent (false);
723 _lastEntryWritten = OldestEventLogEntry + EntryCount;
724 if (PInvoke.NotifyChangeEventLog (ReadHandle, _notifyResetEvent.SafeWaitHandle.DangerousGetHandle ()) == 0)
725 throw new InvalidOperationException (string.Format (
726 CultureInfo.InvariantCulture, "Unable to receive notifications"
727 + " for log '{0}' on computer '{1}'.", CoreEventLog.GetLogName (),
728 CoreEventLog.MachineName), new Win32Exception ());
729 _notifyThread = new Thread (() => NotifyEventThread(_notifyResetEvent));
730 _notifyThread.IsBackground = true;
731 _notifyThread.Start ();
735 private void NotifyEventThread (ManualResetEvent resetEvent)
737 if (resetEvent == null)
738 return;
740 while (true) {
741 try {
742 resetEvent.WaitOne ();
743 } catch (ObjectDisposedException) {
744 // Notifications have been disabled and event
745 // has been closed but not yet nulled. End thread.
746 break;
749 lock (_eventLock) {
750 if (resetEvent != _notifyResetEvent) {
751 // A new thread has started with another reset event instance
752 // or DisableNotifications has been called, setting
753 // _notifyResetEvent to null. In both cases end this thread.
754 break;
757 if (_readHandle == IntPtr.Zero)
758 break;
760 int oldest_entry = OldestEventLogEntry;
761 if (_lastEntryWritten < oldest_entry)
762 _lastEntryWritten = oldest_entry;
763 int current_entry = _lastEntryWritten - oldest_entry;
764 int last_entry = EntryCount + oldest_entry;
765 for (int i = current_entry; i < (last_entry - 1); i++) {
766 EventLogEntry entry = GetEntry (i);
767 CoreEventLog.OnEntryWritten (entry);
769 _lastEntryWritten = last_entry;
774 public override OverflowAction OverflowAction {
775 get { throw new NotImplementedException (); }
778 public override int MinimumRetentionDays {
779 get { throw new NotImplementedException (); }
782 public override long MaximumKilobytes {
783 get { throw new NotImplementedException (); }
784 set { throw new NotImplementedException (); }
787 public override void ModifyOverflowPolicy (OverflowAction action, int retentionDays)
789 throw new NotImplementedException ();
792 public override void RegisterDisplayName (string resourceFile, long resourceId)
794 throw new NotImplementedException ();
797 private class PInvoke
799 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
800 public static extern int ClearEventLog (IntPtr hEventLog, string lpBackupFileName);
802 [DllImport ("advapi32.dll", SetLastError=true)]
803 public static extern int CloseEventLog (IntPtr hEventLog);
805 [DllImport ("advapi32.dll", SetLastError=true)]
806 public static extern int DeregisterEventSource (IntPtr hEventLog);
808 [DllImport ("kernel32", CharSet=CharSet.Auto, SetLastError=true)]
809 public static extern int FormatMessage (FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr [] arguments);
811 [DllImport ("kernel32", SetLastError=true)]
812 public static extern bool FreeLibrary (IntPtr hModule);
814 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
815 public static extern int GetNumberOfEventLogRecords (IntPtr hEventLog, ref int NumberOfRecords);
817 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
818 public static extern int GetOldestEventLogRecord (IntPtr hEventLog, ref int OldestRecord);
820 [DllImport ("kernel32", SetLastError=true)]
821 public static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hFile, LoadFlags dwFlags);
823 [DllImport ("kernel32", SetLastError=true)]
824 public static extern IntPtr LocalFree (IntPtr hMem);
826 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "LookupAccountSidW", SetLastError=true)]
827 public static extern bool LookupAccountSid (
828 string lpSystemName,
829 [MarshalAs (UnmanagedType.LPArray)] byte [] Sid,
830 StringBuilder lpName,
831 ref uint cchName,
832 StringBuilder ReferencedDomainName,
833 ref uint cchReferencedDomainName,
834 out SidNameUse peUse);
836 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
837 public static extern int NotifyChangeEventLog (IntPtr hEventLog, IntPtr hEvent);
839 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
840 public static extern IntPtr OpenEventLog (string machineName, string logName);
842 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
843 public static extern IntPtr RegisterEventSource (string machineName, string sourceName);
845 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
846 public static extern int ReportEvent (IntPtr hHandle, ushort wType,
847 ushort wCategory, uint dwEventID, IntPtr sid, ushort wNumStrings,
848 uint dwDataSize, string [] lpStrings, byte [] lpRawData);
850 [DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
851 public static extern int ReadEventLog (IntPtr hEventLog, ReadFlags dwReadFlags, int dwRecordOffset, byte [] buffer, int nNumberOfBytesToRead, ref int pnBytesRead, ref int pnMinNumberOfBytesNeeded);
853 public const int ERROR_INSUFFICIENT_BUFFER = 122;
854 public const int ERROR_EVENTLOG_FILE_CHANGED = 1503;
857 private enum ReadFlags
859 Sequential = 0x001,
860 Seek = 0x002,
861 ForwardsRead = 0x004,
862 BackwardsRead = 0x008
865 private enum LoadFlags: uint
867 LibraryAsDataFile = 0x002
870 [Flags]
871 private enum FormatMessageFlags
873 AllocateBuffer = 0x100,
874 IgnoreInserts = 0x200,
875 FromHModule = 0x0800,
876 FromSystem = 0x1000,
877 ArgumentArray = 0x2000
880 private enum SidNameUse
882 User = 1,
883 Group,
884 Domain,
885 lias,
886 WellKnownGroup,
887 DeletedAccount,
888 Invalid,
889 Unknown,
890 Computer
895 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
897 // struct EVENTLOGRECORD {
898 // int Length;
899 // int Reserved;
900 // int RecordNumber;
901 // int TimeGenerated;
902 // int TimeWritten;
903 // int EventID;
904 // short EventType;
905 // short NumStrings;
906 // short EventCategory;
907 // short ReservedFlags;
908 // int ClosingRecordNumber;
909 // int StringOffset;
910 // int UserSidLength;
911 // int UserSidOffset;
912 // int DataLength;
913 // int DataOffset;
914 // }
916 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html