MS公开的gchandle.cs源码

 

  1// ==++==
  2// 
  3//   
  4//    Copyright (c) 2002 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// ==--==
 15namespace System.Runtime.InteropServices {
 16    
 17 using System;
 18 using System.Security.Permissions;
 19 using System.Runtime.CompilerServices;
 20
 21 // These are the types of handles used by the EE.  IMPORTANT: These must
 22 // match the definitions in ObjectHandle.h in the EE.
 23 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType"]/*' />
 24 [Serializable]
 25 public enum GCHandleType
 26 {
 27  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Weak"]/*' />
 28  Weak = 0,
 29  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.WeakTrackResurrection"]/*' />
 30  WeakTrackResurrection = 1,
 31  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Normal"]/*' />
 32  Normal = 2,
 33  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Pinned"]/*' />
 34  Pinned = 3
 35 }

 36
 37    // This class allows you to create an opaque, GC handle to any 
 38    // COM+ object. A GC handle is used when an object reference must be
 39 // reachable from unmanaged memory.  There are 3 kinds of roots:
 40 // Normal - keeps the object from being collected.
 41 // Weak - allows object to be collected and handle contents will be zeroed.
 42    //          Weak references are zeroed before the finalizer runs, so if the
 43    //          object is resurrected in the finalizer the weak reference is
 44    //          still zeroed.
 45 // WeakTrackResurrection - Same as weak, but stays until after object is
 46    //          really gone.
 47 // Pinned - same as normal, but allows the address of the actual object
 48 //          to be taken.
 49    //
 50    /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle"]/*' />
 51 [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
 52    public struct GCHandle
 53    {
 54        // Allocate a handle storing the object and the type.
 55        internal GCHandle(Object value, GCHandleType type)
 56  {
 57   m_handle = InternalAlloc(value, type);
 58
 59   // Record if the handle is pinned.
 60   if (type == GCHandleType.Pinned)
 61                SetIsPinned();
 62  }
  
 63
 64  // Used in the conversion functions below.
 65  internal GCHandle(IntPtr handle)
 66  {
 67         InternalCheckDomain(handle);
 68   m_handle = handle;
 69  }

 70
 71        // Creates a new GC handle for an object.
 72        //
 73        // value - The object that the GC handle is created for.
 74  // type - The type of GC handle to create.
 75        // 
 76     // returns a new GC handle that protects the object.
 77        /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc"]/*' />
 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        /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc1"]/*' />
 85        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
 86        public static GCHandle Alloc(Object value, GCHandleType type)
 87        {
 88   return new GCHandle(value, type);
 89        }

 90
 91        // Frees a GC handle.  The caller must provide synchronization to
 92  // prevent multiple threads from executing this simultaneously for
 93  // a given handle. If you modify this method please modify the 
 94        // __InternalFree also which is the internal without the linktime check.
 95        /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Free"]/*' />
 96        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
 97        public void Free()
 98  {
 99   // Check if the handle was never initialized for was freed.
100   if (m_handle == IntPtr.Zero)
101    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
102
103   // Free the handle.
104   InternalFree(GetHandleValue());
105   m_handle = IntPtr.Zero;
106  }

107  
108  internal void __InternalFree()
109  {
110   // Check if the handle was never initialized for was freed.
111   if (m_handle == IntPtr.Zero)
112    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
113
114   // Free the handle.
115   InternalFree(GetHandleValue());
116   m_handle = IntPtr.Zero;
117  }

118
119        // Target property - allows getting / updating of the handle's referent. If you modify this method
120
121        // then modify the __InternalTarget too which is the internal method without the linktime check.
122        /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Target"]/*' />
123        public Object Target
124        {
125         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
126            get
127            {
128                // Check if the handle was never initialized or was freed.
129    if (m_handle == IntPtr.Zero)
130     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
131
132                return InternalGet(GetHandleValue());
133            }

134    
135         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
136            set
137            {
138                // Check if the handle was never initialized or was freed.
139    if (m_handle == IntPtr.Zero)
140     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
141
142                InternalSet(GetHandleValue(), value, IsPinned());
143            }

144        }

145        
146        internal Object __InternalTarget
147        {
148            get
149            {
150                // Check if the handle was never initialized or was freed.
151    if (m_handle == IntPtr.Zero)
152     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
153
154                return InternalGet(GetHandleValue());
155            }

156        }

157
158        // Retrieve the address of an object in a Pinned handle.  This throws
159  // an exception if the handle is any type other than Pinned.
160  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.AddrOfPinnedObject"]/*' />
161        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
162  public IntPtr AddrOfPinnedObject()
163  {
164   // Check if the handle was not a pinned handle.
165   if (!IsPinned())
166   {
167    // Check if the handle was never initialized for was freed.
168    if (m_handle == IntPtr.Zero)
169     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
170
171    // You can only get the address of pinned handles.
172    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned"));
173   }

174
175   // Get the address.
176   return InternalAddrOfPinnedObject(GetHandleValue());
177  }

178
179        // Determine whether this handle has been allocated or not.
180  /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.IsAllocated"]/*' />
181  public bool IsAllocated
182  {
183   get
184   {
185    return m_handle != IntPtr.Zero;
186   }

187  }

188
189        // Used to create a GCHandle from an int.  This is intended to
190  // be used with the reverse conversion.
191     /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorGCHandle"]/*' />
192        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
193     public static explicit operator GCHandle(IntPtr value)
194  {
195            return new GCHandle(value);
196        }

197
198 // Used to get the internal integer representation of the handle out.
199     /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorIntPtr"]/*' />
200     public static explicit operator IntPtr(GCHandle value)
201  {
202            return value.m_handle;
203        }

204
205        internal IntPtr GetHandleValue()
206        {
207#if WIN32
208            return new IntPtr(((int)m_handle) & ~1);
209#else
210            return new IntPtr(((long)m_handle) & ~1L);
211#endif
212        }

213
214        internal bool IsPinned()
215        {
216#if WIN32
217            return (((int)m_handle) & 1!= 0;
218#else
219            return (((long)m_handle) & 1!= 0;
220#endif
221        }

222
223        internal void SetIsPinned()
224        {
225#if WIN32
226            m_handle = new IntPtr(((int)m_handle) | 1);
227#else
228            m_handle = new IntPtr(((long)m_handle) | 1L);
229#endif
230        }

231
232  // Internal native calls that this implementation uses.
233        [MethodImplAttribute(MethodImplOptions.InternalCall)]
234  internal static extern IntPtr InternalAlloc(Object value, GCHandleType type);
235        [MethodImplAttribute(MethodImplOptions.InternalCall)]
236        internal static extern void InternalFree(IntPtr handle);
237        [MethodImplAttribute(MethodImplOptions.InternalCall)]
238        internal static extern Object InternalGet(IntPtr handle);
239        [MethodImplAttribute(MethodImplOptions.InternalCall)]
240        internal static extern void InternalSet(IntPtr handle, Object value, bool isPinned);
241        [MethodImplAttribute(MethodImplOptions.InternalCall)]
242        internal static extern void InternalCompareExchange(IntPtr handle, Object value, Object oldValue, bool isPinned);
243        [MethodImplAttribute(MethodImplOptions.InternalCall)]
244  internal static extern IntPtr InternalAddrOfPinnedObject(IntPtr handle);
245        [MethodImplAttribute(MethodImplOptions.InternalCall)]
246  internal static extern void InternalCheckDomain(IntPtr handle);
247
248
249  // The actual integer handle value that the EE uses internally.
250  private IntPtr m_handle;
251    }

252}

253
254
posted on 2005-08-04 00:52  wanna  阅读(611)  评论(0编辑  收藏  举报