Completed unit tests and updates for pdh.dll

pull/83/head
David Hall 2019-09-05 15:32:41 -06:00
parent bc632c48ab
commit c3ee660228
2 changed files with 300 additions and 44 deletions

View File

@ -792,6 +792,31 @@ namespace Vanara.PInvoke
[PInvokeData("pdh.h", MSDNShortId = "eaed9b28-eb09-4123-9317-5d3d50e2d77a")]
public static extern Win32Error PdhBindInputDataSource(out SafePDH_HLOG phDataSource, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[] LogFileNameList);
/// <summary>Binds one or more binary log files together for reading log data.</summary>
/// <param name="LogFileNameList">
/// <para>
/// One or more binary log files to bind together. The log file names can contain absolute or relative paths. You cannot specify more
/// than 32 log files.
/// </para>
/// <para>If <c>NULL</c>, the source is a real-time data source.</para>
/// </param>
/// <returns>Handle to the bound data sources.</returns>
/// <remarks>
/// <para>
/// This function is used with the PDH functions that require a handle to a data source. For a list of these functions, see See Also.
/// </para>
/// <para>
/// You cannot specify more than one comma-delimited (CSV) or tab-delimited (TSV) file. The list can contain only one type of
/// file—you cannot combine multiple file types.
/// </para>
/// </remarks>
[PInvokeData("pdh.h", MSDNShortId = "eaed9b28-eb09-4123-9317-5d3d50e2d77a")]
public static SafePDH_HLOG PdhBindInputDataSource(params string[] LogFileNameList)
{
var err = PdhBindInputDataSource(out var hLog, LogFileNameList is null || LogFileNameList.Length == 0 ? null : LogFileNameList);
return err.Succeeded ? hLog : throw err.GetException();
}
/// <summary>
/// <para>
/// Displays a <c>Browse Counters</c> dialog box that the user can use to select one or more counters that they want to add to the query.
@ -3835,7 +3860,7 @@ namespace Vanara.PInvoke
// dwAccessFlags, LPDWORD lpdwLogType, PDH_HQUERY hQuery, DWORD dwMaxSize, LPCSTR szUserCaption, PDH_HLOG *phLog );
[DllImport(Lib.Pdh, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("pdh.h", MSDNShortId = "a8457959-af3a-497f-91ca-0876cbb552cc")]
public static extern Win32Error PdhOpenLog(string szLogFileName, PdhLogAccess dwAccessFlags, ref PDH_LOG_TYPE lpdwLogType, [Optional] PDH_HQUERY hQuery, uint dwMaxSize, [Optional] string szUserCaption, out SafePDH_HLOG phLog);
public static extern Win32Error PdhOpenLog(string szLogFileName, PdhLogAccess dwAccessFlags, ref PDH_LOG_TYPE lpdwLogType, [Optional] PDH_HQUERY hQuery, [Optional] uint dwMaxSize, [Optional] string szUserCaption, out SafePDH_HLOG phLog);
/// <summary>
/// <para>Creates a new query that is used to manage the collection of performance data.</para>
@ -4704,10 +4729,10 @@ namespace Vanara.PInvoke
/// of this parameter is PDH_MIN_SCALE (7) (the returned value is the actual value times 10⁷) to PDH_MAX_SCALE (+7) (the
/// returned value is the actual value times 10⁺⁷). A value of zero will set the scale to one, so that the actual value is returned
/// </summary>
public int lScale;
public long lScale;
/// <summary>Default scale factor as suggested by the counter's provider.</summary>
public int lDefaultScale;
public long lDefaultScale;
/// <summary>The value passed in the dwUserData parameter when calling PdhAddCounter.</summary>
public IntPtr dwUserData;
@ -4716,46 +4741,40 @@ namespace Vanara.PInvoke
public IntPtr dwQueryUserData;
/// <summary><c>Null</c>-terminated string that specifies the full counter path. The string follows this structure in memory.</summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szFullPath;
/// <summary>A PDH_DATA_ITEM_PATH_ELEMENTS structure. Not used.</summary>
public PDH_DATA_ITEM_PATH_ELEMENTS DataItemPath;
/// <summary>A PDH_COUNTER_PATH_ELEMENTS structure.</summary>
public PDH_COUNTER_PATH_ELEMENTS CounterPath;
public StrPtrAuto szFullPath;
/// <summary>
/// <c>Null</c>-terminated string that contains the name of the computer specified in the counter path. Is <c>NULL</c>, if the
/// path does not specify a computer. The string follows this structure in memory.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szMachineName;
public StrPtrAuto szMachineName;
/// <summary>
/// <c>Null</c>-terminated string that contains the name of the performance object specified in the counter path. The string
/// follows this structure in memory.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szObjectName;
public StrPtrAuto szObjectName;
/// <summary>
/// <c>Null</c>-terminated string that contains the name of the object instance specified in the counter path. Is <c>NULL</c>, if
/// the path does not specify an instance. The string follows this structure in memory.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szInstanceName;
public StrPtrAuto szInstanceName;
/// <summary>
/// <c>Null</c>-terminated string that contains the name of the parent instance specified in the counter path. Is <c>NULL</c>, if
/// the path does not specify a parent instance. The string follows this structure in memory.
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szParentInstance;
public StrPtrAuto szParentInstance;
/// <summary>Instance index specified in the counter path. Is 0, if the path does not specify an instance index.</summary>
public uint dwInstanceIndex;
/// <summary><c>Null</c>-terminated string that contains the counter name. The string follows this structure in memory.</summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szCounterName;
public StrPtrAuto szCounterName;
/// <summary>Help text that describes the counter. Is <c>NULL</c> if the source is a log file.</summary>
[MarshalAs(UnmanagedType.LPTStr)] public string szExplainText;
public StrPtrAuto szExplainText;
/// <summary>Start of the string data that is appended to the structure.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
@ -4826,7 +4845,7 @@ namespace Vanara.PInvoke
// CStatus; union { LONG longValue; double doubleValue; LONGLONG largeValue; LPCSTR AnsiStringValue; LPCWSTR WideStringValue; }; }
// PDH_FMT_COUNTERVALUE, *PPDH_FMT_COUNTERVALUE;
[PInvokeData("pdh.h", MSDNShortId = "68ccd722-94d2-4610-ba64-f51318f5436e")]
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PDH_FMT_COUNTERVALUE
{
/// <summary>
@ -4834,26 +4853,26 @@ namespace Vanara.PInvoke
/// displaying its value. For a list of possible values, see Checking PDH Interface Return Values.
/// </summary>
[FieldOffset(0)]
public uint CStatus;
public Win32Error CStatus;
/// <summary>The computed counter value as a <c>LONG</c>.</summary>
[FieldOffset(0)]
[FieldOffset(8)]
public int longValue;
/// <summary>The computed counter value as a <c>DOUBLE</c>.</summary>
[FieldOffset(0)]
[FieldOffset(8)]
public double doubleValue;
/// <summary>The computed counter value as a <c>LONGLONG</c>.</summary>
[FieldOffset(0)]
[FieldOffset(8)]
public long largeValue;
/// <summary>The computed counter value as a <c>LPCSTR</c>. Not supported.</summary>
[FieldOffset(0)]
[FieldOffset(8)]
public StrPtrAnsi AnsiStringValue;
/// <summary>The computed counter value as a <c>LPCWSTR</c>. Not supported.</summary>
[FieldOffset(0)]
[FieldOffset(8)]
public StrPtrUni WideStringValue;
}
@ -5116,10 +5135,9 @@ namespace Vanara.PInvoke
/// <summary>Size of the <c>RawBytes</c> data.</summary>
public uint dwItems;
private byte _RawBytes;
/// <summary>Binary record.</summary>
public byte[] RawBytes => StructHelper.FieldToArray(ref _RawBytes, (int)dwItems);
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] RawBytes;
}
/// <summary>
@ -5132,7 +5150,7 @@ namespace Vanara.PInvoke
public struct PDH_STATISTICS
{
/// <summary>Format of the data. The format is specified in the dwFormat when calling PdhComputeCounterStatistics.</summary>
public uint dwFormat;
public PDH_FMT dwFormat;
/// <summary>Number of values in the array.</summary>
public uint count;
@ -5153,7 +5171,7 @@ namespace Vanara.PInvoke
// https://docs.microsoft.com/en-us/windows/win32/api/pdh/ns-pdh-pdh_time_info typedef struct _PDH_TIME_INFO { LONGLONG StartTime;
// LONGLONG EndTime; DWORD SampleCount; } PDH_TIME_INFO, *PPDH_TIME_INFO;
[PInvokeData("pdh.h", MSDNShortId = "a747f288-8d6c-401c-a927-a61ffea3d423")]
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential, Size = 24)]
public struct PDH_TIME_INFO
{
/// <summary>Starting time of the sample interval, in local FILETIME format.</summary>

View File

@ -1,6 +1,8 @@
using NUnit.Framework;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Vanara.Extensions;
using Vanara.InteropServices;
@ -11,9 +13,9 @@ namespace Vanara.PInvoke.Tests
[TestFixture]
public class PdhTests
{
private const string counterPath = "\\Processor(0)\\% Processor Time";
private const string dsn = "Test";
private const string logFile = @"C:\Temp\TestLogFile.etl";
private const string counterPath = @"\Processor(0)\% Processor Time";
private const string dsn = "TestSet";
private const string logFile = @"C:\PerfLogs\Admin\TestSet\System Monitor Log.blg";
[Test]
public void BrowsePerfCountersTest()
@ -65,8 +67,8 @@ namespace Vanara.PInvoke.Tests
[Test]
public void PdhBindInputDataSourceTest()
{
throw new NotImplementedException();
//Assert.That(PdhBindInputDataSource(), ResultIs.Successful);
Assert.That(PdhBindInputDataSource(out var hLog, new[] { logFile }), ResultIs.Successful);
hLog.Dispose();
}
[Test]
@ -87,10 +89,6 @@ namespace Vanara.PInvoke.Tests
Assert.That(PdhCollectQueryDataEx(Query, 0, evt), ResultIs.Successful);
evt.WaitOne(100);
}
// Compute a displayable value for the counter.
Assert.That(PdhGetFormattedCounterValue(Counter, PDH_FMT.PDH_FMT_DOUBLE, out var CounterType, out var DisplayValue), ResultIs.Successful);
TestContext.WriteLine($",\"{DisplayValue.doubleValue}\"");
}
}
}
@ -135,7 +133,7 @@ namespace Vanara.PInvoke.Tests
Assert.That(PdhCalculateCounterFromRawValue(Counter, PDH_FMT.PDH_FMT_LONG, rawCounter1, rawCounter2, out var fmtValue), ResultIs.Successful);
TestContext.WriteLine($"{fmtValue.longValue}");
//Assert.That(PdhFormatFromRawValue(CounterType.PERF_100NSEC_TIMER)
Assert.That(PdhFormatFromRawValue(type, PDH_FMT.PDH_FMT_LONG, ft2, rawCounter1, rawCounter2, out fmtValue), ResultIs.Successful);
}
}
}
@ -150,9 +148,10 @@ namespace Vanara.PInvoke.Tests
Assert.That(PdhAddCounter(Query, counterPath, default, out var Counter), ResultIs.Successful);
using (Counter)
{
var first = 0U;
var values = new PDH_RAW_COUNTER[] { };
Assert.That(PdhComputeCounterStatistics(Counter, PDH_FMT.PDH_FMT_LONG, first, (uint)values.Length, values, out var stats), ResultIs.Failure);
Assert.That(PdhGetRawCounterValue(Counter, out var type, out var rawCounter), ResultIs.Successful);
var values = new PDH_RAW_COUNTER[] { rawCounter };
Assert.That(PdhComputeCounterStatistics(Counter, PDH_FMT.PDH_FMT_LONG, 0, (uint)values.Length, values, out var stats), ResultIs.Successful);
stats.WriteValues();
}
}
}
@ -253,6 +252,13 @@ namespace Vanara.PInvoke.Tests
TestContext.WriteLine(string.Join("\n", strs));
}
[Test]
public void PdhExpandWildCardPathHTest()
{
Assert.That(CallMethodWithStrings((IntPtr p, ref uint sz) => PdhExpandWildCardPathH(default, @"\Process(*)\ID Process", p, ref sz, 0), out var strs), ResultIs.Successful);
TestContext.WriteLine(string.Join("\n", strs));
}
[Test]
public void PdhExpandWildCardPathTest()
{
@ -261,10 +267,228 @@ namespace Vanara.PInvoke.Tests
}
[Test]
public void PdhExpandWildCardPathHTest()
public void PdhGetCounterInfoTest()
{
Assert.That(CallMethodWithStrings((IntPtr p, ref uint sz) => PdhExpandWildCardPathH(default, @"\Process(*)\ID Process", p, ref sz, 0), out var strs), ResultIs.Successful);
TestContext.WriteLine(string.Join("\n", strs));
Assert.That(PdhOpenQuery(null, default, out var Query), ResultIs.Successful);
using (Query)
{
// Add the selected counter to the query.
Assert.That(PdhAddCounter(Query, counterPath, default, out var Counter), ResultIs.Successful);
using (Counter)
{
Assert.That(PdhSetCounterScaleFactor(Counter, 1), ResultIs.Successful);
uint sz = 0;
Assert.That(PdhGetCounterInfo(Counter, true, ref sz, default), ResultIs.FailureCode(Win32Error.PDH_MORE_DATA));
using (var buffer = new SafeHGlobalHandle(sz))
{
Assert.That(PdhGetCounterInfo(Counter, true, ref sz, buffer), ResultIs.Successful);
buffer.ToStructure<PDH_COUNTER_INFO>().WriteValues();
}
}
}
}
[Test]
public void PdhGetCounterTimeBaseTest()
{
Assert.That(PdhOpenQuery(null, default, out var Query), ResultIs.Successful);
using (Query)
{
// Add the selected counter to the query.
Assert.That(PdhAddCounter(Query, counterPath, default, out var Counter), ResultIs.Successful);
using (Counter)
{
Assert.That(PdhGetCounterTimeBase(Counter, out var ft), ResultIs.Successful);
TestContext.Write(ft.ToString("U"));
}
}
}
[Test]
public void PdhGetDataSourceTimeRangeHTest()
{
Assert.That(PdhBindInputDataSource(out var hLog, new[] { logFile }), ResultIs.Successful);
using (hLog)
{
uint sz = (uint)Marshal.SizeOf<PDH_TIME_INFO>();
Assert.That(PdhGetDataSourceTimeRangeH(hLog, out var cnt, out var info, ref sz), ResultIs.Successful);
Assert.That(cnt, Is.EqualTo(1));
info.WriteValues();
}
}
[Test]
public void PdhGetDataSourceTimeRangeTest()
{
uint sz = (uint)Marshal.SizeOf<PDH_TIME_INFO>();
Assert.That(PdhGetDataSourceTimeRange(logFile, out var cnt, out var info, ref sz), ResultIs.Successful);
Assert.That(cnt, Is.EqualTo(1));
info.WriteValues();
}
[Test]
public void PdhGetDefaultPerfCounterObjectHTest()
{
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(PdhGetDefaultPerfObjectH(PDH_HLOG.NULL, null, sb, ref sz), ResultIs.Successful);
TestContext.WriteLine($"DefObj: {sb}");
sz = (uint)sb.Capacity;
var obj = sb.ToString();
Assert.That(PdhGetDefaultPerfCounterH(PDH_HLOG.NULL, null, obj, sb, ref sz), ResultIs.Successful);
TestContext.WriteLine($"DefCntr: {sb}");
}
[Test]
public void PdhGetDefaultPerfCounterObjectTest()
{
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(PdhGetDefaultPerfObject(null, null, sb, ref sz), ResultIs.Successful);
TestContext.WriteLine($"DefObj: {sb}");
sz = (uint)sb.Capacity;
var obj = sb.ToString();
Assert.That(PdhGetDefaultPerfCounter(null, null, obj, sb, ref sz), ResultIs.Successful);
TestContext.WriteLine($"DefCntr: {sb}");
}
[Test]
public void PdhGetDllVersionTest()
{
Assert.That(PdhGetDllVersion(out var ver), ResultIs.Successful);
TestContext.Write(ver);
}
[Test]
public void PdhGetFormattedRawCounterArrayTest()
{
Assert.That(PdhOpenQuery(null, default, out var Query), ResultIs.Successful);
using (Query)
{
// Add the selected counter to the query.
Assert.That(PdhAddCounter(Query, counterPath.Replace("(0)", "(*)"), default, out var Counter), ResultIs.Successful);
using (Counter)
{
Assert.That(PdhCollectQueryData(Query), ResultIs.Successful);
Assert.That(PdhCollectQueryData(Query), ResultIs.Successful);
// Compute a displayable value for the counter.
using (var mem = new SafeHGlobalHandle(4096))
{
var sz = (uint)mem.Size;
Assert.That(PdhGetFormattedCounterArray(Counter, PDH_FMT.PDH_FMT_DOUBLE, ref sz, out var n, mem), ResultIs.Successful);
mem.ToArray<PDH_FMT_COUNTERVALUE_ITEM>((int)n).WriteValues();
TestContext.WriteLine("===============================");
sz = (uint)mem.Size;
Assert.That(PdhGetRawCounterArray(Counter, ref sz, out n, mem), ResultIs.Successful);
mem.ToArray<PDH_RAW_COUNTER_ITEM>((int)n).WriteValues();
}
}
}
}
[Test]
public void PdhGetLogFileSizeTest()
{
var type = PDH_LOG_TYPE.PDH_LOG_TYPE_UNDEFINED;
Assert.That(PdhOpenLog(logFile, PdhLogAccess.PDH_LOG_READ_ACCESS | PdhLogAccess.PDH_LOG_OPEN_EXISTING, ref type, phLog: out var hlog), ResultIs.Successful);
using (hlog)
{
Assert.That(PdhGetLogFileSize(hlog, out var sz), ResultIs.Successful);
TestContext.Write(sz);
}
}
[Test]
public void PdhLookupPerfNameByIndexTest()
{
var name = "Cache";
Assert.That(PdhLookupPerfIndexByName(null, name, out var idx), ResultIs.Successful);
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(PdhLookupPerfNameByIndex(null, idx, sb, ref sz), ResultIs.Successful);
Assert.That(name, Is.EqualTo(sb.ToString()));
}
[Test]
public void PdhMakeCounterPathTest()
{
var e = new PDH_COUNTER_PATH_ELEMENTS { szObjectName = "Processor", szInstanceName = "1", szCounterName = "% Processor Time" };
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(PdhMakeCounterPath(e, sb, ref sz, 0, Kernel32.GetSystemDefaultLangID()), ResultIs.Successful);
TestContext.Write(sb);
}
[Test]
public void PdhParseCounterPathTest()
{
using (var mem = new SafeCoTaskMemHandle(1024))
{
uint sz = mem.Size;
Assert.That(PdhParseCounterPath(counterPath, mem, ref sz), ResultIs.Successful);
mem.ToStructure<PDH_COUNTER_PATH_ELEMENTS>().WriteValues();
}
}
[Test]
public void PdhParseInstanceNameTest()
{
var sz1 = 1024U;
var sb1 = new StringBuilder((int)sz1);
var sz2 = 1024U;
var sb2 = new StringBuilder((int)sz2);
Assert.That(PdhParseInstanceName("dog/cat#1", sb1, ref sz1, sb2, ref sz2, out var idx), ResultIs.Successful);
Assert.That(sb2.ToString(), Is.EqualTo("dog"));
Assert.That(idx, Is.EqualTo(1));
}
[Test]
public void PdhReadRawLogRecordTest()
{
using (var hlog = PdhBindInputDataSource(logFile))
using (var mem = new SafeCoTaskMemHandle(1024))
{
uint sz = (uint)Marshal.SizeOf<PDH_TIME_INFO>();
Assert.That(PdhGetDataSourceTimeRangeH(hlog, out var cnt, out var info, ref sz), ResultIs.Successful);
TestContext.WriteLine($"Start:{info.StartTime.ToString("U")}; End:{info.EndTime.ToString("U")}; Cnt:{info.SampleCount}");
sz = mem.Size;
// TODO: Can't get this to return anything but PDH_ENTRY_NOT_IN_LOG_FILE
Assert.That(PdhReadRawLogRecord(hlog, info.StartTime, mem, ref sz), ResultIs.FailureCode(Win32Error.PDH_ENTRY_NOT_IN_LOG_FILE));
//var rec = mem.ToStructure<PDH_RAW_LOG_RECORD>();
//rec.WriteValues();
//TestContext.Write(mem.ToArray<byte>((int)rec.dwItems, 12).ToHexString((int)rec.dwItems));
}
}
[Test]
public void PdhSelectDataSourceTest()
{
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(PdhSelectDataSource(default, PdhSelectDataSourceFlags.Default, sb, ref sz), ResultIs.Successful);
}
[Test]
public void PdhSetQueryTimeRangeTest()
{
using (var hlog = PdhBindInputDataSource(logFile))
{
uint sz = (uint)Marshal.SizeOf<PDH_TIME_INFO>();
Assert.That(PdhGetDataSourceTimeRangeH(hlog, out var cnt, out var info, ref sz), ResultIs.Successful);
Assert.That(PdhOpenQueryH(hlog, default, out var Query), ResultIs.Successful);
using (Query)
Assert.That(PdhSetQueryTimeRange(Query, info), ResultIs.Successful);
}
}
[Test]
@ -275,6 +499,8 @@ namespace Vanara.PInvoke.Tests
using (var tmp = new TempFile(null))
using (hQuery)
{
Assert.That(PdhIsRealTimeQuery(hQuery), Is.True);
// Add one counter that will provide the data.
Assert.That(PdhAddEnglishCounter(hQuery, counterPath, default, out var hCounter), ResultIs.Successful);
@ -286,6 +512,18 @@ namespace Vanara.PInvoke.Tests
}
}
[Test]
public void PdhValidatePathExWTest()
{
Assert.That(PdhValidatePathExW(PDH_HLOG.NULL, counterPath), ResultIs.Successful);
}
[Test]
public void PdhValidatePathTest()
{
Assert.That(PdhValidatePath(counterPath), ResultIs.Successful);
}
private static Win32Error CallMethodWithStrings(FunctionHelper.PtrFunc<uint> method, out string[] result)
{
var sz = 0U;