mirror of https://github.com/dahall/Vanara.git
Updated SafeMoveableHGlobalHandle class and added tests.
parent
7c0c7fe66c
commit
63203f558e
|
@ -5,10 +5,10 @@ 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>
|
||||
|
@ -80,6 +80,11 @@ namespace Vanara.PInvoke
|
|||
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>
|
||||
|
@ -91,5 +96,4 @@ namespace Vanara.PInvoke
|
|||
/// <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,22 +1,21 @@
|
|||
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()
|
||||
{
|
||||
const uint MEMORY_REQUESTED = 1024 * 1024;
|
||||
|
||||
GetSystemInfo(out var sSysInfo); // fill the system information structure
|
||||
GetSystemInfo(out SYSTEM_INFO sSysInfo); // fill the system information structure
|
||||
|
||||
TestContext.Write("This computer has page size {0}.\n", sSysInfo.dwPageSize);
|
||||
|
||||
|
@ -25,13 +24,13 @@ namespace Vanara.PInvoke.Tests
|
|||
TestContext.Write("Requesting {0} pages of memory.\n", NumberOfPages);
|
||||
|
||||
// Enable the privilege.
|
||||
using (var hProc = SafeHPROCESS.Current)
|
||||
using (SafeHPROCESS hProc = SafeHPROCESS.Current)
|
||||
using (new ElevPriv("SeLockMemoryPrivilege", hProc))
|
||||
{
|
||||
// Allocate the physical memory.
|
||||
var aPFNs = new IntPtr[NumberOfPages];
|
||||
IntPtr[] aPFNs = new IntPtr[NumberOfPages];
|
||||
|
||||
var NumberOfPagesInitial = NumberOfPages;
|
||||
SizeT NumberOfPagesInitial = NumberOfPages;
|
||||
|
||||
Assert.That(AllocateUserPhysicalPages(hProc, ref NumberOfPages, aPFNs), ResultIs.Successful);
|
||||
|
||||
|
@ -69,38 +68,107 @@ namespace Vanara.PInvoke.Tests
|
|||
[Test]
|
||||
public void FillMemoryTest()
|
||||
{
|
||||
using (var mem = new SafeHGlobalHandle(128))
|
||||
{
|
||||
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));
|
||||
}
|
||||
public void GetLargePageMinimumTest() => Assert.That((uint)GetLargePageMinimum(), Is.GreaterThan(0));
|
||||
|
||||
[Test]
|
||||
public void GetMemoryErrorHandlingCapabilitiesTest()
|
||||
{
|
||||
Assert.That(GetMemoryErrorHandlingCapabilities(out var cap), Is.True);
|
||||
Assert.That(GetMemoryErrorHandlingCapabilities(out uint 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);
|
||||
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 var min, out var max, out var flg), Is.True);
|
||||
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