Reputation: 155792
I have a .Net class that allocates unmanaged memory for a struct
using Marshal.AllocHGlobal
and then disposes of it using Marshal.FreeHGlobal
.
I understand that the classes Microsoft.Win32.SafeHandles
provide wrappers that handle this, but it isn't clear how to instantiate them (many don't have constructors) - should I be writing a specific implementation of the abstract base class or is there some way to use them in the extern
declaration?
Upvotes: 4
Views: 1097
Reputation: 111910
The main problem of subclassing SafeHandle
is that to Marshal.DestroyStructure
you need the Type
of the struct... This makes everything more complex.
You can't use generics (because they aren't compatible with pinvoke)... So you can have multiple SafeHandle
subclasses (one for each Type
), or a property inside the SafeHandle
with the type of the struct that you set manually... Or you can make the constructor of the SafeHandle
accept the struct to be marshaled and set the Type
inside a property.
I'm using the last two "options" (property Type
that can be set manually or that can be set automatically by a constructor)
Example of MySafeHandle
:
public class MySafeHandle : SafeHandle
{
public Type Type { get; set; }
public MySafeHandle() : base(IntPtr.Zero, true)
{
}
public MySafeHandle(object obj)
: base(IntPtr.Zero, true)
{
if (obj != null)
{
Type = obj.GetType();
int size = Marshal.SizeOf(obj);
try
{
}
finally
{
// the finally part can't be interrupted by
// Thread.Abort
handle = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, handle, false);
}
}
}
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
[SecurityCritical]
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
{
if (Type == null)
{
throw new InvalidOperationException();
}
try
{
}
finally
{
Marshal.DestroyStructure(handle, Type);
Marshal.FreeHGlobal(handle);
handle = IntPtr.Zero;
}
return true;
}
return false;
}
}
The constructor you should use is the one that marshals the structure with Marshal.StructureToPtr
. It has the advantage that it saves the type of the structure so that it can use it later to Marshal.DestroyStructure
.
Upvotes: 7