使用Microsoft.Win32.SafeHandles与Marshal.AllocHGlobal和Marshal.FreeHGlobal

时间:2015-06-24 07:45:34

标签: .net winapi marshalling

我有一个.Net类,使用structMarshal.AllocHGlobal分配非托管内存,然后使用Marshal.FreeHGlobal处理它。

我理解类Microsoft.Win32.SafeHandles提供了处理这个的包装器,但是不清楚如何实例化它们(很多都没有构造函数) - 我应该编写抽象基类的特定实现或者有没有办法在extern声明中使用它们?

1 个答案:

答案 0 :(得分:6)

子类化SafeHandle的主要问题是,Marshal.DestroyStructure需要结构的Type ...这会使一切变得更加复杂。

你不能使用泛型(因为它们与pinvoke不兼容)...所以你可以拥有多个SafeHandle子类(每个Type一个),或SafeHandle内的属性{1}}使用您手动设置的结构类型...或者您可以使SafeHandle的构造函数接受要封送的结构并在属性中设置Type

我正在使用最后两个“选项”(属性Type,可以手动设置,也可以由构造函数自动设置)

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;
    }
}

您应该使用的构造函数是使用Marshal.StructureToPtr封送结构的构造函数。它的优点是可以保存结构的类型,以便以后可以使用Marshal.DestroyStructure