2 // System.Diagnostics.Win32EventLog.cs
5 // Gert Driesen <driesen@users.sourceforge.net>
7 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
31 using System
.Collections
;
32 using System
.ComponentModel
;
33 using System
.Diagnostics
;
34 using System
.Globalization
;
36 using System
.Runtime
.InteropServices
;
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
)
58 public override void BeginInit ()
62 public override void Clear ()
64 int ret
= PInvoke
.ClearEventLog (ReadHandle
, null);
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;
86 logKey
= eventLogKey
.OpenSubKey (sourceData
.LogName
, true);
88 ValidateCustomerLogName (sourceData
.LogName
,
89 sourceData
.MachineName
);
91 logKey
= eventLogKey
.CreateSubKey (sourceData
.LogName
);
92 logKey
.SetValue ("Sources", new string [] { sourceData
.LogName
,
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
});
111 for (int i
= 0; i
< sources
.Length
; i
++) {
112 if (sources
[i
] == sourceData
.Source
) {
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
);
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)) {
144 throw new InvalidOperationException (string.Format (
145 CultureInfo
.InvariantCulture
, "Event Log '{0}'"
146 + " does not exist on computer '{1}'.", logName
,
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");
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
)
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
);
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 ()
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 ()
736 _notifyResetEvent
.WaitOne ();
738 // after a clear, we something get notified
739 // twice for the same entry
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
;
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 ();
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 (
820 [MarshalAs (UnmanagedType
.LPArray
)] byte [] Sid
,
821 StringBuilder lpName
,
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
852 ForwardsRead
= 0x004,
853 BackwardsRead
= 0x008
856 private enum LoadFlags
: uint
858 LibraryAsDataFile
= 0x002
862 private enum FormatMessageFlags
864 AllocateBuffer
= 0x100,
865 IgnoreInserts
= 0x200,
866 FromHModule
= 0x0800,
868 ArgumentArray
= 0x2000
871 private enum SidNameUse
886 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
888 // struct EVENTLOGRECORD {
892 // int TimeGenerated;
897 // short EventCategory;
898 // short ReservedFlags;
899 // int ClosingRecordNumber;
901 // int UserSidLength;
902 // int UserSidOffset;
907 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html