Xamarin Public Jenkins (auto-signing) e46a49ecf1 Imported Upstream version 5.10.0.47
Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
2018-01-24 17:04:36 +00:00

917 lines
27 KiB
C#

//
// System.Diagnostics.Win32EventLog.cs
//
// Author:
// Gert Driesen <driesen@users.sourceforge.net>
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
//
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.Win32;
namespace System.Diagnostics
{
internal class Win32EventLog : EventLogImpl
{
private const int MESSAGE_NOT_FOUND = 317;
private ManualResetEvent _notifyResetEvent;
private IntPtr _readHandle;
private Thread _notifyThread;
private int _lastEntryWritten;
private Object _eventLock = new object();
public Win32EventLog (EventLog coreEventLog)
: base (coreEventLog)
{
}
public override void BeginInit ()
{
}
public override void Clear ()
{
int ret = PInvoke.ClearEventLog (ReadHandle, null);
if (ret != 1)
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
public override void Close ()
{
lock (_eventLock) {
if (_readHandle != IntPtr.Zero) {
CloseEventLog (_readHandle);
_readHandle = IntPtr.Zero;
}
}
}
public override void CreateEventSource (EventSourceCreationData sourceData)
{
using (RegistryKey eventLogKey = GetEventLogKey (sourceData.MachineName, true)) {
if (eventLogKey == null)
throw new InvalidOperationException ("EventLog registry key is missing.");
bool logKeyCreated = false;
RegistryKey logKey = null;
try {
logKey = eventLogKey.OpenSubKey (sourceData.LogName, true);
if (logKey == null) {
ValidateCustomerLogName (sourceData.LogName,
sourceData.MachineName);
logKey = eventLogKey.CreateSubKey (sourceData.LogName);
logKey.SetValue ("Sources", new string [] { sourceData.LogName,
sourceData.Source });
UpdateLogRegistry (logKey);
using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.LogName)) {
UpdateSourceRegistry (sourceKey, sourceData);
}
logKeyCreated = true;
}
if (sourceData.LogName != sourceData.Source) {
if (!logKeyCreated) {
string [] sources = (string []) logKey.GetValue ("Sources");
if (sources == null) {
logKey.SetValue ("Sources", new string [] { sourceData.LogName,
sourceData.Source });
} else {
bool found = false;
for (int i = 0; i < sources.Length; i++) {
if (sources [i] == sourceData.Source) {
found = true;
break;
}
}
if (!found) {
string [] newSources = new string [sources.Length + 1];
Array.Copy (sources, 0, newSources, 0, sources.Length);
newSources [sources.Length] = sourceData.Source;
logKey.SetValue ("Sources", newSources);
}
}
}
using (RegistryKey sourceKey = logKey.CreateSubKey (sourceData.Source)) {
UpdateSourceRegistry (sourceKey, sourceData);
}
}
} finally {
if (logKey != null)
logKey.Close ();
}
}
}
public override void Delete (string logName, string machineName)
{
using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
if (eventLogKey == null)
throw new InvalidOperationException ("The event log key does not exist.");
using (RegistryKey logKey = eventLogKey.OpenSubKey (logName, false)) {
if (logKey == null)
throw new InvalidOperationException (string.Format (
CultureInfo.InvariantCulture, "Event Log '{0}'"
+ " does not exist on computer '{1}'.", logName,
machineName));
// remove all eventlog entries for specified log
CoreEventLog.Clear ();
// remove file holding event log entries
string file = (string) logKey.GetValue ("File");
if (file != null) {
try {
File.Delete (file);
} catch (Exception) {
// .NET seems to ignore failures here
}
}
}
eventLogKey.DeleteSubKeyTree (logName);
}
}
public override void DeleteEventSource (string source, string machineName)
{
using (RegistryKey logKey = FindLogKeyBySource (source, machineName, true)) {
if (logKey == null) {
throw new ArgumentException (string.Format (
CultureInfo.InvariantCulture, "The source '{0}' is not"
+ " registered on computer '{1}'.", source, machineName));
}
logKey.DeleteSubKeyTree (source);
string [] sources = (string []) logKey.GetValue ("Sources");
if (sources != null) {
var temp = new List<string> ();
for (int i = 0; i < sources.Length; i++)
if (sources [i] != source)
temp.Add (sources [i]);
string [] newSources = temp.ToArray ();
logKey.SetValue ("Sources", newSources);
}
}
}
public override void Dispose (bool disposing)
{
Close ();
}
public override void EndInit ()
{
}
public override bool Exists (string logName, string machineName)
{
using (RegistryKey logKey = FindLogKeyByName (logName, machineName, false)) {
return (logKey != null);
}
}
[MonoTODO] // ParameterResourceFile ??
protected override string FormatMessage (string source, uint messageID, string [] replacementStrings)
{
string formattedMessage = null;
string [] msgResDlls = GetMessageResourceDlls (source, "EventMessageFile");
for (int i = 0; i < msgResDlls.Length; i++) {
formattedMessage = FetchMessage (msgResDlls [i],
messageID, replacementStrings);
if (formattedMessage != null)
break;
}
return formattedMessage != null ? formattedMessage : string.Join (
", ", replacementStrings);
}
private string FormatCategory (string source, int category)
{
string formattedCategory = null;
string [] msgResDlls = GetMessageResourceDlls (source, "CategoryMessageFile");
for (int i = 0; i < msgResDlls.Length; i++) {
formattedCategory = FetchMessage (msgResDlls [i],
(uint) category, new string [0]);
if (formattedCategory != null)
break;
}
return formattedCategory != null ? formattedCategory : "(" +
category.ToString (CultureInfo.InvariantCulture) + ")";
}
protected override int GetEntryCount ()
{
int entryCount = 0;
int retVal = PInvoke.GetNumberOfEventLogRecords (ReadHandle, ref entryCount);
if (retVal != 1)
throw new Win32Exception (Marshal.GetLastWin32Error ());
return entryCount;
}
protected override EventLogEntry GetEntry (int index)
{
// http://msdn.microsoft.com/library/en-us/eventlog/base/readeventlog.asp
// http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp
// http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html
index += OldestEventLogEntry;
int bytesRead = 0;
int minBufferNeeded = 0;
byte [] buffer = new byte [0x7ffff]; // according to MSDN this is the max size of the buffer
ReadEventLog (index, buffer, ref bytesRead, ref minBufferNeeded);
MemoryStream ms = new MemoryStream (buffer);
BinaryReader br = new BinaryReader (ms);
// skip first 8 bytes
br.ReadBytes (8);
int recordNumber = br.ReadInt32 (); // 8
int timeGeneratedSeconds = br.ReadInt32 (); // 12
int timeWrittenSeconds = br.ReadInt32 (); // 16
uint instanceID = br.ReadUInt32 ();
int eventID = EventLog.GetEventID (instanceID);
short eventType = br.ReadInt16 (); // 24
short numStrings = br.ReadInt16 (); ; // 26
short categoryNumber = br.ReadInt16 (); ; // 28
// skip reservedFlags
br.ReadInt16 (); // 30
// skip closingRecordNumber
br.ReadInt32 (); // 32
int stringOffset = br.ReadInt32 (); // 36
int userSidLength = br.ReadInt32 (); // 40
int userSidOffset = br.ReadInt32 (); // 44
int dataLength = br.ReadInt32 (); // 48
int dataOffset = br.ReadInt32 (); // 52
DateTime timeGenerated = new DateTime (1970, 1, 1).AddSeconds (
timeGeneratedSeconds);
DateTime timeWritten = new DateTime (1970, 1, 1).AddSeconds (
timeWrittenSeconds);
StringBuilder sb = new StringBuilder ();
while (br.PeekChar () != '\0')
sb.Append (br.ReadChar ());
br.ReadChar (); // skip the null-char
string sourceName = sb.ToString ();
sb.Length = 0;
while (br.PeekChar () != '\0')
sb.Append (br.ReadChar ());
br.ReadChar (); // skip the null-char
string machineName = sb.ToString ();
sb.Length = 0;
while (br.PeekChar () != '\0')
sb.Append (br.ReadChar ());
br.ReadChar (); // skip the null-char
string userName = null;
if (userSidLength != 0) {
// TODO: lazy init ?
ms.Position = userSidOffset;
byte [] sid = br.ReadBytes (userSidLength);
userName = LookupAccountSid (machineName, sid);
}
ms.Position = stringOffset;
string [] replacementStrings = new string [numStrings];
for (int i = 0; i < numStrings; i++) {
sb.Length = 0;
while (br.PeekChar () != '\0')
sb.Append (br.ReadChar ());
br.ReadChar (); // skip the null-char
replacementStrings [i] = sb.ToString ();
}
byte [] data = new byte [dataLength];
ms.Position = dataOffset;
br.Read (data, 0, dataLength);
// TODO: lazy fetch ??
string message = this.FormatMessage (sourceName, instanceID, replacementStrings);
string category = FormatCategory (sourceName, categoryNumber);
return new EventLogEntry (category, (short) categoryNumber, recordNumber,
eventID, sourceName, message, userName, machineName,
(EventLogEntryType) eventType, timeGenerated, timeWritten,
data, replacementStrings, instanceID);
}
[MonoTODO]
protected override string GetLogDisplayName ()
{
return CoreEventLog.Log;
}
protected override string [] GetLogNames (string machineName)
{
using (RegistryKey eventLogKey = GetEventLogKey (machineName, true)) {
if (eventLogKey == null)
return new string [0];
return eventLogKey.GetSubKeyNames ();
}
}
public override string LogNameFromSourceName (string source, string machineName)
{
using (RegistryKey logKey = FindLogKeyBySource (source, machineName, false)) {
if (logKey == null)
return string.Empty;
return GetLogName (logKey);
}
}
public override bool SourceExists (string source, string machineName)
{
RegistryKey logKey = FindLogKeyBySource (source, machineName, false);
if (logKey != null) {
logKey.Close ();
return true;
}
return false;
}
public override void WriteEntry (string [] replacementStrings, EventLogEntryType type, uint instanceID, short category, byte [] rawData)
{
IntPtr hEventLog = RegisterEventSource ();
try {
int ret = PInvoke.ReportEvent (hEventLog, (ushort) type,
(ushort) category, instanceID, IntPtr.Zero,
(ushort) replacementStrings.Length,
(uint) rawData.Length, replacementStrings, rawData);
if (ret != 1) {
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
} finally {
DeregisterEventSource (hEventLog);
}
}
private static void UpdateLogRegistry (RegistryKey logKey)
{
// TODO: write other Log values:
// - MaxSize
// - Retention
// - AutoBackupLogFiles
if (logKey.GetValue ("File") == null) {
string logName = GetLogName (logKey);
string file;
if (logName.Length > 8) {
file = logName.Substring (0, 8) + ".evt";
} else {
file = logName + ".evt";
}
string configPath = Path.Combine (Environment.GetFolderPath (
Environment.SpecialFolder.System), "config");
logKey.SetValue ("File", Path.Combine (configPath, file));
}
}
private static void UpdateSourceRegistry (RegistryKey sourceKey, EventSourceCreationData data)
{
if (data.CategoryCount > 0)
sourceKey.SetValue ("CategoryCount", data.CategoryCount);
if (data.CategoryResourceFile != null && data.CategoryResourceFile.Length > 0)
sourceKey.SetValue ("CategoryMessageFile", data.CategoryResourceFile);
if (data.MessageResourceFile != null && data.MessageResourceFile.Length > 0) {
sourceKey.SetValue ("EventMessageFile", data.MessageResourceFile);
} else {
// FIXME: write default once we have approval for shipping EventLogMessages.dll
}
if (data.ParameterResourceFile != null && data.ParameterResourceFile.Length > 0)
sourceKey.SetValue ("ParameterMessageFile", data.ParameterResourceFile);
}
private static string GetLogName (RegistryKey logKey)
{
string logName = logKey.Name;
return logName.Substring (logName.LastIndexOf ("\\") + 1);
}
private void ReadEventLog (int index, byte [] buffer, ref int bytesRead, ref int minBufferNeeded)
{
const int max_retries = 3;
// if the eventlog file changed since the handle was
// obtained, then we need to re-try multiple times
for (int i = 0; i < max_retries; i++) {
int ret = PInvoke.ReadEventLog (ReadHandle,
ReadFlags.Seek | ReadFlags.ForwardsRead,
index, buffer, buffer.Length, ref bytesRead,
ref minBufferNeeded);
if (ret != 1) {
int error = Marshal.GetLastWin32Error ();
if (i < (max_retries - 1)) {
CoreEventLog.Reset ();
} else {
throw new Win32Exception (error);
}
}
}
}
[MonoTODO ("Support remote machines")]
private static RegistryKey GetEventLogKey (string machineName, bool writable)
{
return Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Services\EventLog", writable);
}
private static RegistryKey FindSourceKeyByName (string source, string machineName, bool writable)
{
if (source == null || source.Length == 0)
return null;
RegistryKey eventLogKey = null;
try {
eventLogKey = GetEventLogKey (machineName, writable);
if (eventLogKey == null)
return null;
string [] subKeys = eventLogKey.GetSubKeyNames ();
for (int i = 0; i < subKeys.Length; i++) {
using (RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable)) {
if (logKey == null)
break;
RegistryKey sourceKey = logKey.OpenSubKey (source, writable);
if (sourceKey != null)
return sourceKey;
}
}
return null;
} finally {
if (eventLogKey != null)
eventLogKey.Close ();
}
}
private static RegistryKey FindLogKeyByName (string logName, string machineName, bool writable)
{
using (RegistryKey eventLogKey = GetEventLogKey (machineName, writable)) {
if (eventLogKey == null) {
return null;
}
return eventLogKey.OpenSubKey (logName, writable);
}
}
private static RegistryKey FindLogKeyBySource (string source, string machineName, bool writable)
{
if (source == null || source.Length == 0)
return null;
RegistryKey eventLogKey = null;
try {
eventLogKey = GetEventLogKey (machineName, writable);
if (eventLogKey == null)
return null;
string [] subKeys = eventLogKey.GetSubKeyNames ();
for (int i = 0; i < subKeys.Length; i++) {
RegistryKey sourceKey = null;
try {
RegistryKey logKey = eventLogKey.OpenSubKey (subKeys [i], writable);
if (logKey != null) {
sourceKey = logKey.OpenSubKey (source, writable);
if (sourceKey != null)
return logKey;
}
} finally {
if (sourceKey != null)
sourceKey.Close ();
}
}
return null;
} finally {
if (eventLogKey != null)
eventLogKey.Close ();
}
}
private int OldestEventLogEntry {
get {
int oldestEventLogEntry = 0;
int ret = PInvoke.GetOldestEventLogRecord (ReadHandle, ref oldestEventLogEntry);
if (ret != 1) {
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
return oldestEventLogEntry;
}
}
private void CloseEventLog (IntPtr hEventLog)
{
int ret = PInvoke.CloseEventLog (hEventLog);
if (ret != 1) {
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
}
private void DeregisterEventSource (IntPtr hEventLog)
{
int ret = PInvoke.DeregisterEventSource (hEventLog);
if (ret != 1) {
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
}
private static string LookupAccountSid (string machineName, byte [] sid)
{
// http://www.pinvoke.net/default.aspx/advapi32/LookupAccountSid.html
// http://msdn.microsoft.com/library/en-us/secauthz/security/lookupaccountsid.asp
StringBuilder name = new StringBuilder ();
uint cchName = (uint) name.Capacity;
StringBuilder referencedDomainName = new StringBuilder ();
uint cchReferencedDomainName = (uint) referencedDomainName.Capacity;
SidNameUse sidUse;
string accountName = null;
while (accountName == null) {
bool retOk = PInvoke.LookupAccountSid (machineName, sid, name, ref cchName,
referencedDomainName, ref cchReferencedDomainName,
out sidUse);
if (!retOk) {
int err = Marshal.GetLastWin32Error ();
if (err == PInvoke.ERROR_INSUFFICIENT_BUFFER) {
name.EnsureCapacity ((int) cchName);
referencedDomainName.EnsureCapacity ((int) cchReferencedDomainName);
} else {
// TODO: write warning ?
accountName = string.Empty;
}
} else {
accountName = string.Format ("{0}\\{1}", referencedDomainName.ToString (),
name.ToString ());
}
}
return accountName;
}
private static string FetchMessage (string msgDll, uint messageID, string [] replacementStrings)
{
// http://msdn.microsoft.com/library/en-us/debug/base/formatmessage.asp
// http://msdn.microsoft.com/msdnmag/issues/02/08/CQA/
// http://msdn.microsoft.com/netframework/programming/netcf/cffaq/default.aspx
IntPtr msgDllHandle = PInvoke.LoadLibraryEx (msgDll, IntPtr.Zero,
LoadFlags.LibraryAsDataFile);
if (msgDllHandle == IntPtr.Zero)
// TODO: write warning
return null;
IntPtr lpMsgBuf = IntPtr.Zero;
IntPtr [] arguments = new IntPtr [replacementStrings.Length];
try {
for (int i = 0; i < replacementStrings.Length; i++) {
arguments [i] = Marshal.StringToHGlobalAuto (
replacementStrings [i]);
}
int ret = PInvoke.FormatMessage (FormatMessageFlags.ArgumentArray |
FormatMessageFlags.FromHModule | FormatMessageFlags.AllocateBuffer,
msgDllHandle, messageID, 0, ref lpMsgBuf, 0, arguments);
if (ret != 0) {
string sRet = Marshal.PtrToStringAuto (lpMsgBuf);
lpMsgBuf = PInvoke.LocalFree (lpMsgBuf);
// remove trailing whitespace (CRLF)
return sRet.TrimEnd (null);
} else {
int err = Marshal.GetLastWin32Error ();
if (err == MESSAGE_NOT_FOUND) {
// do not consider this a failure (or even warning) as
// multiple message resource DLLs may have been configured
// and as such we just need to try the next library if
// the current one does not contain a message for this
// ID
} else {
// TODO: report warning
}
}
} finally {
// release unmanaged memory allocated for replacement strings
for (int i = 0; i < arguments.Length; i++) {
IntPtr argument = arguments [i];
if (argument != IntPtr.Zero)
Marshal.FreeHGlobal (argument);
}
PInvoke.FreeLibrary (msgDllHandle);
}
return null;
}
private string [] GetMessageResourceDlls (string source, string valueName)
{
// Some event sources (such as Userenv) have multiple message
// resource DLLs, delimited by a semicolon.
RegistryKey sourceKey = FindSourceKeyByName (source,
CoreEventLog.MachineName, false);
if (sourceKey != null) {
string value = sourceKey.GetValue (valueName) as string;
if (value != null) {
string [] msgResDlls = value.Split (';');
return msgResDlls;
}
}
return new string [0];
}
private IntPtr ReadHandle {
get {
if (_readHandle != IntPtr.Zero)
return _readHandle;
string logName = CoreEventLog.GetLogName ();
_readHandle = PInvoke.OpenEventLog (CoreEventLog.MachineName,
logName);
if (_readHandle == IntPtr.Zero)
throw new InvalidOperationException (string.Format (
CultureInfo.InvariantCulture, "Event Log '{0}' on computer"
+ " '{1}' cannot be opened.", logName, CoreEventLog.MachineName),
new Win32Exception ());
return _readHandle;
}
}
private IntPtr RegisterEventSource ()
{
IntPtr hEventLog = PInvoke.RegisterEventSource (
CoreEventLog.MachineName, CoreEventLog.Source);
if (hEventLog == IntPtr.Zero) {
throw new InvalidOperationException (string.Format (
CultureInfo.InvariantCulture, "Event source '{0}' on computer"
+ " '{1}' cannot be opened.", CoreEventLog.Source,
CoreEventLog.MachineName), new Win32Exception ());
}
return hEventLog;
}
public override void DisableNotification ()
{
lock (_eventLock) {
if (_notifyResetEvent != null) {
_notifyResetEvent.Close ();
_notifyResetEvent = null;
}
_notifyThread = null;
}
}
public override void EnableNotification ()
{
lock (_eventLock) {
if (_notifyResetEvent != null)
return;
_notifyResetEvent = new ManualResetEvent (false);
_lastEntryWritten = OldestEventLogEntry + EntryCount;
if (PInvoke.NotifyChangeEventLog (ReadHandle, _notifyResetEvent.SafeWaitHandle.DangerousGetHandle ()) == 0)
throw new InvalidOperationException (string.Format (
CultureInfo.InvariantCulture, "Unable to receive notifications"
+ " for log '{0}' on computer '{1}'.", CoreEventLog.GetLogName (),
CoreEventLog.MachineName), new Win32Exception ());
_notifyThread = new Thread (() => NotifyEventThread(_notifyResetEvent));
_notifyThread.IsBackground = true;
_notifyThread.Start ();
}
}
private void NotifyEventThread (ManualResetEvent resetEvent)
{
if (resetEvent == null)
return;
while (true) {
try {
resetEvent.WaitOne ();
} catch (ObjectDisposedException) {
// Notifications have been disabled and event
// has been closed but not yet nulled. End thread.
break;
}
lock (_eventLock) {
if (resetEvent != _notifyResetEvent) {
// A new thread has started with another reset event instance
// or DisableNotifications has been called, setting
// _notifyResetEvent to null. In both cases end this thread.
break;
}
if (_readHandle == IntPtr.Zero)
break;
int oldest_entry = OldestEventLogEntry;
if (_lastEntryWritten < oldest_entry)
_lastEntryWritten = oldest_entry;
int current_entry = _lastEntryWritten - oldest_entry;
int last_entry = EntryCount + oldest_entry;
for (int i = current_entry; i < (last_entry - 1); i++) {
EventLogEntry entry = GetEntry (i);
CoreEventLog.OnEntryWritten (entry);
}
_lastEntryWritten = last_entry;
}
}
}
public override OverflowAction OverflowAction {
get { throw new NotImplementedException (); }
}
public override int MinimumRetentionDays {
get { throw new NotImplementedException (); }
}
public override long MaximumKilobytes {
get { throw new NotImplementedException (); }
set { throw new NotImplementedException (); }
}
public override void ModifyOverflowPolicy (OverflowAction action, int retentionDays)
{
throw new NotImplementedException ();
}
public override void RegisterDisplayName (string resourceFile, long resourceId)
{
throw new NotImplementedException ();
}
private class PInvoke
{
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int ClearEventLog (IntPtr hEventLog, string lpBackupFileName);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int CloseEventLog (IntPtr hEventLog);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int DeregisterEventSource (IntPtr hEventLog);
[DllImport ("kernel32", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int FormatMessage (FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr [] arguments);
[DllImport ("kernel32", SetLastError=true)]
public static extern bool FreeLibrary (IntPtr hModule);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int GetNumberOfEventLogRecords (IntPtr hEventLog, ref int NumberOfRecords);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int GetOldestEventLogRecord (IntPtr hEventLog, ref int OldestRecord);
[DllImport ("kernel32", SetLastError=true)]
public static extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hFile, LoadFlags dwFlags);
[DllImport ("kernel32", SetLastError=true)]
public static extern IntPtr LocalFree (IntPtr hMem);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern bool LookupAccountSid (
string lpSystemName,
[MarshalAs (UnmanagedType.LPArray)] byte [] Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SidNameUse peUse);
[DllImport ("advapi32.dll", SetLastError = true)]
public static extern int NotifyChangeEventLog (IntPtr hEventLog, IntPtr hEvent);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern IntPtr OpenEventLog (string machineName, string logName);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern IntPtr RegisterEventSource (string machineName, string sourceName);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int ReportEvent (IntPtr hHandle, ushort wType,
ushort wCategory, uint dwEventID, IntPtr sid, ushort wNumStrings,
uint dwDataSize, string [] lpStrings, byte [] lpRawData);
[DllImport ("advapi32.dll", SetLastError=true)]
public static extern int ReadEventLog (IntPtr hEventLog, ReadFlags dwReadFlags, int dwRecordOffset, byte [] buffer, int nNumberOfBytesToRead, ref int pnBytesRead, ref int pnMinNumberOfBytesNeeded);
public const int ERROR_INSUFFICIENT_BUFFER = 122;
public const int ERROR_EVENTLOG_FILE_CHANGED = 1503;
}
private enum ReadFlags
{
Sequential = 0x001,
Seek = 0x002,
ForwardsRead = 0x004,
BackwardsRead = 0x008
}
private enum LoadFlags: uint
{
LibraryAsDataFile = 0x002
}
[Flags]
private enum FormatMessageFlags
{
AllocateBuffer = 0x100,
IgnoreInserts = 0x200,
FromHModule = 0x0800,
FromSystem = 0x1000,
ArgumentArray = 0x2000
}
private enum SidNameUse
{
User = 1,
Group,
Domain,
lias,
WellKnownGroup,
DeletedAccount,
Invalid,
Unknown,
Computer
}
}
}
// http://msdn.microsoft.com/library/en-us/eventlog/base/eventlogrecord_str.asp:
//
// struct EVENTLOGRECORD {
// int Length;
// int Reserved;
// int RecordNumber;
// int TimeGenerated;
// int TimeWritten;
// int EventID;
// short EventType;
// short NumStrings;
// short EventCategory;
// short ReservedFlags;
// int ClosingRecordNumber;
// int StringOffset;
// int UserSidLength;
// int UserSidOffset;
// int DataLength;
// int DataOffset;
// }
//
// http://www.whitehats.ca/main/members/Malik/malik_eventlogs/malik_eventlogs.html