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.Generic;
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 var temp = new List<string> ();
181 for (int i = 0; i < sources.Length; i++)
182 if (sources [i] != source)
183 temp.Add (sources [i]);
184 string [] newSources = temp.ToArray ();
185 logKey.SetValue ("Sources", newSources);
190 public override void Dispose (bool disposing)
195 public override void EndInit ()
199 public override bool Exists (string logName, string machineName)
201 using (RegistryKey logKey = FindLogKeyByName (logName, machineName, false)) {
202 return (logKey != null);
206 [MonoTODO] // ParameterResourceFile ??
207 protected override string FormatMessage (string source, uint messageID, string [] replacementStrings)
209 string formattedMessage = null;
211 string [] msgResDlls = GetMessageResourceDlls (source, "EventMessageFile");
212 for (int i = 0; i < msgResDlls.Length; i++) {
213 formattedMessage = FetchMessage (msgResDlls [i],
214 messageID, replacementStrings);
215 if (formattedMessage != null)
219 return formattedMessage != null ? formattedMessage : string.Join (
220 ", ", replacementStrings);
223 private string FormatCategory (string source, int category)
225 string formattedCategory = null;
227 string [] msgResDlls = GetMessageResourceDlls (source, "CategoryMessageFile");
228 for (int i = 0; i < msgResDlls.Length; i++) {
229 formattedCategory = FetchMessage (msgResDlls [i],
230 (uint) category, new string [0]);
231 if (formattedCategory != null)
235 return formattedCategory != null ? formattedCategory : "(" +
236 category.ToString (CultureInfo.InvariantCulture) + ")";
239 protected override int GetEntryCount ()
242 int retVal = PInvoke.GetNumberOfEventLogRecords (ReadHandle, ref entryCount);
244 throw new Win32Exception (Marshal.GetLastWin32Error ());
248 protected override EventLogEntry GetEntry (int index)
250 // http://msdn.microsoft.com/library/en-us/eventlog/base/readeventlog.asp
251 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp
252 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html
254 index += OldestEventLogEntry;
257 int minBufferNeeded = 0;
258 byte [] buffer = new byte [0x7ffff]; // according to MSDN this is the max size of the buffer
260 ReadEventLog (index, buffer, ref bytesRead, ref minBufferNeeded);
262 MemoryStream ms = new MemoryStream (buffer);
263 BinaryReader br = new BinaryReader (ms);
265 // skip first 8 bytes
268 int recordNumber = br.ReadInt32 (); // 8
270 int timeGeneratedSeconds = br.ReadInt32 (); // 12
271 int timeWrittenSeconds = br.ReadInt32 (); // 16
272 uint instanceID = br.ReadUInt32 ();
273 int eventID = EventLog.GetEventID (instanceID);
274 short eventType = br.ReadInt16 (); // 24
275 short numStrings = br.ReadInt16 (); ; // 26
276 short categoryNumber = br.ReadInt16 (); ; // 28
277 // skip reservedFlags
278 br.ReadInt16 (); // 30
279 // skip closingRecordNumber
280 br.ReadInt32 (); // 32
281 int stringOffset = br.ReadInt32 (); // 36
282 int userSidLength = br.ReadInt32 (); // 40
283 int userSidOffset = br.ReadInt32 (); // 44
284 int dataLength = br.ReadInt32 (); // 48
285 int dataOffset = br.ReadInt32 (); // 52
287 DateTime timeGenerated = new DateTime (1970, 1, 1).AddSeconds (
288 timeGeneratedSeconds);
290 DateTime timeWritten = new DateTime (1970, 1, 1).AddSeconds (
293 StringBuilder sb = new StringBuilder ();
294 while (br.PeekChar () != '\0')
295 sb.Append (br.ReadChar ());
296 br.ReadChar (); // skip the null-char
298 string sourceName = sb.ToString ();
301 while (br.PeekChar () != '\0')
302 sb.Append (br.ReadChar ());
303 br.ReadChar (); // skip the null-char
304 string machineName = sb.ToString ();
307 while (br.PeekChar () != '\0')
308 sb.Append (br.ReadChar ());
309 br.ReadChar (); // skip the null-char
311 string userName = null;
312 if (userSidLength != 0) {
314 ms.Position = userSidOffset;
315 byte [] sid = br.ReadBytes (userSidLength);
316 userName = LookupAccountSid (machineName, sid);
319 ms.Position = stringOffset;
320 string [] replacementStrings = new string [numStrings];
321 for (int i = 0; i < numStrings; i++) {
323 while (br.PeekChar () != '\0')
324 sb.Append (br.ReadChar ());
325 br.ReadChar (); // skip the null-char
326 replacementStrings [i] = sb.ToString ();
329 byte [] data = new byte [dataLength];
330 ms.Position = dataOffset;
331 br.Read (data, 0, dataLength);
333 // TODO: lazy fetch ??
334 string message = this.FormatMessage (sourceName, instanceID, replacementStrings);
335 string category = FormatCategory (sourceName, categoryNumber);
337 return new EventLogEntry (category, (short) categoryNumber, recordNumber,
338 eventID, sourceName, message, userName, machineName,
339 (EventLogEntryType) eventType, timeGenerated, timeWritten,
340 data, replacementStrings, instanceID);
344 protected override string GetLogDisplayName ()
346 return CoreEventLog.Log;
349 protected override string [] GetLogNames (string machineName)
351 using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
352 if (eventLogKey == null)
353 return new string [0];
355 return eventLogKey.GetSubKeyNames ();
359 public override string LogNameFromSourceName (string source, string machineName)
361 using (RegistryKey logKey = FindLogKeyBySource (source, machineName, false)) {
365 return GetLogName (logKey);
369 public override bool SourceExists (string source, string machineName)
371 RegistryKey logKey = FindLogKeyBySource (source, machineName, false);
372 if (logKey != null) {
379 public override void WriteEntry (string [] replacementStrings, EventLogEntryType type, uint instanceID, short category, byte [] rawData)
381 IntPtr hEventLog = RegisterEventSource ();
383 int ret = PInvoke.ReportEvent (hEventLog, (ushort) type,
384 (ushort) category, instanceID, IntPtr.Zero,
385 (ushort) replacementStrings.Length,
386 (uint) rawData.Length, replacementStrings, rawData);
388 throw new Win32Exception (Marshal.GetLastWin32Error ());
391 DeregisterEventSource (hEventLog);
395 private static void UpdateLogRegistry (RegistryKey logKey)
397 // TODO: write other Log values:
400 // - AutoBackupLogFiles
402 if (logKey.GetValue ("File") == null) {
403 string logName = GetLogName (logKey);
405 if (logName.Length > 8) {
406 file = logName.Substring (0, 8) + ".evt";
408 file = logName + ".evt";
410 string configPath = Path.Combine (Environment.GetFolderPath (
411 Environment.SpecialFolder.System), "config");
412 logKey.SetValue ("File", Path.Combine (configPath, file));
416 private static void UpdateSourceRegistry (RegistryKey sourceKey, EventSourceCreationData data)
418 if (data.CategoryCount > 0)
419 sourceKey.SetValue ("CategoryCount", data.CategoryCount);
421 if (data.CategoryResourceFile != null && data.CategoryResourceFile.Length > 0)
422 sourceKey.SetValue ("CategoryMessageFile", data.CategoryResourceFile);
424 if (data.MessageResourceFile != null && data.MessageResourceFile.Length > 0) {
425 sourceKey.SetValue ("EventMessageFile", data.MessageResourceFile);
427 // FIXME: write default once we have approval for shipping EventLogMessages.dll
430 if (data.ParameterResourceFile != null && data.ParameterResourceFile.Length > 0)
431 sourceKey.SetValue ("ParameterMessageFile", data.ParameterResourceFile);
434 private static string GetLogName (RegistryKey logKey)
436 string logName = logKey.Name;
437 return logName.Substring (logName.LastIndexOf ("\\") + 1);
440 private void ReadEventLog (int index, byte [] buffer, ref int bytesRead, ref int minBufferNeeded)
442 const int max_retries = 3;
444 // if the eventlog file changed since the handle was
445 // obtained, then we need to re-try multiple times
446 for (int i = 0; i < max_retries; i++) {
447 int ret = PInvoke.ReadEventLog (ReadHandle,
448 ReadFlags.Seek | ReadFlags.ForwardsRead,
449 index, buffer, buffer.Length, ref bytesRead,
450 ref minBufferNeeded);
452 int error = Marshal.GetLastWin32Error ();
453 if (i < (max_retries - 1)) {
454 CoreEventLog.Reset ();
456 throw new Win32Exception (error);
463 [MonoTODO ("Support remote machines")]
464 private static RegistryKey GetEventLogKey (string machineName, bool writable)
466 return Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Services\EventLog", writable);
469 private static RegistryKey FindSourceKeyByName (string source, string machineName, bool writable)
471 if (source == null || source.Length == 0)
474 RegistryKey eventLogKey = null;
476 eventLogKey = GetEventLogKey (machineName, writable);
477 if (eventLogKey == null)
480 string [] subKeys = eventLogKey.GetSubKeyNames ();
481 for (int i = 0; i < subKeys.Length; i++) {
482 using (RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable)) {
486 RegistryKey sourceKey = logKey.OpenSubKey (source, writable);
487 if (sourceKey != null)
493 if (eventLogKey != null)
494 eventLogKey.Close ();
498 private static RegistryKey FindLogKeyByName (string logName, string machineName, bool writable)
500 using (RegistryKey eventLogKey = GetEventLogKey (machineName, writable)) {
501 if (eventLogKey == null) {
505 return eventLogKey.OpenSubKey (logName, writable);
509 private static RegistryKey FindLogKeyBySource (string source, string machineName, bool writable)
511 if (source == null || source.Length == 0)
514 RegistryKey eventLogKey = null;
516 eventLogKey = GetEventLogKey (machineName, writable);
517 if (eventLogKey == null)
520 string [] subKeys = eventLogKey.GetSubKeyNames ();
521 for (int i = 0; i < subKeys.Length; i++) {
522 RegistryKey sourceKey = null;
524 RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable);
525 if (logKey != null) {
526 sourceKey = logKey.OpenSubKey (source, writable);
527 if (sourceKey != null)
531 if (sourceKey != null)
537 if (eventLogKey != null)
538 eventLogKey.Close ();
542 private int OldestEventLogEntry {
544 int oldestEventLogEntry = 0;
545 int ret = PInvoke.GetOldestEventLogRecord (ReadHandle, ref oldestEventLogEntry);
547 throw new Win32Exception (Marshal.GetLastWin32Error ());
549 return oldestEventLogEntry;
553 private void CloseEventLog (IntPtr hEventLog)
555 int ret = PInvoke.CloseEventLog (hEventLog);
557 throw new Win32Exception (Marshal.GetLastWin32Error ());
561 private void DeregisterEventSource (IntPtr hEventLog)
563 int ret = PInvoke.DeregisterEventSource (hEventLog);
565 throw new Win32Exception (Marshal.GetLastWin32Error ());
569 private static string LookupAccountSid (string machineName, byte [] sid)
571 // http://www.pinvoke.net/default.aspx/advapi32/LookupAccountSid.html
572 // http://msdn.microsoft.com/library/en-us/secauthz/security/lookupaccountsid.asp
574 StringBuilder name = new StringBuilder ();
575 uint cchName = (uint) name.Capacity;
576 StringBuilder referencedDomainName = new StringBuilder ();
577 uint cchReferencedDomainName = (uint) referencedDomainName.Capacity;
580 string accountName = null;
582 while (accountName == null) {
583 bool retOk = PInvoke.LookupAccountSid (machineName, sid, name, ref cchName,
584 referencedDomainName, ref cchReferencedDomainName,
587 int err = Marshal.GetLastWin32Error ();
588 if (err == PInvoke.ERROR_INSUFFICIENT_BUFFER) {
589 name.EnsureCapacity ((int) cchName);
590 referencedDomainName.EnsureCapacity ((int) cchReferencedDomainName);
592 // TODO: write warning ?
593 accountName = string.Empty;
596 accountName = string.Format ("{0}\\{1}", referencedDomainName.ToString (),
603 private static string FetchMessage (string msgDll, uint messageID, string [] replacementStrings)
605 // http://msdn.microsoft.com/library/en-us/debug/base/formatmessage.asp
606 // http://msdn.microsoft.com/msdnmag/issues/02/08/CQA/
607 // http://msdn.microsoft.com/netframework/programming/netcf/cffaq/default.aspx
609 IntPtr msgDllHandle = PInvoke.LoadLibraryEx (msgDll, IntPtr.Zero,
610 LoadFlags.LibraryAsDataFile);
611 if (msgDllHandle == IntPtr.Zero)
612 // TODO: write warning
615 IntPtr lpMsgBuf = IntPtr.Zero;
616 IntPtr [] arguments = new IntPtr [replacementStrings.Length];
619 for (int i = 0; i < replacementStrings.Length; i++) {
620 arguments [i] = Marshal.StringToHGlobalAuto (
621 replacementStrings [i]);
624 int ret = PInvoke.FormatMessage (FormatMessageFlags.ArgumentArray |
625 FormatMessageFlags.FromHModule | FormatMessageFlags.AllocateBuffer,
626 msgDllHandle, messageID, 0, ref lpMsgBuf, 0, arguments);
628 string sRet = Marshal.PtrToStringAuto (lpMsgBuf);
629 lpMsgBuf = PInvoke.LocalFree (lpMsgBuf);
630 // remove trailing whitespace (CRLF)
631 return sRet.TrimEnd (null);
633 int err = Marshal.GetLastWin32Error ();
634 if (err == MESSAGE_NOT_FOUND) {
635 // do not consider this a failure (or even warning) as
636 // multiple message resource DLLs may have been configured
637 // and as such we just need to try the next library if
638 // the current one does not contain a message for this
641 // TODO: report warning
645 // release unmanaged memory allocated for replacement strings
646 for (int i = 0; i < arguments.Length; i++) {
647 IntPtr argument = arguments [i];
648 if (argument != IntPtr.Zero)
649 Marshal.FreeHGlobal (argument);
652 PInvoke.FreeLibrary (msgDllHandle);
657 private string [] GetMessageResourceDlls (string source, string valueName)
659 // Some event sources (such as Userenv) have multiple message
660 // resource DLLs, delimited by a semicolon.
662 RegistryKey sourceKey = FindSourceKeyByName (source,
663 CoreEventLog.MachineName, false);
664 if (sourceKey != null) {
665 string value = sourceKey.GetValue (valueName) as string;
667 string [] msgResDlls = value.Split (';');
671 return new string [0];
674 private IntPtr ReadHandle {
676 if (_readHandle != IntPtr.Zero)
679 string logName = CoreEventLog.GetLogName ();
680 _readHandle = PInvoke.OpenEventLog (CoreEventLog.MachineName,
682 if (_readHandle == IntPtr.Zero)
683 throw new InvalidOperationException (string.Format (
684 CultureInfo.InvariantCulture, "Event Log '{0}' on computer"
685 + " '{1}' cannot be opened.", logName, CoreEventLog.MachineName),
686 new Win32Exception ());
691 private IntPtr RegisterEventSource ()
693 IntPtr hEventLog = PInvoke.RegisterEventSource (
694 CoreEventLog.MachineName, CoreEventLog.Source);
695 if (hEventLog == IntPtr.Zero) {
696 throw new InvalidOperationException (string.Format (
697 CultureInfo.InvariantCulture, "Event source '{0}' on computer"
698 + " '{1}' cannot be opened.", CoreEventLog.Source,
699 CoreEventLog.MachineName), new Win32Exception ());
704 public override void DisableNotification ()
706 if (_notifyResetEvent != null) {
707 _notifyResetEvent.Close ();
708 _notifyResetEvent = null;
711 if (_notifyThread != null) {
712 if (_notifyThread.ThreadState == System.Threading.ThreadState.Running)
713 _notifyThread.Abort ();
714 _notifyThread = null;
718 public override void EnableNotification ()
720 _notifyResetEvent = new ManualResetEvent (false);
721 _lastEntryWritten = OldestEventLogEntry + EntryCount;
722 if (PInvoke.NotifyChangeEventLog (ReadHandle, _notifyResetEvent.Handle) == 0)
723 throw new InvalidOperationException (string.Format (
724 CultureInfo.InvariantCulture, "Unable to receive notifications"
725 + " for log '{0}' on computer '{1}'.", CoreEventLog.GetLogName (),
726 CoreEventLog.MachineName), new Win32Exception ());
727 _notifyThread = new Thread (new ThreadStart (NotifyEventThread));
728 _notifyThread.IsBackground = true;
729 _notifyThread.Start ();
732 private void NotifyEventThread ()
735 _notifyResetEvent.WaitOne ();
737 // after a clear, we something get notified
738 // twice for the same entry
745 int oldest_entry = OldestEventLogEntry;
746 if (_lastEntryWritten < oldest_entry)
747 _lastEntryWritten = oldest_entry;
748 int current_entry = _lastEntryWritten - oldest_entry;
749 int last_entry = EntryCount + oldest_entry;
750 for (int i = current_entry; i < (last_entry - 1); i++) {
751 EventLogEntry entry = GetEntry (i);
752 CoreEventLog.OnEntryWritten (entry);
754 _lastEntryWritten = last_entry;
762 public override OverflowAction OverflowAction {
763 get { throw new NotImplementedException (); }
766 public override int MinimumRetentionDays {
767 get { throw new NotImplementedException (); }
770 public override long MaximumKilobytes {
771 get { throw new NotImplementedException (); }
772 set { throw new NotImplementedException (); }
775 public override void ModifyOverflowPolicy (OverflowAction action, int retentionDays)
777 throw new NotImplementedException ();
780 public override void RegisterDisplayName (string resourceFile, long resourceId)
782 throw new NotImplementedException ();
785 private class PInvoke
787 [DllImport ("advapi32.dll", SetLastError=true)]
788 public static extern int ClearEventLog (IntPtr hEventLog, string lpBackupFileName);
790 [DllImport ("advapi32.dll", SetLastError=true)]
791 public static extern int CloseEventLog (IntPtr hEventLog);
793 [DllImport ("advapi32.dll", SetLastError=true)]
794 public static extern int DeregisterEventSource (IntPtr hEventLog);
796 [DllImport ("kernel32", CharSet=CharSet.Auto, SetLastError=true)]
797 public static extern int FormatMessage (FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr [] arguments);
799 [DllImport ("kernel32", SetLastError=true)]
800 public static extern bool FreeLibrary (IntPtr hModule);
802 [DllImport ("advapi32.dll", SetLastError=true)]
803 public static extern int GetNumberOfEventLogRecords (IntPtr hEventLog, ref int NumberOfRecords);
805 [DllImport ("advapi32.dll", SetLastError=true)]
806 public static extern int GetOldestEventLogRecord (IntPtr hEventLog, ref int OldestRecord);
808 [DllImport ("kernel32", SetLastError=true)]
809 public static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hFile, LoadFlags dwFlags);
811 [DllImport ("kernel32", SetLastError=true)]
812 public static extern IntPtr LocalFree (IntPtr hMem);
814 [DllImport ("advapi32.dll", SetLastError=true)]
815 public static extern bool LookupAccountSid (
817 [MarshalAs (UnmanagedType.LPArray)] byte [] Sid,
818 StringBuilder lpName,
820 StringBuilder ReferencedDomainName,
821 ref uint cchReferencedDomainName,
822 out SidNameUse peUse);
824 [DllImport ("advapi32.dll", SetLastError = true)]
825 public static extern int NotifyChangeEventLog (IntPtr hEventLog, IntPtr hEvent);
827 [DllImport ("advapi32.dll", SetLastError=true)]
828 public static extern IntPtr OpenEventLog (string machineName, string logName);
830 [DllImport ("advapi32.dll", SetLastError=true)]
831 public static extern IntPtr RegisterEventSource (string machineName, string sourceName);
833 [DllImport ("advapi32.dll", SetLastError=true)]
834 public static extern int ReportEvent (IntPtr hHandle, ushort wType,
835 ushort wCategory, uint dwEventID, IntPtr sid, ushort wNumStrings,
836 uint dwDataSize, string [] lpStrings, byte [] lpRawData);
838 [DllImport ("advapi32.dll", SetLastError=true)]
839 public static extern int ReadEventLog (IntPtr hEventLog, ReadFlags dwReadFlags, int dwRecordOffset, byte [] buffer, int nNumberOfBytesToRead, ref int pnBytesRead, ref int pnMinNumberOfBytesNeeded);
841 public const int ERROR_INSUFFICIENT_BUFFER = 122;
842 public const int ERROR_EVENTLOG_FILE_CHANGED = 1503;
845 private enum ReadFlags
849 ForwardsRead = 0x004,
850 BackwardsRead = 0x008
853 private enum LoadFlags: uint
855 LibraryAsDataFile = 0x002
859 private enum FormatMessageFlags
861 AllocateBuffer = 0x100,
862 IgnoreInserts = 0x200,
863 FromHModule = 0x0800,
865 ArgumentArray = 0x2000
868 private enum SidNameUse
883 // http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
885 // struct EVENTLOGRECORD {
889 // int TimeGenerated;
894 // short EventCategory;
895 // short ReservedFlags;
896 // int ClosingRecordNumber;
898 // int UserSidLength;
899 // int UserSidOffset;
904 // http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html