2 // System.Diagnostics.Win32EventLog.cs
5 // Gert Driesen <driesen@users.sourceforge.net>
7 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System
.Collections
.Generic
;
31 using System
.ComponentModel
;
32 using System
.Diagnostics
;
33 using System
.Globalization
;
35 using System
.Runtime
.InteropServices
;
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
)
57 public override void BeginInit ()
61 public override void Clear ()
63 int ret
= PInvoke
.ClearEventLog (ReadHandle
, null);
65 throw new Win32Exception (Marshal
.GetLastWin32Error ());
68 public override void Close ()
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;
87 logKey
= eventLogKey
.OpenSubKey (sourceData
.LogName
, true);
89 ValidateCustomerLogName (sourceData
.LogName
,
90 sourceData
.MachineName
);
92 logKey
= eventLogKey
.CreateSubKey (sourceData
.LogName
);
93 logKey
.SetValue ("Sources", new string [] { sourceData
.LogName
,
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
});
112 for (int i
= 0; i
< sources
.Length
; i
++) {
113 if (sources
[i
] == sourceData
.Source
) {
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
);
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)) {
145 throw new InvalidOperationException (string.Format (
146 CultureInfo
.InvariantCulture
, "Event Log '{0}'"
147 + " does not exist on computer '{1}'.", logName
,
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");
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
)
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)
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)
236 return formattedCategory
!= null ? formattedCategory
: "(" +
237 category
.ToString (CultureInfo
.InvariantCulture
) + ")";
240 protected override int GetEntryCount ()
243 int retVal
= PInvoke
.GetNumberOfEventLogRecords (ReadHandle
, ref entryCount
);
245 throw new Win32Exception (Marshal
.GetLastWin32Error ());
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
;
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
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 (
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 ();
302 while (br
.PeekChar () != '\0')
303 sb
.Append (br
.ReadChar ());
304 br
.ReadChar (); // skip the null-char
305 string machineName
= sb
.ToString ();
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) {
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
++) {
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
);
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)) {
366 return GetLogName (logKey
);
370 public override bool SourceExists (string source
, string machineName
)
372 RegistryKey logKey
= FindLogKeyBySource (source
, machineName
, false);
373 if (logKey
!= null) {
380 public override void WriteEntry (string [] replacementStrings
, EventLogEntryType type
, uint instanceID
, short category
, byte [] rawData
)
382 IntPtr hEventLog
= RegisterEventSource ();
384 int ret
= PInvoke
.ReportEvent (hEventLog
, (ushort) type
,
385 (ushort) category
, instanceID
, IntPtr
.Zero
,
386 (ushort) replacementStrings
.Length
,
387 (uint) rawData
.Length
, replacementStrings
, rawData
);
389 throw new Win32Exception (Marshal
.GetLastWin32Error ());
392 DeregisterEventSource (hEventLog
);
396 private static void UpdateLogRegistry (RegistryKey logKey
)
398 // TODO: write other Log values:
401 // - AutoBackupLogFiles
403 if (logKey
.GetValue ("File") == null) {
404 string logName
= GetLogName (logKey
);
406 if (logName
.Length
> 8) {
407 file
= logName
.Substring (0, 8) + ".evt";
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
);
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
);
453 int error
= Marshal
.GetLastWin32Error ();
454 if (i
< (max_retries
- 1)) {
455 CoreEventLog
.Reset ();
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)
475 RegistryKey eventLogKey
= null;
477 eventLogKey
= GetEventLogKey (machineName
, writable
);
478 if (eventLogKey
== null)
481 string [] subKeys
= eventLogKey
.GetSubKeyNames ();
482 for (int i
= 0; i
< subKeys
.Length
; i
++) {
483 using (RegistryKey logKey
= eventLogKey
.OpenSubKey (subKeys
[i
], writable
)) {
487 RegistryKey sourceKey
= logKey
.OpenSubKey (source
, writable
);
488 if (sourceKey
!= null)
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) {
506 return eventLogKey
.OpenSubKey (logName
, writable
);
510 private static RegistryKey
FindLogKeyBySource (string source
, string machineName
, bool writable
)
512 if (source
== null || source
.Length
== 0)
515 RegistryKey eventLogKey
= null;
517 eventLogKey
= GetEventLogKey (machineName
, writable
);
518 if (eventLogKey
== null)
521 string [] subKeys
= eventLogKey
.GetSubKeyNames ();
522 for (int i
= 0; i
< subKeys
.Length
; i
++) {
523 RegistryKey sourceKey
= null;
525 RegistryKey logKey
= eventLogKey
.OpenSubKey (subKeys
[i
], writable
);
526 if (logKey
!= null) {
527 sourceKey
= logKey
.OpenSubKey (source
, writable
);
528 if (sourceKey
!= null)
532 if (sourceKey
!= null)
538 if (eventLogKey
!= null)
539 eventLogKey
.Close ();
543 private int OldestEventLogEntry
{
545 int oldestEventLogEntry
= 0;
546 int ret
= PInvoke
.GetOldestEventLogRecord (ReadHandle
, ref oldestEventLogEntry
);
548 throw new Win32Exception (Marshal
.GetLastWin32Error ());
550 return oldestEventLogEntry
;
554 private void CloseEventLog (IntPtr hEventLog
)
556 int ret
= PInvoke
.CloseEventLog (hEventLog
);
558 throw new Win32Exception (Marshal
.GetLastWin32Error ());
562 private void DeregisterEventSource (IntPtr hEventLog
)
564 int ret
= PInvoke
.DeregisterEventSource (hEventLog
);
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
;
581 string accountName
= null;
583 while (accountName
== null) {
584 bool retOk
= PInvoke
.LookupAccountSid (machineName
, sid
, name
, ref cchName
,
585 referencedDomainName
, ref cchReferencedDomainName
,
588 int err
= Marshal
.GetLastWin32Error ();
589 if (err
== PInvoke
.ERROR_INSUFFICIENT_BUFFER
) {
590 name
.EnsureCapacity ((int) cchName
);
591 referencedDomainName
.EnsureCapacity ((int) cchReferencedDomainName
);
593 // TODO: write warning ?
594 accountName
= string.Empty
;
597 accountName
= string.Format ("{0}\\{1}", referencedDomainName
.ToString (),
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
616 IntPtr lpMsgBuf
= IntPtr
.Zero
;
617 IntPtr
[] arguments
= new IntPtr
[replacementStrings
.Length
];
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
);
629 string sRet
= Marshal
.PtrToStringAuto (lpMsgBuf
);
630 lpMsgBuf
= PInvoke
.LocalFree (lpMsgBuf
);
631 // remove trailing whitespace (CRLF)
632 return sRet
.TrimEnd (null);
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
642 // TODO: report warning
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
);
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;
668 string [] msgResDlls
= value.Split (';');
672 return new string [0];
675 private IntPtr ReadHandle
{
677 if (_readHandle
!= IntPtr
.Zero
)
680 string logName
= CoreEventLog
.GetLogName ();
681 _readHandle
= PInvoke
.OpenEventLog (CoreEventLog
.MachineName
,
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 ());
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 ());
705 public override void DisableNotification ()
708 if (_notifyResetEvent
!= null) {
709 _notifyResetEvent
.Close ();
710 _notifyResetEvent
= null;
712 _notifyThread
= null;
716 public override void EnableNotification ()
719 if (_notifyResetEvent
!= null)
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)
742 resetEvent
.WaitOne ();
743 } catch (ObjectDisposedException
) {
744 // Notifications have been disabled and event
745 // has been closed but not yet nulled. End thread.
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.
757 if (_readHandle
== IntPtr
.Zero
)
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 (
829 [MarshalAs (UnmanagedType
.LPArray
)] byte [] Sid
,
830 StringBuilder lpName
,
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
861 ForwardsRead
= 0x004,
862 BackwardsRead
= 0x008
865 private enum LoadFlags
: uint
867 LibraryAsDataFile
= 0x002
871 private enum FormatMessageFlags
873 AllocateBuffer
= 0x100,
874 IgnoreInserts
= 0x200,
875 FromHModule
= 0x0800,
877 ArgumentArray
= 0x2000
880 private enum SidNameUse
895 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
897 // struct EVENTLOGRECORD {
901 // int TimeGenerated;
906 // short EventCategory;
907 // short ReservedFlags;
908 // int ClosingRecordNumber;
910 // int UserSidLength;
911 // int UserSidOffset;
916 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html