如何在应用程序关闭时处理释放非托管结构?

时间:2010-05-14 19:05:21

标签: c# unmanaged structure

我有一个C#项目,其中我使用了几个非托管C ++函数。 更重要的是,我还有静态I​​ntPtr,我将其用作这些函数的参数。我知道每当我使用它们时,我应该在该类中实现IDisposable并使用析构函数来调用Dispose方法,在那里我释放使用过的IntPtr,如MSDN页面中所述。

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
    // Check to see if Dispose has already been called.
    if (!this.disposed)
    {
        if (disposing)
        {
            component.Dispose();
        }

        CloseHandle(m_InstanceHandle);
        m_InstanceHandle = IntPtr.Zero;

        disposed = true;

    }
}

[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);

但是,当我终止应用程序时,我仍然在TaskManager中处于挂起状态。我认为它必须与我在结构中使用MarshalAs指令有关:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
 public struct SipxAudioCodec
 {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
        public string CodecName;
        public SipxAudioBandwidth Bandwidth;
        public int PayloadType;
 }

当我创建这样的结构时,我还应该小心释放它使用析构函数分配的空间吗?

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
 public struct SipxAudioCodec
 {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
        public string CodecName;
        public SipxAudioBandwidth Bandwidth;
        public int PayloadType;

        ~SipxAudioCodec()
        {
            Marshal.FreeGlobal(something...);
        }
 }

2 个答案:

答案 0 :(得分:1)

在p / Invoke互操作中处理IntPtr - 样式句柄的正确方法是:

  • 定义从SafeMyHandle派生的课程SafeHandle。它应该只覆盖IsInvalidReleaseHandle,而不执行任何其他操作。
  • 定义另一个类MyHandle,该类具有该句柄的公共API的方法。
  • MyHandle应该有SafeMyHandle类型的私有成员。
  • MyHandle应该实施IDisposable,其Dispose方法应该只调用SafeMyHandle.Dispose
  • 所有p / Invoke方法都不应直接使用IntPtr;相反,他们应该传递并返回SafeMyHandle的实例。唯一的例外是从SafeMyHandle.ReleaseHandle调用的“释放函数”;它应该采用IntPtr

如果您遵循这些约定,即使您的AppDomain被严重拆除,您的句柄也会被释放。

答案 1 :(得分:0)

我曾经遇到过应用程序在关闭后挂起的情况,通常是因为并非所有线程都被终止。你如何终止你的应用程序?也许线程是原因?