views:

49

answers:

2

I have a C# project in which i use several unmanaged C++ functions. More so, I also have static IntPtr that I use as parameters for those functions. I know that whenever I use them, I should implement IDisposable in that class and use a destructor to invoke the Dispose method, where I free the used IntPtr, as is said in the MSDN page.

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

However, when I terminate the application, I'm still left with a hanging process in TaskManager. I believe that it must be related to the used of the MarshalAs instruction in my structures:

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

When I create such a structure should I also be careful to free the space it allocs using a destructor?

 [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...);
        }
 }
A: 

I have had cases in the past where the application hangs after closing, usually because not all threads were terminated. How do you terminate your app? Maybe threads are the cause?

Andrey
A: 

The proper way to handle IntPtr-style handles in p/Invoke interop is:

  • Define a class SafeMyHandle derived from SafeHandle. It should only override IsInvalid and ReleaseHandle, and do nothing else.
  • Define another class MyHandle that has methods for the public API for that handle.
  • MyHandle should have a private member of type SafeMyHandle.
  • MyHandle should implement IDisposable, and its Dispose method should just call SafeMyHandle.Dispose.
  • All of the p/Invoke methods should not use IntPtr directly; rather, they should pass and return instances of SafeMyHandle. The one exception is the "freeing function" that is called from SafeMyHandle.ReleaseHandle; it should take an IntPtr.

If you follow these conventions, your handles will be freed even if your AppDomain is rudely torn down.

Stephen Cleary