SafeHandle and HandleRef

After reading about everything, including the high voice response on this site, I still find this a bit obscure.

Since my understanding of this question may be wrong, I will first publish a summary of what I know, so I can be corrected if I am wrong, and then ask my specific questions:

Sometimes when encoding a managed code, we must pass the address to the unmanaged code. This is for IntPtr. However, we are trying to make sure of two opposite things: a) Keep this pointer (at the address) alive from the GC. b) Release it when it is not needed (even if we forget to do it explicitly).

HandleRef does the first, and SafeHandle does the second. (I actually refer here to the SafeHandle definitions listed here ).

My questions:

  • Obviously, I want to confirm both. So, how do I get that functionality? (This is the main question.)
  • From here and From MSDN ("call of a managed object"), it seems that there someObject.Handlecan only be GC'd, but IntPtrthere will be no free position . But he is IntPtr controlled!
  • How can IntPtr be GC'd before it goes out of scope (as indicated here )?
+5
source share
1 answer

, (IntPtr void*) ( Windows). , IntPtr, .

SafeHandle . , , ( - ). , CreateFile HANDLE, SafeFileHandle. SafeHandle Windows, Windows, SafeHandle. , SafeHandle , .

- . . IntPtr - struct, struct (.. , IntPtr , IntPtr)). , GC IntPtr s.

HandleRef :

HandleRef : a Object, , IntPtr, . interop , ( HandleRef) .

MSDN:

FileStream fs = new FileStream("HandleRef.txt", FileMode.Open);
HandleRef hr = new HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle());
StringBuilder buffer = new StringBuilder(5);
int read = 0;

// platform invoke will hold reference to HandleRef until call ends

LibWrap.ReadFile(hr, buffer, 5, out read, 0);
Console.WriteLine("Read with struct parameter: {0}", buffer);
LibWrap.ReadFile2(hr, buffer, 5, out read, null);
Console.WriteLine("Read with class parameter: {0}", buffer);

:

FileStream fs = new FileStream("HandleRef.txt", FileMode.Open);
var hf = fs.SafeFileHandle.DangerousGetHandle();
StringBuilder buffer = new StringBuilder(5);
int read = 0;

LibWrap.ReadFile(hf, buffer, 5, out read, 0);
Console.WriteLine("Read with struct parameter: {0}", buffer);
LibWrap.ReadFile2(hf, buffer, 5, out read, null);
Console.WriteLine("Read with class parameter: {0}", buffer);

// Since we no more have a HandleRef, the following line is needed:
GC.KeepAlive(fs);

:

using(FileStream fs = new FileStream("HandleRef.txt", FileMode.Open))
{
    StringBuilder buffer = new StringBuilder(5);
    int read = 0;

    LibWrap.ReadFile(fs.SafeFileHandle, buffer, 5, out read, 0);
    Console.WriteLine("Read with struct parameter: {0}", buffer);
    LibWrap.ReadFile2(fs.SafeFileHandle, buffer, 5, out read, null);
    Console.WriteLine("Read with class parameter: {0}", buffer);
}

:

  • SafeHandle , , , GC , ( Dispose()).

    , , . fixed GCHandle.

  • IntPtr struct, , GC.

  • IntPtr, , HWnd, , GC. , .

    :

    HWnd a = new HWnd();
    IntPtr h = a.Handle;
    
    // The GC can kick in at this point and collect HWnd,
    // because it not referenced after this line.
    // If it does, HWnd finalizer could run.
    // If it runs, HWnd will dispose the handle.
    // If the handle is disposed, h will hold a freed handle value,
    // which is invalid. It still has the same numerical value, but
    // Windows will already have freed the underlying object.
    // Being a value type, h itself has nothing to do with the GC.
    // It not collectable. Think of it like it were an int.
    
    B.SendMessage(h, ...);
    
    // Adding GC.KeepAlive(a) here solves this issue.
    

    , , . IntPtr h = a.Handle; a, , . GC.KeepAlive(a) , ( , JIT, ).


SafeHandle , HandleRef. ?

. , P/Invoke , (, HWnd) , . , HandleRef, SafeHandle. , (HWnd ) .

HandleRef IntPtr, . SafeHandle IntPtr . , P/Invoke.

+6

All Articles