mirror of https://github.com/dahall/Vanara.git
Updated SafeMoveableHGlobalHandle class and added tests.
parent
7c0c7fe66c
commit
63203f558e
|
@ -5,91 +5,95 @@ using System.Runtime.InteropServices;
|
|||
using Vanara.Extensions;
|
||||
using Vanara.InteropServices;
|
||||
|
||||
namespace Vanara.PInvoke
|
||||
namespace Vanara.PInvoke;
|
||||
|
||||
public static partial class Kernel32
|
||||
{
|
||||
public static partial class Kernel32
|
||||
/// <summary>A <see cref="SafeHandle"/> for memory allocated as moveable HGLOBAL.</summary>
|
||||
/// <seealso cref="SafeHandle"/>
|
||||
public class SafeMoveableHGlobalHandle : SafeMemoryHandleExt<MoveableHGlobalMemoryMethods>
|
||||
{
|
||||
/// <summary>A <see cref="SafeHandle"/> for memory allocated as moveable HGLOBAL.</summary>
|
||||
/// <seealso cref="SafeHandle"/>
|
||||
public class SafeMoveableHGlobalHandle : SafeMemoryHandleExt<MoveableHGlobalMemoryMethods>
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
/// <param name="handle">The handle.</param>
|
||||
/// <param name="ownsHandle">if set to <c>true</c> if this class is responsible for freeing the memory on disposal.</param>
|
||||
public SafeMoveableHGlobalHandle(IntPtr handle, bool ownsHandle = true) : base(handle, handle == default ? 0 : GlobalSize(handle), ownsHandle) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
/// <param name="size">The size of memory to allocate, in bytes.</param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">size - The value of this argument must be non-negative</exception>
|
||||
public SafeMoveableHGlobalHandle(SizeT size) : base(size) { }
|
||||
|
||||
/// <summary>
|
||||
/// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native
|
||||
/// array equivalent.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Array of unmanaged pointers</param>
|
||||
/// <returns>SafeMoveableHGlobalHandle object to an native (unmanaged) array of pointers</returns>
|
||||
public SafeMoveableHGlobalHandle(byte[] bytes) : base(bytes?.Length ?? 0)
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
/// <param name="handle">The handle.</param>
|
||||
/// <param name="ownsHandle">if set to <c>true</c> if this class is responsible for freeing the memory on disposal.</param>
|
||||
public SafeMoveableHGlobalHandle(IntPtr handle, bool ownsHandle = true) : base(handle, handle == default ? 0 : GlobalSize(handle), ownsHandle) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
/// <param name="size">The size of memory to allocate, in bytes.</param>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">size - The value of this argument must be non-negative</exception>
|
||||
public SafeMoveableHGlobalHandle(SizeT size) : base(size) { }
|
||||
|
||||
/// <summary>
|
||||
/// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native
|
||||
/// array equivalent.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Array of unmanaged pointers</param>
|
||||
/// <returns>SafeMoveableHGlobalHandle object to an native (unmanaged) array of pointers</returns>
|
||||
public SafeMoveableHGlobalHandle(byte[] bytes) : base(bytes?.Length ?? 0)
|
||||
{
|
||||
if (Size == 0) return;
|
||||
CallLocked(p => Marshal.Copy(bytes, 0, p, sz));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class from a <see cref="SafeAllocatedMemoryHandle"/>
|
||||
/// instance, copying all the memory.
|
||||
/// </summary>
|
||||
/// <param name="source">The source memory block.</param>
|
||||
public SafeMoveableHGlobalHandle(SafeAllocatedMemoryHandle source) : base(source) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal SafeMoveableHGlobalHandle() : base(0) { }
|
||||
|
||||
/// <summary>Represents a NULL memory pointer.</summary>
|
||||
public static SafeMoveableHGlobalHandle Null { get; } = new SafeMoveableHGlobalHandle(IntPtr.Zero, false);
|
||||
|
||||
/// <summary>
|
||||
/// Allocates from unmanaged memory to represent a structure with a variable length array at the end and marshal these structure
|
||||
/// elements. It is the callers responsibility to marshal what precedes the trailing array into the unmanaged memory. ONLY
|
||||
/// structures with attribute StructLayout of LayoutKind.Sequential are supported.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the trailing array of structures</typeparam>
|
||||
/// <param name="values">Collection of structure objects</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the trailing array of structures</param>
|
||||
/// <returns><see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) structure with a trail array of structures</returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromList<T>(IEnumerable<T> values, int prefixBytes = 0) =>
|
||||
new(InteropExtensions.MarshalToPtr(values, mm.AllocMem, out _, prefixBytes, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Allocates from unmanaged memory sufficient memory to hold an array of strings.</summary>
|
||||
/// <param name="values">The list of strings.</param>
|
||||
/// <param name="packing">The packing type for the strings.</param>
|
||||
/// <param name="charSet">The character set to use for the strings.</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the trailing strings.</param>
|
||||
/// <returns>
|
||||
/// <see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) array of strings stored using the <paramref
|
||||
/// name="packing"/> model and the character set defined by <paramref name="charSet"/>.
|
||||
/// </returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromStringList(IEnumerable<string> values, StringListPackMethod packing = StringListPackMethod.Concatenated,
|
||||
CharSet charSet = CharSet.Auto, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(values, packing, mm.AllocMem, out _, charSet, prefixBytes, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Allocates from unmanaged memory sufficient memory to hold an object of type T.</summary>
|
||||
/// <typeparam name="T">Native type</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns><see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) memory block the size of T.</returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromStructure<T>(in T value = default) =>
|
||||
new(InteropExtensions.MarshalToPtr(value, mm.AllocMem, out _, 0, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Converts an <see cref="IntPtr"/> to a <see cref="SafeMoveableHGlobalHandle"/> where it owns the reference.</summary>
|
||||
/// <param name="ptr">The <see cref="IntPtr"/>.</param>
|
||||
/// <returns>The result of the conversion.</returns>
|
||||
public static implicit operator SafeMoveableHGlobalHandle(IntPtr ptr) => new(ptr, true);
|
||||
|
||||
/// <summary>Runs a delegate method while locking the memory.</summary>
|
||||
/// <typeparam name="T">The output type.</typeparam>
|
||||
/// <param name="action">The action to perform while memory is locked.</param>
|
||||
/// <returns>The output from the action.</returns>
|
||||
public new T CallLocked<T>(Func<IntPtr, T> action) => base.CallLocked(action);
|
||||
if (Size == 0) return;
|
||||
CallLocked(p => Marshal.Copy(bytes, 0, p, sz));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class from a <see cref="SafeAllocatedMemoryHandle"/>
|
||||
/// instance, copying all the memory.
|
||||
/// </summary>
|
||||
/// <param name="source">The source memory block.</param>
|
||||
public SafeMoveableHGlobalHandle(SafeAllocatedMemoryHandle source) : base(source) { }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SafeMoveableHGlobalHandle"/> class.</summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal SafeMoveableHGlobalHandle() : base(0) { }
|
||||
|
||||
/// <summary>Represents a NULL memory pointer.</summary>
|
||||
public static SafeMoveableHGlobalHandle Null { get; } = new SafeMoveableHGlobalHandle(IntPtr.Zero, false);
|
||||
|
||||
/// <summary>
|
||||
/// Allocates from unmanaged memory to represent a structure with a variable length array at the end and marshal these structure
|
||||
/// elements. It is the callers responsibility to marshal what precedes the trailing array into the unmanaged memory. ONLY
|
||||
/// structures with attribute StructLayout of LayoutKind.Sequential are supported.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the trailing array of structures</typeparam>
|
||||
/// <param name="values">Collection of structure objects</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the trailing array of structures</param>
|
||||
/// <returns><see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) structure with a trail array of structures</returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromList<T>(IEnumerable<T> values, int prefixBytes = 0) =>
|
||||
new(InteropExtensions.MarshalToPtr(values, mm.AllocMem, out _, prefixBytes, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Allocates from unmanaged memory sufficient memory to hold an array of strings.</summary>
|
||||
/// <param name="values">The list of strings.</param>
|
||||
/// <param name="packing">The packing type for the strings.</param>
|
||||
/// <param name="charSet">The character set to use for the strings.</param>
|
||||
/// <param name="prefixBytes">Number of bytes preceding the trailing strings.</param>
|
||||
/// <returns>
|
||||
/// <see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) array of strings stored using the <paramref
|
||||
/// name="packing"/> model and the character set defined by <paramref name="charSet"/>.
|
||||
/// </returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromStringList(IEnumerable<string> values, StringListPackMethod packing = StringListPackMethod.Concatenated,
|
||||
CharSet charSet = CharSet.Auto, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(values, packing, mm.AllocMem, out _, charSet, prefixBytes, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Allocates from unmanaged memory sufficient memory to hold an object of type T.</summary>
|
||||
/// <typeparam name="T">Native type</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns><see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) memory block the size of T.</returns>
|
||||
public static SafeMoveableHGlobalHandle CreateFromStructure<T>(in T value = default) =>
|
||||
new(InteropExtensions.MarshalToPtr(value, mm.AllocMem, out _, 0, mm.LockMem, mm.UnlockMem), true);
|
||||
|
||||
/// <summary>Converts an <see cref="SafeMoveableHGlobalHandle"/> to a <see cref="HGLOBAL"/> where it owns the reference.</summary>
|
||||
/// <param name="ptr">The <see cref="SafeMoveableHGlobalHandle"/>.</param>
|
||||
/// <returns>The result of the conversion.</returns>
|
||||
public static implicit operator HGLOBAL(SafeMoveableHGlobalHandle ptr) => ptr.handle;
|
||||
|
||||
/// <summary>Converts an <see cref="IntPtr"/> to a <see cref="SafeMoveableHGlobalHandle"/> where it owns the reference.</summary>
|
||||
/// <param name="ptr">The <see cref="IntPtr"/>.</param>
|
||||
/// <returns>The result of the conversion.</returns>
|
||||
public static implicit operator SafeMoveableHGlobalHandle(IntPtr ptr) => new(ptr, true);
|
||||
|
||||
/// <summary>Runs a delegate method while locking the memory.</summary>
|
||||
/// <typeparam name="T">The output type.</typeparam>
|
||||
/// <param name="action">The action to perform while memory is locked.</param>
|
||||
/// <returns>The output from the action.</returns>
|
||||
public new T CallLocked<T>(Func<IntPtr, T> action) => base.CallLocked(action);
|
||||
}
|
||||
}
|
|
@ -44,13 +44,8 @@ namespace Vanara.PInvoke
|
|||
GMEM_NOT_BANKED = 0x1000,
|
||||
|
||||
/// <summary>Allocate sharable memory.</summary>
|
||||
[Obsolete("Value is obsolete, but is provided for compatibility with 16-bit Windows.")]
|
||||
GMEM_SHARE = 0x2000,
|
||||
|
||||
/// <summary>Allocate sharable memory.</summary>
|
||||
[Obsolete("Value is obsolete, but is provided for compatibility with 16-bit Windows.")]
|
||||
GMEM_DDESHARE = 0x2000,
|
||||
|
||||
/// <summary>Notify upon discarding</summary>
|
||||
[Obsolete("Value is obsolete, but is provided for compatibility with 16-bit Windows.")]
|
||||
GMEM_NOTIFY = 0x4000,
|
||||
|
@ -844,6 +839,9 @@ namespace Vanara.PInvoke
|
|||
/// <seealso cref="MemoryMethodsBase" />
|
||||
public sealed class MoveableHGlobalMemoryMethods : MemoryMethodsBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool AllocZeroes => true;
|
||||
|
||||
/// <summary>Gets a value indicating whether this memory supports locking.</summary>
|
||||
/// <value><see langword="true"/> if lockable; otherwise, <see langword="false"/>.</value>
|
||||
public override bool Lockable => true;
|
||||
|
@ -858,12 +856,12 @@ namespace Vanara.PInvoke
|
|||
|
||||
/// <summary>Frees the memory associated with a handle.</summary>
|
||||
/// <param name="hMem">A memory handle.</param>
|
||||
public override void FreeMem(IntPtr hMem) => GlobalFree(hMem);
|
||||
public override void FreeMem(IntPtr hMem) => Win32Error.ThrowLastErrorIfNull((IntPtr)GlobalFree(hMem));
|
||||
|
||||
/// <summary>Locks the memory of a specified handle and gets a pointer to it.</summary>
|
||||
/// <param name="hMem">A memory handle.</param>
|
||||
/// <returns>A pointer to the locked memory.</returns>
|
||||
public override IntPtr LockMem(IntPtr hMem) => GlobalLock(hMem);
|
||||
public override IntPtr LockMem(IntPtr hMem) => Win32Error.ThrowLastErrorIfNull(GlobalLock(hMem));
|
||||
|
||||
/// <summary>Gets the reallocation method.</summary>
|
||||
/// <param name="hMem">A memory handle.</param>
|
||||
|
@ -875,9 +873,6 @@ namespace Vanara.PInvoke
|
|||
/// <param name="hMem">A memory handle.</param>
|
||||
/// <returns><see langword="true"/> if the memory object is still locked after decrementing the lock count; otherwise <see langword="false"/>.</returns>
|
||||
public override bool UnlockMem(IntPtr hMem) => GlobalUnlock(hMem);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool AllocZeroes => true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,106 +1,174 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Vanara.Extensions;
|
||||
using Vanara.InteropServices;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
|
||||
namespace Vanara.PInvoke.Tests
|
||||
namespace Vanara.PInvoke.Tests;
|
||||
|
||||
[TestFixture]
|
||||
public class MemoryApiTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class MemoryApiTests
|
||||
// From https://docs.microsoft.com/en-us/windows/desktop/Memory/awe-example
|
||||
[Test]
|
||||
public void AWETest()
|
||||
{
|
||||
// From https://docs.microsoft.com/en-us/windows/desktop/Memory/awe-example
|
||||
[Test]
|
||||
public void AWETest()
|
||||
const uint MEMORY_REQUESTED = 1024 * 1024;
|
||||
|
||||
GetSystemInfo(out SYSTEM_INFO sSysInfo); // fill the system information structure
|
||||
|
||||
TestContext.Write("This computer has page size {0}.\n", sSysInfo.dwPageSize);
|
||||
|
||||
// Calculate the number of pages of memory to request.
|
||||
SizeT NumberOfPages = MEMORY_REQUESTED / sSysInfo.dwPageSize;
|
||||
TestContext.Write("Requesting {0} pages of memory.\n", NumberOfPages);
|
||||
|
||||
// Enable the privilege.
|
||||
using (SafeHPROCESS hProc = SafeHPROCESS.Current)
|
||||
using (new ElevPriv("SeLockMemoryPrivilege", hProc))
|
||||
{
|
||||
const uint MEMORY_REQUESTED = 1024 * 1024;
|
||||
// Allocate the physical memory.
|
||||
IntPtr[] aPFNs = new IntPtr[NumberOfPages];
|
||||
|
||||
GetSystemInfo(out var sSysInfo); // fill the system information structure
|
||||
SizeT NumberOfPagesInitial = NumberOfPages;
|
||||
|
||||
TestContext.Write("This computer has page size {0}.\n", sSysInfo.dwPageSize);
|
||||
Assert.That(AllocateUserPhysicalPages(hProc, ref NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
// Calculate the number of pages of memory to request.
|
||||
SizeT NumberOfPages = MEMORY_REQUESTED / sSysInfo.dwPageSize;
|
||||
TestContext.Write("Requesting {0} pages of memory.\n", NumberOfPages);
|
||||
Assert.That(NumberOfPagesInitial, Is.EqualTo(NumberOfPages));
|
||||
|
||||
// Enable the privilege.
|
||||
using (var hProc = SafeHPROCESS.Current)
|
||||
using (new ElevPriv("SeLockMemoryPrivilege", hProc))
|
||||
// Reserve the virtual memory.
|
||||
IntPtr lpMemReserved;
|
||||
Assert.That(lpMemReserved = VirtualAlloc(IntPtr.Zero, MEMORY_REQUESTED, MEM_ALLOCATION_TYPE.MEM_RESERVE | MEM_ALLOCATION_TYPE.MEM_PHYSICAL, MEM_PROTECTION.PAGE_READWRITE), ResultIs.ValidHandle);
|
||||
|
||||
try
|
||||
{
|
||||
// Allocate the physical memory.
|
||||
var aPFNs = new IntPtr[NumberOfPages];
|
||||
// Map the physical memory into the window.
|
||||
Assert.That(MapUserPhysicalPages(lpMemReserved, NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
var NumberOfPagesInitial = NumberOfPages;
|
||||
// unmap
|
||||
Assert.That(MapUserPhysicalPages(lpMemReserved, NumberOfPages, null), ResultIs.Successful);
|
||||
|
||||
Assert.That(AllocateUserPhysicalPages(hProc, ref NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
// Map the physical memory into the window scattered.
|
||||
Assert.That(MapUserPhysicalPagesScatter(lpMemReserved, NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
Assert.That(NumberOfPagesInitial, Is.EqualTo(NumberOfPages));
|
||||
// unmap
|
||||
Assert.That(MapUserPhysicalPagesScatter(lpMemReserved, NumberOfPages, null), ResultIs.Successful);
|
||||
|
||||
// Reserve the virtual memory.
|
||||
IntPtr lpMemReserved;
|
||||
Assert.That(lpMemReserved = VirtualAlloc(IntPtr.Zero, MEMORY_REQUESTED, MEM_ALLOCATION_TYPE.MEM_RESERVE | MEM_ALLOCATION_TYPE.MEM_PHYSICAL, MEM_PROTECTION.PAGE_READWRITE), ResultIs.ValidHandle);
|
||||
|
||||
try
|
||||
{
|
||||
// Map the physical memory into the window.
|
||||
Assert.That(MapUserPhysicalPages(lpMemReserved, NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
// unmap
|
||||
Assert.That(MapUserPhysicalPages(lpMemReserved, NumberOfPages, null), ResultIs.Successful);
|
||||
|
||||
// Map the physical memory into the window scattered.
|
||||
Assert.That(MapUserPhysicalPagesScatter(lpMemReserved, NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
// unmap
|
||||
Assert.That(MapUserPhysicalPagesScatter(lpMemReserved, NumberOfPages, null), ResultIs.Successful);
|
||||
|
||||
// Free the physical pages.
|
||||
Assert.That(FreeUserPhysicalPages(hProc, ref NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Free virtual memory.
|
||||
Assert.That(VirtualFree(lpMemReserved, 0, MEM_ALLOCATION_TYPE.MEM_RELEASE), ResultIs.Successful);
|
||||
}
|
||||
// Free the physical pages.
|
||||
Assert.That(FreeUserPhysicalPages(hProc, ref NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FillMemoryTest()
|
||||
{
|
||||
using (var mem = new SafeHGlobalHandle(128))
|
||||
finally
|
||||
{
|
||||
FillMemory((IntPtr)mem, 128, 0xFF);
|
||||
Assert.That(mem.ToArray<byte>(128), Has.All.EqualTo(0xFF));
|
||||
// Free virtual memory.
|
||||
Assert.That(VirtualFree(lpMemReserved, 0, MEM_ALLOCATION_TYPE.MEM_RELEASE), ResultIs.Successful);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLargePageMinimumTest()
|
||||
{
|
||||
Assert.That((uint)GetLargePageMinimum(), Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetMemoryErrorHandlingCapabilitiesTest()
|
||||
{
|
||||
Assert.That(GetMemoryErrorHandlingCapabilities(out var cap), Is.True);
|
||||
TestContext.WriteLine(cap);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetProcessWorkingSetSizeExTest()
|
||||
{
|
||||
Assert.That(GetProcessWorkingSetSizeEx(GetCurrentProcess(), out var min, out var max, out var flg), Is.True);
|
||||
TestContext.WriteLine($"{min} : {max} : {flg}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSystemFileCacheSizeTest()
|
||||
{
|
||||
Assert.That(GetSystemFileCacheSize(out var min, out var max, out var flg), Is.True);
|
||||
TestContext.WriteLine($"{min} : {max} : {flg}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FillMemoryTest()
|
||||
{
|
||||
using SafeHGlobalHandle mem = new(128);
|
||||
FillMemory((IntPtr)mem, 128, 0xFF);
|
||||
Assert.That(mem.ToArray<byte>(128), Has.All.EqualTo(0xFF));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLargePageMinimumTest() => Assert.That((uint)GetLargePageMinimum(), Is.GreaterThan(0));
|
||||
|
||||
[Test]
|
||||
public void GetMemoryErrorHandlingCapabilitiesTest()
|
||||
{
|
||||
Assert.That(GetMemoryErrorHandlingCapabilities(out uint cap), Is.True);
|
||||
TestContext.WriteLine(cap);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetProcessWorkingSetSizeExTest()
|
||||
{
|
||||
Assert.That(GetProcessWorkingSetSizeEx(GetCurrentProcess(), out SizeT min, out SizeT max, out QUOTA_LIMITS_HARDWS flg), Is.True);
|
||||
TestContext.WriteLine($"{min} : {max} : {flg}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSystemFileCacheSizeTest()
|
||||
{
|
||||
Assert.That(GetSystemFileCacheSize(out SizeT min, out SizeT max, out FILE_CACHE_LIMITS flg), Is.True);
|
||||
TestContext.WriteLine($"{min} : {max} : {flg}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobleFlagsTest()
|
||||
{
|
||||
using SafeMoveableHGlobalHandle h = new(32);
|
||||
Assert.AreEqual(GlobalFlags(h), GMEM.GMEM_SHARE);
|
||||
}
|
||||
|
||||
[Test, Repeat(50)]
|
||||
public void SafeMoveableHGlobalCreateFromHGLOBALTest()
|
||||
{
|
||||
var val = new RECT(8, 16, 32, 64);
|
||||
var ptr = InteropExtensions.MarshalToPtr(val, i => (IntPtr)GlobalAlloc(GMEM.GHND | GMEM.GMEM_SHARE, i), out _, memLock: p => GlobalLock(p), memUnlock: p => GlobalUnlock(p));
|
||||
using SafeMoveableHGlobalHandle h = new(ptr, true);
|
||||
Assert.AreEqual(val, h.ToStructure<RECT>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobalCreateFromStringListTest()
|
||||
{
|
||||
var strings = new[] { "AAAA", "BBBB", "CCCC" };
|
||||
using SafeMoveableHGlobalHandle h = SafeMoveableHGlobalHandle.CreateFromStringList(strings);
|
||||
CollectionAssert.AreEqual(strings, h.ToStringEnum());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobalCreateFromStructTest()
|
||||
{
|
||||
var val = new RECT(8, 16, 32, 64);
|
||||
using SafeMoveableHGlobalHandle h = SafeMoveableHGlobalHandle.CreateFromStructure(val);
|
||||
Assert.AreEqual(val, h.ToStructure<RECT>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobalCreateFromBytesTest()
|
||||
{
|
||||
const string txt = @"“0’0©0è0”";
|
||||
using SafeMoveableHGlobalHandle h = new(System.Text.Encoding.Unicode.GetBytes(txt + '\0'));
|
||||
Assert.AreEqual(txt, h.ToString(-1));
|
||||
}
|
||||
|
||||
[Test, Repeat(50)]
|
||||
public void SafeMoveableHGlobalTakeOwnershipTest()
|
||||
{
|
||||
var val = new RECT(8, 16, 32, 64);
|
||||
using SafeMoveableHGlobalHandle h = SafeMoveableHGlobalHandle.CreateFromStructure(val);
|
||||
HGLOBAL myh = h.TakeOwnership();
|
||||
try
|
||||
{
|
||||
var p = GlobalLock(myh);
|
||||
Assert.AreEqual(val, p.ToStructure<RECT>());
|
||||
GlobalUnlock(myh);
|
||||
}
|
||||
finally { Assert.AreEqual(GlobalFree(myh), HGLOBAL.NULL); }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobalWriteStructTest()
|
||||
{
|
||||
var val = new RECT(8, 16, 32, 64);
|
||||
using SafeMoveableHGlobalHandle h = new(32);
|
||||
h.Write(val);
|
||||
Assert.AreEqual(val, h.ToStructure<RECT>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SafeMoveableHGlobalWriteStringListTest()
|
||||
{
|
||||
var strings = new[] { "AAAA", "BBBB", "CCCC" };
|
||||
using SafeMoveableHGlobalHandle h = new(256);
|
||||
h.CallLocked(p => p.Write(strings, StringListPackMethod.Concatenated, offset: 64, allocatedBytes: h.Size));
|
||||
CollectionAssert.AreEqual(strings, h.ToStringEnum(prefixBytes: 64));
|
||||
Assert.That(() => h.CallLocked(p => p.Write(strings, StringListPackMethod.Concatenated, offset: 250, allocatedBytes: h.Size)), Throws.Exception);
|
||||
CollectionAssert.AreEqual(strings, h.ToStringEnum(prefixBytes: 64));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue