Added event log unit tests and fixes for winbase.h functions.

pull/83/head
David Hall 2019-08-20 10:20:45 -06:00
parent 6e70fc0b19
commit 727021fea8
4 changed files with 207 additions and 34 deletions

View File

@ -7,30 +7,6 @@ namespace Vanara.PInvoke
{
public const uint ELF_LOG_SIGNATURE = 0x654c664c;
/// <summary>The status of the event log.</summary>
[PInvokeData("Winnt.h", MSDNShortId = "bb309024")]
[Flags]
public enum ELF_FLAGS
{
/// <summary>
/// Indicates that records have been written to an event log, but the event log file has not been properly closed. For more
/// information about this flag, see the Remarks section.
/// </summary>
ELF_LOGFILE_HEADER_DIRTY = 0x0001,
/// <summary>Indicates that records in the event log have wrapped.</summary>
ELF_LOGFILE_HEADER_WRAP = 0x0002,
/// <summary>Indicates that the most recent write attempt failed due to insufficient space.</summary>
ELF_LOGFILE_LOGFULL_WRITTEN = 0x0004,
/// <summary>
/// Indicates that the archive attribute has been set for the file. Normal file APIs can also be used to determine the value of
/// this flag.
/// </summary>
ELF_LOGFILE_ARCHIVE_SET = 0x0008,
}
/// <summary>Saves the specified event log to a backup file. The function does not clear the event log.</summary>
/// <param name="hEventLog">A handle to the open event log. The OpenEventLog function returns this handle.</param>
/// <param name="lpBackupFileName">The absolute or relative path of the backup file.</param>
@ -67,7 +43,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "b66896f6-baee-43c4-9d9b-5663c164d092")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ClearEventLog(HEVENTLOG hEventLog, string lpBackupFileName);
public static extern bool ClearEventLog(HEVENTLOG hEventLog, [Optional] string lpBackupFileName);
/// <summary>Closes the specified event log.</summary>
/// <param name="hEventLog">
@ -98,7 +74,20 @@ namespace Vanara.PInvoke
/// <summary>Retrieves information about the specified event log.</summary>
/// <param name="hEventLog">A handle to the event log. The OpenEventLog or RegisterEventSource function returns this handle.</param>
/// <param name="dwInfoLevel">The level of event log information to return.</param>
/// <param name="dwInfoLevel">
/// The level of event log information to return.
/// <para>This parameter can be the following value.</para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>EVENTLOG_FULL_INFO</term>
/// <term>Indicate whether the specified log is full. The lpBuffer parameter will contain an EVENTLOG_FULL_INFORMATION structure.</term>
/// </item>
/// </list>
/// </param>
/// <param name="lpBuffer">
/// An application-allocated buffer that receives the event log information. The format of this data depends on the value of the
/// dwInfoLevel parameter.
@ -112,7 +101,7 @@ namespace Vanara.PInvoke
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// </returns>
// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-geteventloginformation BOOL GetEventLogInformation( HANDLE
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-geteventloginformation BOOL GetEventLogInformation( HANDLE
// hEventLog, DWORD dwInfoLevel, LPVOID lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded );
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("winbase.h", MSDNShortId = "627e0af2-3ce6-47fe-89c6-d7c0483cb94b")]
@ -214,7 +203,7 @@ namespace Vanara.PInvoke
// lpUNCServerName, LPCSTR lpFileName );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "cfef0912-9d35-44aa-a1d3-f9bb37213ce0")]
public static extern SafeHEVENTLOG OpenBackupEventLog(string lpUNCServerName, string lpFileName);
public static extern SafeHEVENTLOG OpenBackupEventLog([Optional] string lpUNCServerName, string lpFileName);
/// <summary>Opens a handle to the specified event log.</summary>
/// <param name="lpUNCServerName">
@ -241,7 +230,7 @@ namespace Vanara.PInvoke
// lpUNCServerName, LPCSTR lpSourceName );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "6cd8797a-aeaf-4603-b43c-b1ff45b6200a")]
public static extern SafeHEVENTLOG OpenEventLog(string lpUNCServerName, string lpSourceName);
public static extern SafeHEVENTLOG OpenEventLog([Optional] string lpUNCServerName, string lpSourceName);
/// <summary>
/// Reads the specified number of entries from the specified event log. The function can be used to read log entries in chronological
@ -327,7 +316,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "10b37174-661a-4dc6-a7fe-752739494156")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadEventLog(HEVENTLOG hEventLog, uint dwReadFlags, uint dwRecordOffset, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint pnBytesRead, out uint pnMinNumberOfBytesNeeded);
public static extern bool ReadEventLog(HEVENTLOG hEventLog, EVENTLOG_READ dwReadFlags, uint dwRecordOffset, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint pnBytesRead, out uint pnMinNumberOfBytesNeeded);
/// <summary>
/// <para>Retrieves a registered handle to the specified event log.</para>
@ -367,7 +356,7 @@ namespace Vanara.PInvoke
// lpUNCServerName, LPCSTR lpSourceName );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "53706f83-6bc9-45d6-981c-bd0680d7bc08")]
public static extern SafeHEVENTSOURCE RegisterEventSource(string lpUNCServerName, string lpSourceName);
public static extern SafeHEVENTSOURCE RegisterEventSource([Optional] string lpUNCServerName, string lpSourceName);
/// <summary>Writes an entry at the end of the specified event log.</summary>
/// <param name="hEventLog">
@ -507,13 +496,13 @@ namespace Vanara.PInvoke
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("winbase.h", MSDNShortId = "e39273c3-9e42-41a1-9ec1-1cdff2ab7b55")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReportEvent(HEVENTLOG hEventLog, ushort wType, ushort wCategory, uint dwEventID, PSID lpUserSid, ushort wNumStrings, uint dwDataSize, ref string lpStrings, IntPtr lpRawData);
public static extern bool ReportEvent(HEVENTLOG hEventLog, EVENTLOG_TYPE wType, ushort wCategory, uint dwEventID, PSID lpUserSid, ushort wNumStrings, uint dwDataSize, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPTStr, SizeParamIndex = 5)] string[] lpStrings, IntPtr lpRawData);
/// <summary>Indicates whether the event log is full.</summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_eventlog_full_information typedef struct
// _EVENTLOG_FULL_INFORMATION { DWORD dwFull; } EVENTLOG_FULL_INFORMATION, *LPEVENTLOG_FULL_INFORMATION;
[PInvokeData("winbase.h", MSDNShortId = "3ca41d6b-51a6-4226-89be-ab2c37628289")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[StructLayout(LayoutKind.Sequential)]
public struct EVENTLOG_FULL_INFORMATION
{
/// <summary>Indicates whether the event log is full. If the log is full, this member is <c>TRUE</c>. Otherwise, it is <c>FALSE</c>.</summary>

View File

@ -116,6 +116,74 @@ namespace Vanara.PInvoke
CTMF_INCLUDE_LPAC = 0x00000002
}
/// <summary>The status of the event log.</summary>
[PInvokeData("Winnt.h", MSDNShortId = "bb309024")]
[Flags]
public enum ELF_FLAGS
{
/// <summary>
/// Indicates that records have been written to an event log, but the event log file has not been properly closed. For more
/// information about this flag, see the Remarks section.
/// </summary>
ELF_LOGFILE_HEADER_DIRTY = 0x0001,
/// <summary>Indicates that records in the event log have wrapped.</summary>
ELF_LOGFILE_HEADER_WRAP = 0x0002,
/// <summary>Indicates that the most recent write attempt failed due to insufficient space.</summary>
ELF_LOGFILE_LOGFULL_WRITTEN = 0x0004,
/// <summary>
/// Indicates that the archive attribute has been set for the file. Normal file APIs can also be used to determine the value of
/// this flag.
/// </summary>
ELF_LOGFILE_ARCHIVE_SET = 0x0008,
}
/// <summary>Indicate how to read the log file.</summary>
[PInvokeData("winnt.h", MSDNShortId = "53706f83-6bc9-45d6-981c-bd0680d7bc08")]
[Flags]
public enum EVENTLOG_READ
{
/// <summary>The eventlog sequential read</summary>
EVENTLOG_SEQUENTIAL_READ = 0x0001,
/// <summary>
/// Begin reading from the record specified in the dwRecordOffset parameter. This option may not work with large log files if the
/// function cannot determine the log file's size. For details, see Knowledge Base article, 177199.
/// </summary>
EVENTLOG_SEEK_READ = 0x0002,
/// <summary>The log is read in chronological order (oldest to newest).</summary>
EVENTLOG_FORWARDS_READ = 0x0004,
/// <summary>The log is read in reverse chronological order (newest to oldest).</summary>
EVENTLOG_BACKWARDS_READ = 0x0008,
}
/// <summary>The type of event to be logged.</summary>
[PInvokeData("winnt.h", MSDNShortId = "e39273c3-9e42-41a1-9ec1-1cdff2ab7b55")]
public enum EVENTLOG_TYPE : ushort
{
/// <summary>Information event</summary>
EVENTLOG_SUCCESS = 0x0000,
/// <summary>Error event</summary>
EVENTLOG_ERROR_TYPE = 0x0001,
/// <summary>Warning event</summary>
EVENTLOG_WARNING_TYPE = 0x0002,
/// <summary>Information event</summary>
EVENTLOG_INFORMATION_TYPE = 0x0004,
/// <summary>Success Audit event</summary>
EVENTLOG_AUDIT_SUCCESS = 0x0008,
/// <summary>Failure Audit event</summary>
EVENTLOG_AUDIT_FAILURE = 0x0010,
}
/// <summary>Group attributes.</summary>
[Flags]
[PInvokeData("winnt.h")]
@ -2809,7 +2877,7 @@ namespace Vanara.PInvoke
/// </list>
/// <para>For more information, see Event Types.</para>
/// </summary>
public ushort EventType;
public EVENTLOG_TYPE EventType;
/// <summary>
/// The number of strings present in the log (at the position indicated by <c>StringOffset</c>). These strings are merged into

View File

@ -0,0 +1,115 @@
using NUnit.Framework;
using System;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke.Tests
{
[TestFixture()]
public class WinBase_EventLogTests
{
private const string eventLogName = @"C:\Temp\Test.log";
[Test]
public void OpenBackupClearCloseEventLogTest()
{
using (var hEL = OpenEventLog(null, eventLogName))
using (var tmp = new TempFile(null))
{
Assert.That(hEL, ResultIs.ValidHandle);
Assert.That(BackupEventLog(hEL, tmp.FullName), ResultIs.Successful);
using (var hBEL = OpenBackupEventLog(null, tmp.FullName))
Assert.That(hBEL, ResultIs.ValidHandle);
using (var hBEL = OpenEventLog(null, tmp.FullName))
{
Assert.That(hBEL, ResultIs.ValidHandle);
Assert.That(ClearEventLog(hBEL, null), ResultIs.Successful);
}
}
}
[Test]
public void RegisterEventSourceTest()
{
using (var hES = RegisterEventSource(null, "TestSource"))
{
Assert.That(hES, ResultIs.ValidHandle);
using (var mem = SafeHGlobalHandle.CreateFromStructure<EVENTLOG_FULL_INFORMATION>())
{
Assert.That(GetEventLogInformation(hES, 0, mem, mem.Size, out var req), ResultIs.Successful);
mem.ToStructure<EVENTLOG_FULL_INFORMATION>().WriteValues();
}
}
}
[Test]
public void GetEventLogInformationTest()
{
using (var hEL = OpenEventLog(null, eventLogName))
using (var mem = SafeHGlobalHandle.CreateFromStructure<EVENTLOG_FULL_INFORMATION>())
{
Assert.That(GetEventLogInformation(hEL, 0, mem, mem.Size, out var req), ResultIs.Successful);
mem.ToStructure<EVENTLOG_FULL_INFORMATION>().WriteValues();
}
}
[Test]
public void GetNumberOfEventLogRecordsTest()
{
using (var hEL = OpenEventLog(null, eventLogName))
{
Assert.That(GetNumberOfEventLogRecords(hEL, out var numRec), ResultIs.Successful);
Assert.That(numRec, Is.GreaterThan(0));
TestContext.Write(numRec);
}
}
[Test]
public void GetOldestEventLogRecordTest()
{
using (var hEL = OpenEventLog(null, eventLogName))
{
Assert.That(GetOldestEventLogRecord(hEL, out var oldRec), ResultIs.Successful);
Assert.That(oldRec, Is.GreaterThan(0));
TestContext.Write(oldRec);
}
}
[Test]
public void NotifyChangeEventLogTest()
{
using (var hEvent = CreateEvent(null, false, false, null))
using (var hEL = OpenEventLog(null, eventLogName))
{
Assert.That(GetNumberOfEventLogRecords(hEL, out var numRec), ResultIs.Successful);
var t = new System.Threading.Thread(ThreadProc);
t.Start(((HEVENTLOG)hEL, hEvent));
System.Threading.Thread.Sleep(100);
Assert.That(ReportEvent(hEL, EVENTLOG_TYPE.EVENTLOG_INFORMATION_TYPE, 5, 5, SafePSID.Current, 2, 0, new[] { "Testing", "1, 2, 3" }, default), ResultIs.Successful);
while (t.IsAlive)
{
System.Threading.Thread.Sleep(100);
}
Assert.That(GetNumberOfEventLogRecords(hEL, out var numRec2), ResultIs.Successful);
Assert.That(numRec2, Is.GreaterThan(numRec));
using (var mem = new SafeHGlobalHandle(4096))
{
Assert.That(ReadEventLog(hEL, EVENTLOG_READ.EVENTLOG_BACKWARDS_READ | EVENTLOG_READ.EVENTLOG_SEQUENTIAL_READ, 0, mem, mem.Size, out var read, out var minReq), ResultIs.Successful);
var hdr = mem.ToStructure<EVENTLOGRECORD>();
Assert.That(hdr.EventType, Is.EqualTo(EVENTLOG_TYPE.EVENTLOG_INFORMATION_TYPE));
}
}
void ThreadProc(object obj)
{
var (hLog, hEvent) = ((HEVENTLOG hLog, SafeEventHandle hEvent))obj;
Assert.That(NotifyChangeEventLog(hLog, hEvent), ResultIs.Successful);
WaitForSingleObject(hEvent, 0);
}
}
}
}

View File

@ -45,6 +45,7 @@
<Compile Include="AdvApi32\EventRecordEventArgs.cs" />
<Compile Include="AdvApi32\EventTraceController.cs" />
<Compile Include="AdvApi32\EventTraceLogs.cs" />
<Compile Include="AdvApi32\WinBase_EventLogTests.cs" />
<Compile Include="AdvApi32\WinBaseTests.cs" />
<Compile Include="AdvApi32\wctTests.cs" />
<Compile Include="AdvApi32\EvnTraceTests.cs" />