Keith
Keith

Reputation: 155792

Using Microsoft.Win32.SafeHandles vs Marshal.AllocHGlobal and Marshal.FreeHGlobal

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

Answers (1)

xanatos
xanatos

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

Related Questions