Skip to content

Commit

Permalink
Implemented initialization of UnmanagedString from IntPtr
Browse files Browse the repository at this point in the history
  • Loading branch information
3F committed Aug 12, 2018
1 parent 6d4e368 commit 9b7e137
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 15 deletions.
89 changes: 75 additions & 14 deletions Conari/Types/UnmanagedString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ namespace net.r_eg.Conari.Types
[DebuggerDisplay("{managed} [ {\"0x\" + Pointer.ToString(\"X\")} ]")]
public sealed class UnmanagedString: IDisposable
{
private string managed;

/// <summary>
/// Pointer to allocated string.
/// </summary>
Expand All @@ -42,6 +40,24 @@ public IntPtr Pointer
private set;
}

/// <summary>
/// Who is the owner for unmanaged string.
/// </summary>
public bool Owner
{
get;
private set;
}

/// <summary>
/// Access to managed or unmanaged string data.
/// </summary>
public string Data
{
get;
private set;
}

public SType Type
{
get;
Expand Down Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions ConariTest/Types/UnmanagedStringTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
2 changes: 1 addition & 1 deletion ConariTest/Types/UnmanagedStructureTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void allocFreeTest2()

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void allocFreeTest3()
public void ctorTest1()
{
new UnmanagedStructure(null);
}
Expand Down

0 comments on commit 9b7e137

Please sign in to comment.