From 9b7e1371a4f9381a82603f5c638ce4d6742168ec Mon Sep 17 00:00:00 2001 From: "Denis Kuzmin [ github.com/3F ]" Date: Mon, 13 Aug 2018 00:11:44 +0300 Subject: [PATCH] Implemented initialization of UnmanagedString from IntPtr --- Conari/Types/UnmanagedString.cs | 89 ++++++++++++++++++---- ConariTest/Types/UnmanagedStringTest.cs | 41 ++++++++++ ConariTest/Types/UnmanagedStructureTest.cs | 2 +- 3 files changed, 117 insertions(+), 15 deletions(-) diff --git a/Conari/Types/UnmanagedString.cs b/Conari/Types/UnmanagedString.cs index 147d9cd..fb4e867 100644 --- a/Conari/Types/UnmanagedString.cs +++ b/Conari/Types/UnmanagedString.cs @@ -31,8 +31,6 @@ namespace net.r_eg.Conari.Types [DebuggerDisplay("{managed} [ {\"0x\" + Pointer.ToString(\"X\")} ]")] public sealed class UnmanagedString: IDisposable { - private string managed; - /// /// Pointer to allocated string. /// @@ -42,6 +40,24 @@ public IntPtr Pointer private set; } + /// + /// Who is the owner for unmanaged string. + /// + public bool Owner + { + get; + private set; + } + + /// + /// Access to managed or unmanaged string data. + /// + public string Data + { + get; + private set; + } + public SType Type { get; @@ -79,55 +95,100 @@ public static implicit operator BSTR(UnmanagedString val) public UnmanagedString(string str, SType type = SType.Auto) { - managed = str; - Type = type; + Data = str ?? throw new ArgumentNullException(nameof(str)); + Type = type; alloc(); } + public UnmanagedString(IntPtr ptr, SType type) + { + if(ptr == IntPtr.Zero) { + throw new ArgumentException("Pointer must be non-zero for UnmanagedString."); + } + + Type = type; + Data = alloc(ptr); + } + + private string alloc(IntPtr ptr) + { + Pointer = ptr; + Owner = false; + + switch(Type) + { + case SType.Ansi: { + return (CharPtr)ptr; + } + case SType.Unicode: { + return (WCharPtr)ptr; + } + case SType.BSTR: { + return (BSTR)ptr; + } + } + + //TODO: SType.Auto + throw new NotImplementedException($"the type '{Type}' is not implemented yet."); + } + private void alloc() { + Owner = true; + switch(Type) { case SType.Auto: { - Pointer = Marshal.StringToHGlobalAuto(managed); + Pointer = Marshal.StringToHGlobalAuto(Data); return; } case SType.Ansi: { - Pointer = Marshal.StringToHGlobalAnsi(managed); + Pointer = Marshal.StringToHGlobalAnsi(Data); return; } case SType.Unicode: { - Pointer = Marshal.StringToHGlobalUni(managed); + Pointer = Marshal.StringToHGlobalUni(Data); return; } case SType.BSTR: { - Pointer = Marshal.StringToBSTR(managed); + Pointer = Marshal.StringToBSTR(Data); return; } } - throw new NotImplementedException($"the type '{Type}' is not yet implemented."); + throw new NotImplementedException($"the type '{Type}' is not implemented yet."); } - private void free() + private void free(IntPtr ptr, SType type) { - switch(Type) + if(ptr == IntPtr.Zero) { + return; + } + + switch(type) { case SType.Auto: case SType.Ansi: case SType.Unicode: { - Marshal.FreeHGlobal(Pointer); + Marshal.FreeHGlobal(ptr); break; } case SType.BSTR: { - Marshal.FreeBSTR(Pointer); + Marshal.FreeBSTR(ptr); break; } } + } + + private void free() + { + if(Owner) { + free(Pointer, Type); + } // but we still can try to get data from this offset :) Pointer = IntPtr.Zero; - managed = null; + Data = null; } #region IDisposable diff --git a/ConariTest/Types/UnmanagedStringTest.cs b/ConariTest/Types/UnmanagedStringTest.cs index 61b11c1..1c4c6a5 100644 --- a/ConariTest/Types/UnmanagedStringTest.cs +++ b/ConariTest/Types/UnmanagedStringTest.cs @@ -55,5 +55,46 @@ public void allocFreeTest3() Assert.AreEqual(IntPtr.Zero, (IntPtr)uns); } + + [TestMethod] + public void pointerTest1() + { + string managed = " my string 123 "; + + UnmanagedString uns, uns2; + using(uns = new UnmanagedString(managed, UnmanagedString.SType.Unicode)) + { + IntPtr ptr = uns; + + using(uns2 = new UnmanagedString(ptr, uns.Type)) + { + Assert.AreEqual(uns.Pointer, uns2.Pointer); + Assert.AreEqual(uns.Type, uns2.Type); + + Assert.AreEqual(false, uns2.Owner); + Assert.AreEqual(true, uns.Owner); + + Assert.AreEqual(managed.Length, uns2.Data.Length); + Assert.AreEqual(managed, uns2.Data); + } + } + + Assert.AreEqual(IntPtr.Zero, (IntPtr)uns); + Assert.AreEqual(IntPtr.Zero, (IntPtr)uns2); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ctorTest1() + { + new UnmanagedString(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void ctorTest2() + { + new UnmanagedString(IntPtr.Zero, UnmanagedString.SType.Unicode); + } } } diff --git a/ConariTest/Types/UnmanagedStructureTest.cs b/ConariTest/Types/UnmanagedStructureTest.cs index 46d67c9..3a04288 100644 --- a/ConariTest/Types/UnmanagedStructureTest.cs +++ b/ConariTest/Types/UnmanagedStructureTest.cs @@ -46,7 +46,7 @@ public void allocFreeTest2() [TestMethod] [ExpectedException(typeof(ArgumentNullException))] - public void allocFreeTest3() + public void ctorTest1() { new UnmanagedStructure(null); }