The Labs \ Source Viewer \ SSCLI \ System.Runtime.InteropServices \ GCHandleType

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Runtime.InteropServices
  16. {
  17.     using System;
  18.     using System.Security.Permissions;
  19.     using System.Runtime.CompilerServices;
  20.     using System.Threading;
  21.    
  22.     // These are the types of handles used by the EE. IMPORTANT: These must
  23.     // match the definitions in ObjectHandle.h in the EE.
  24.     [Serializable()]
  25.     [System.Runtime.InteropServices.ComVisible(true)]
  26.     public enum GCHandleType
  27.     {
  28.         Weak = 0,
  29.         WeakTrackResurrection = 1,
  30.         Normal = 2,
  31.         Pinned = 3
  32.     }
  33.    
  34.     // This class allows you to create an opaque, GC handle to any
  35.     // COM+ object. A GC handle is used when an object reference must be
  36.     // reachable from unmanaged memory. There are 3 kinds of roots:
  37.     // Normal - keeps the object from being collected.
  38.     // Weak - allows object to be collected and handle contents will be zeroed.
  39.     // Weak references are zeroed before the finalizer runs, so if the
  40.     // object is resurrected in the finalizer the weak reference is
  41.     // still zeroed.
  42.     // WeakTrackResurrection - Same as weak, but stays until after object is
  43.     // really gone.
  44.     // Pinned - same as normal, but allows the address of the actual object
  45.     // to be taken.
  46.     //
  47.    
  48.     [StructLayout(LayoutKind.Sequential)]
  49.     [System.Runtime.InteropServices.ComVisible(true)]
  50.     public struct GCHandle
  51.     {
  52.         static internal readonly IntPtr InvalidCookie = new IntPtr(unchecked((int)4294967295u));
  53.        
  54.        
  55.         // Allocate a handle storing the object and the type.
  56.         internal GCHandle(object value, GCHandleType type)
  57.         {
  58.             m_handle = InternalAlloc(value, type);
  59.            
  60.             // Record if the handle is pinned.
  61.             if (type == GCHandleType.Pinned)
  62.                 SetIsPinned();
  63.         }
  64.        
  65.         // Used in the conversion functions below.
  66.         internal GCHandle(IntPtr handle)
  67.         {
  68.             InternalCheckDomain(handle);
  69.             m_handle = handle;
  70.         }
  71.        
  72.         // Creates a new GC handle for an object.
  73.         //
  74.         // value - The object that the GC handle is created for.
  75.         // type - The type of GC handle to create.
  76.         //
  77.         // returns a new GC handle that protects the object.
  78.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  79.         public static GCHandle Alloc(object value)
  80.         {
  81.             return new GCHandle(value, GCHandleType.Normal);
  82.         }
  83.        
  84.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  85.         public static GCHandle Alloc(object value, GCHandleType type)
  86.         {
  87.             return new GCHandle(value, type);
  88.         }
  89.        
  90.        
  91.         // Frees a GC handle.
  92.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  93.         public void Free()
  94.         {
  95.             // Copy the handle instance member to a local variable. This is required to prevent
  96.             // race conditions releasing the handle.
  97.             IntPtr handle = m_handle;
  98.            
  99.             // Free the handle if it hasn't already been freed.
  100.             if (handle != IntPtr.Zero && Interlocked.CompareExchange(ref m_handle, IntPtr.Zero, handle) == handle) {
  101.                 #if WIN32
  102.                 InternalFree((IntPtr)(((int)handle) & ~1));
  103.                 #else
  104.                 InternalFree((IntPtr)(((long)handle) & ~1l));
  105.                 #endif
  106.                
  107.             }
  108.             else {
  109.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  110.             }
  111.         }
  112.        
  113.         // Target property - allows getting / updating of the handle's referent.
  114.         public object Target {
  115.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  116.             get {
  117.                 // Check if the handle was never initialized or was freed.
  118.                 if (m_handle == IntPtr.Zero)
  119.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  120.                
  121.                 return InternalGet(GetHandleValue());
  122.             }
  123.            
  124.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  125.             set {
  126.                 // Check if the handle was never initialized or was freed.
  127.                 if (m_handle == IntPtr.Zero)
  128.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  129.                
  130.                 InternalSet(GetHandleValue(), value, IsPinned());
  131.             }
  132.         }
  133.        
  134.         // Retrieve the address of an object in a Pinned handle. This throws
  135.         // an exception if the handle is any type other than Pinned.
  136.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  137.         public IntPtr AddrOfPinnedObject()
  138.         {
  139.             // Check if the handle was not a pinned handle.
  140.             if (!IsPinned()) {
  141.                 // Check if the handle was never initialized for was freed.
  142.                 if (m_handle == IntPtr.Zero)
  143.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  144.                
  145.                 // You can only get the address of pinned handles.
  146.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned"));
  147.             }
  148.            
  149.             // Get the address.
  150.             return InternalAddrOfPinnedObject(GetHandleValue());
  151.         }
  152.        
  153.         // Determine whether this handle has been allocated or not.
  154.         public bool IsAllocated {
  155.             get { return m_handle != IntPtr.Zero; }
  156.         }
  157.        
  158.         // Used to create a GCHandle from an int. This is intended to
  159.         // be used with the reverse conversion.
  160.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  161.         public static explicit operator GCHandle(IntPtr value)
  162.         {
  163.             return FromIntPtr(value);
  164.         }
  165.        
  166.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  167.         public static GCHandle FromIntPtr(IntPtr value)
  168.         {
  169.             if (value == IntPtr.Zero)
  170.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  171.            
  172.             IntPtr handle = value;
  173.            
  174.            
  175.             return new GCHandle(handle);
  176.         }
  177.        
  178.         // Used to get the internal integer representation of the handle out.
  179.         public static explicit operator IntPtr(GCHandle value)
  180.         {
  181.             return ToIntPtr(value);
  182.         }
  183.        
  184.         public static IntPtr ToIntPtr(GCHandle value)
  185.         {
  186.             return value.m_handle;
  187.         }
  188.        
  189.         public override int GetHashCode()
  190.         {
  191.             return (int)m_handle;
  192.         }
  193.        
  194.         public override bool Equals(object o)
  195.         {
  196.             GCHandle hnd;
  197.            
  198.             // Check that o is a GCHandle first
  199.             if (o == null || !(o is GCHandle))
  200.                 return false;
  201.             else
  202.                 hnd = (GCHandle)o;
  203.            
  204.             return m_handle == hnd.m_handle;
  205.         }
  206.        
  207.         public static bool operator ==(GCHandle a, GCHandle b)
  208.         {
  209.             return a.m_handle == b.m_handle;
  210.         }
  211.        
  212.         public static bool operator !=(GCHandle a, GCHandle b)
  213.         {
  214.             return a.m_handle != b.m_handle;
  215.         }
  216.        
  217.         internal IntPtr GetHandleValue()
  218.         {
  219.             #if WIN32
  220.             return new IntPtr(((int)m_handle) & ~1);
  221.             #else
  222.             return new IntPtr(((long)m_handle) & ~1l);
  223.             #endif
  224.         }
  225.        
  226.         internal bool IsPinned()
  227.         {
  228.             #if WIN32
  229.             return (((int)m_handle) & 1) != 0;
  230.             #else
  231.             return (((long)m_handle) & 1) != 0;
  232.             #endif
  233.         }
  234.        
  235.         internal void SetIsPinned()
  236.         {
  237.             #if WIN32
  238.             m_handle = new IntPtr(((int)m_handle) | 1);
  239.             #else
  240.             m_handle = new IntPtr(((long)m_handle) | 1l);
  241.             #endif
  242.         }
  243.        
  244.         // Internal native calls that this implementation uses.
  245.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  246.         static internal extern IntPtr InternalAlloc(object value, GCHandleType type);
  247.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  248.         static internal extern void InternalFree(IntPtr handle);
  249.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  250.         static internal extern object InternalGet(IntPtr handle);
  251.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  252.         static internal extern void InternalSet(IntPtr handle, object value, bool isPinned);
  253.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  254.         static internal extern object InternalCompareExchange(IntPtr handle, object value, object oldValue, bool isPinned);
  255.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  256.         static internal extern IntPtr InternalAddrOfPinnedObject(IntPtr handle);
  257.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  258.         static internal extern void InternalCheckDomain(IntPtr handle);
  259.        
  260.         // The actual integer handle value that the EE uses internally.
  261.         private IntPtr m_handle;
  262.        
  263.     }
  264. }

Developer Fusion