Revert
[mono-project.git] / mcs / class / System / System.Diagnostics / Win32EventLog.cs
blob1422f883936ab7da61808202dd4b35a898b789d8
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 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.Collections;
32 using System.ComponentModel;
33 using System.Diagnostics;
34 using System.Globalization;
35 using System.IO;
36 using System.Runtime.InteropServices;
37 using System.Text;
38 using System.Threading;
40 using Microsoft.Win32;
42 namespace System.Diagnostics
44 internal class Win32EventLog : EventLogImpl
46 private const int MESSAGE_NOT_FOUND = 317;
47 private ManualResetEvent _notifyResetEvent;
48 private IntPtr _readHandle;
49 private Thread _notifyThread;
50 private int _lastEntryWritten;
51 private bool _notifying;
53 public Win32EventLog (EventLog coreEventLog)
54 : base (coreEventLog)
58 public override void BeginInit ()
62 public override void Clear ()
64 int ret = PInvoke.ClearEventLog (ReadHandle, null);
65 if (ret != 1)
66 throw new Win32Exception (Marshal.GetLastWin32Error ());
69 public override void Close ()
71 if (_readHandle != IntPtr.Zero) {
72 CloseEventLog (_readHandle);
73 _readHandle = IntPtr.Zero;
77 public override void CreateEventSource (EventSourceCreationData sourceData)
79 using (RegistryKey eventLogKey = GetEventLogKey (sourceData.MachineName, true)) {
80 if (eventLogKey == null)
81 throw new InvalidOperationException ("EventLog registry key is missing.");
83 bool logKeyCreated = false;
84 RegistryKey logKey = null;
85 try {
86 logKey = eventLogKey.OpenSubKey (sourceData.LogName, true);
87 if (logKey == null) {
88 ValidateCustomerLogName (sourceData.LogName,
89 sourceData.MachineName);
91 logKey = eventLogKey.CreateSubKey (sourceData.LogName);
92 logKey.SetValue ("Sources", new string [] { sourceData.LogName,
93 sourceData.Source });
94 UpdateLogRegistry (logKey);
96 using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.LogName)) {
97 UpdateSourceRegistry (sourceKey, sourceData);
100 logKeyCreated = true;
103 if (sourceData.LogName != sourceData.Source) {
104 if (!logKeyCreated) {
105 string [] sources = (string []) logKey.GetValue ("Sources");
106 if (sources == null) {
107 logKey.SetValue ("Sources", new string [] { sourceData.LogName,
108 sourceData.Source });
109 } else {
110 bool found = false;
111 for (int i = 0; i < sources.Length; i++) {
112 if (sources [i] == sourceData.Source) {
113 found = true;
114 break;
117 if (!found) {
118 string [] newSources = new string [sources.Length + 1];
119 Array.Copy (sources, 0, newSources, 0, sources.Length);
120 newSources [sources.Length] = sourceData.Source;
121 logKey.SetValue ("Sources", newSources);
125 using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.Source)) {
126 UpdateSourceRegistry (sourceKey, sourceData);
129 } finally {
130 if (logKey != null)
131 logKey.Close ();
136 public override void Delete (string logName, string machineName)
138 using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
139 if (eventLogKey == null)
140 throw new InvalidOperationException ("The event log key does not exist.");
142 using (RegistryKey logKey = eventLogKey.OpenSubKey (logName, false)) {
143 if (logKey == null)
144 throw new InvalidOperationException (string.Format (
145 CultureInfo.InvariantCulture, "Event Log '{0}'"
146 + " does not exist on computer '{1}'.", logName,
147 machineName));
149 // remove all eventlog entries for specified log
150 CoreEventLog.Clear ();
152 // remove file holding event log entries
153 string file = (string) logKey.GetValue ("File");
154 if (file != null) {
155 try {
156 File.Delete (file);
157 } catch (Exception) {
158 // .NET seems to ignore failures here
163 eventLogKey.DeleteSubKeyTree (logName);
167 public override void DeleteEventSource (string source, string machineName)
169 using (RegistryKey logKey = FindLogKeyBySource (source, machineName, true)) {
170 if (logKey == null) {
171 throw new ArgumentException (string.Format (
172 CultureInfo.InvariantCulture, "The source '{0}' is not"
173 + " registered on computer '{1}'.", source, machineName));
176 logKey.DeleteSubKeyTree (source);
178 string [] sources = (string []) logKey.GetValue ("Sources");
179 if (sources != null) {
180 ArrayList temp = new ArrayList ();
181 for (int i = 0; i < sources.Length; i++)
182 if (sources [i] != source)
183 temp.Add (sources [i]);
184 string [] newSources = new string [temp.Count];
185 temp.CopyTo (newSources, 0);
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);
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 if (_notifyResetEvent != null) {
708 _notifyResetEvent.Close ();
709 _notifyResetEvent = null;
712 if (_notifyThread != null) {
713 if (_notifyThread.ThreadState == System.Threading.ThreadState.Running)
714 _notifyThread.Abort ();
715 _notifyThread = null;
719 public override void EnableNotification ()
721 _notifyResetEvent = new ManualResetEvent (false);
722 _lastEntryWritten = OldestEventLogEntry + EntryCount;
723 if (PInvoke.NotifyChangeEventLog (ReadHandle, _notifyResetEvent.Handle) == 0)
724 throw new InvalidOperationException (string.Format (
725 CultureInfo.InvariantCulture, "Unable to receive notifications"
726 + " for log '{0}' on computer '{1}'.", CoreEventLog.GetLogName (),
727 CoreEventLog.MachineName), new Win32Exception ());
728 _notifyThread = new Thread (new ThreadStart (NotifyEventThread));
729 _notifyThread.IsBackground = true;
730 _notifyThread.Start ();
733 private void NotifyEventThread ()
735 while (true) {
736 _notifyResetEvent.WaitOne ();
737 lock (this) {
738 // after a clear, we something get notified
739 // twice for the same entry
740 if (_notifying)
741 return;
742 _notifying = true;
745 try {
746 int oldest_entry = OldestEventLogEntry;
747 if (_lastEntryWritten < oldest_entry)
748 _lastEntryWritten = oldest_entry;
749 int current_entry = _lastEntryWritten - oldest_entry;
750 int last_entry = EntryCount + oldest_entry;
751 for (int i = current_entry; i < (last_entry - 1); i++) {
752 EventLogEntry entry = GetEntry (i);
753 CoreEventLog.OnEntryWritten (entry);
755 _lastEntryWritten = last_entry;
756 } finally {
757 lock (this)
758 _notifying = false;
763 #if NET_2_0
764 public override OverflowAction OverflowAction {
765 get { throw new NotImplementedException (); }
768 public override int MinimumRetentionDays {
769 get { throw new NotImplementedException (); }
772 public override long MaximumKilobytes {
773 get { throw new NotImplementedException (); }
774 set { throw new NotImplementedException (); }
777 public override void ModifyOverflowPolicy (OverflowAction action, int retentionDays)
779 throw new NotImplementedException ();
782 public override void RegisterDisplayName (string resourceFile, long resourceId)
784 throw new NotImplementedException ();
786 #endif
788 private class PInvoke
790 [DllImport ("advapi32.dll", SetLastError=true)]
791 public static extern int ClearEventLog (IntPtr hEventLog, string lpBackupFileName);
793 [DllImport ("advapi32.dll", SetLastError=true)]
794 public static extern int CloseEventLog (IntPtr hEventLog);
796 [DllImport ("advapi32.dll", SetLastError=true)]
797 public static extern int DeregisterEventSource (IntPtr hEventLog);
799 [DllImport ("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
800 public static extern int FormatMessage (FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr [] arguments);
802 [DllImport ("kernel32.dll", SetLastError=true)]
803 public static extern bool FreeLibrary (IntPtr hModule);
805 [DllImport ("advapi32.dll", SetLastError=true)]
806 public static extern int GetNumberOfEventLogRecords (IntPtr hEventLog, ref int NumberOfRecords);
808 [DllImport ("advapi32.dll", SetLastError=true)]
809 public static extern int GetOldestEventLogRecord (IntPtr hEventLog, ref int OldestRecord);
811 [DllImport ("kernel32.dll", SetLastError=true)]
812 public static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hFile, LoadFlags dwFlags);
814 [DllImport ("kernel32.dll", SetLastError=true)]
815 public static extern IntPtr LocalFree (IntPtr hMem);
817 [DllImport ("advapi32.dll", SetLastError=true)]
818 public static extern bool LookupAccountSid (
819 string lpSystemName,
820 [MarshalAs (UnmanagedType.LPArray)] byte [] Sid,
821 StringBuilder lpName,
822 ref uint cchName,
823 StringBuilder ReferencedDomainName,
824 ref uint cchReferencedDomainName,
825 out SidNameUse peUse);
827 [DllImport ("Advapi32.dll", SetLastError = true)]
828 public static extern int NotifyChangeEventLog (IntPtr hEventLog, IntPtr hEvent);
830 [DllImport ("advapi32.dll", SetLastError=true)]
831 public static extern IntPtr OpenEventLog (string machineName, string logName);
833 [DllImport ("advapi32.dll", SetLastError=true)]
834 public static extern IntPtr RegisterEventSource (string machineName, string sourceName);
836 [DllImport ("Advapi32.dll", SetLastError=true)]
837 public static extern int ReportEvent (IntPtr hHandle, ushort wType,
838 ushort wCategory, uint dwEventID, IntPtr sid, ushort wNumStrings,
839 uint dwDataSize, string [] lpStrings, byte [] lpRawData);
841 [DllImport ("advapi32.dll", SetLastError=true)]
842 public static extern int ReadEventLog (IntPtr hEventLog, ReadFlags dwReadFlags, int dwRecordOffset, byte [] buffer, int nNumberOfBytesToRead, ref int pnBytesRead, ref int pnMinNumberOfBytesNeeded);
844 public const int ERROR_INSUFFICIENT_BUFFER = 122;
845 public const int ERROR_EVENTLOG_FILE_CHANGED = 1503;
848 private enum ReadFlags
850 Sequential = 0x001,
851 Seek = 0x002,
852 ForwardsRead = 0x004,
853 BackwardsRead = 0x008
856 private enum LoadFlags: uint
858 LibraryAsDataFile = 0x002
861 [Flags]
862 private enum FormatMessageFlags
864 AllocateBuffer = 0x100,
865 IgnoreInserts = 0x200,
866 FromHModule = 0x0800,
867 FromSystem = 0x1000,
868 ArgumentArray = 0x2000
871 private enum SidNameUse
873 User = 1,
874 Group,
875 Domain,
876 lias,
877 WellKnownGroup,
878 DeletedAccount,
879 Invalid,
880 Unknown,
881 Computer
886 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
888 // struct EVENTLOGRECORD {
889 // int Length;
890 // int Reserved;
891 // int RecordNumber;
892 // int TimeGenerated;
893 // int TimeWritten;
894 // int EventID;
895 // short EventType;
896 // short NumStrings;
897 // short EventCategory;
898 // short ReservedFlags;
899 // int ClosingRecordNumber;
900 // int StringOffset;
901 // int UserSidLength;
902 // int UserSidOffset;
903 // int DataLength;
904 // int DataOffset;
905 // }
907 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html