1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System.Runtime.InteropServices
{
using System;
using System.Security.Permissions;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
// These are the types of handles used by the EE.
// IMPORTANT: These must match the definitions in ObjectHandle.h in the EE.
// IMPORTANT: If new values are added to the enum the GCHandle::MaxHandleType
// constant must be updated.
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum GCHandleType
{
Weak = 0,
WeakTrackResurrection = 1,
Normal = 2,
Pinned = 3
}
// This class allows you to create an opaque, GC handle to any
// COM+ object. A GC handle is used when an object reference must be
// reachable from unmanaged memory. There are 3 kinds of roots:
// Normal - keeps the object from being collected.
// Weak - allows object to be collected and handle contents will be zeroed.
// Weak references are zeroed before the finalizer runs, so if the
// object is resurrected in the finalizer the weak reference is
// still zeroed.
// WeakTrackResurrection - Same as weak, but stays until after object is
// really gone.
// Pinned - same as normal, but allows the address of the actual object
// to be taken.
//
[StructLayout(LayoutKind.Sequential)]
[System.Runtime.InteropServices.ComVisible(true)]
public struct GCHandle
{
// IMPORTANT: This must be kept in sync with the GCHandleType enum.
private const GCHandleType MaxHandleType = GCHandleType.Pinned;
#if MDA_SUPPORTED
[System.Security.SecuritySafeCritical] // auto-generated
static GCHandle()
{
s_probeIsActive = Mda.IsInvalidGCHandleCookieProbeEnabled();
if (s_probeIsActive)
s_cookieTable = new GCHandleCookieTable();
}
#endif
// Allocate a handle storing the object and the type.
[System.Security.SecurityCritical] // auto-generated
internal GCHandle(Object value, GCHandleType type)
{
// Make sure the type parameter is within the valid range for the enum.
if ((uint)type > (uint)MaxHandleType)
throw new ArgumentOutOfRangeException("type", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
Contract.EndContractBlock();
m_handle = InternalAlloc(value, type);
// Record if the handle is pinned.
if (type == GCHandleType.Pinned)
SetIsPinned();
}
// Used in the conversion functions below.
[System.Security.SecurityCritical] // auto-generated
internal GCHandle(IntPtr handle)
{
InternalCheckDomain(handle);
m_handle = handle;
}
// Creates a new GC handle for an object.
//
// value - The object that the GC handle is created for.
// type - The type of GC handle to create.
//
// returns a new GC handle that protects the object.
[System.Security.SecurityCritical] // auto-generated_required
public static GCHandle Alloc(Object value)
{
return new GCHandle(value, GCHandleType.Normal);
}
[System.Security.SecurityCritical] // auto-generated_required
public static GCHandle Alloc(Object value, GCHandleType type)
{
return new GCHandle(value, type);
}
// Frees a GC handle.
[System.Security.SecurityCritical] // auto-generated_required
public void Free()
{
// Copy the handle instance member to a local variable. This is required to prevent
// race conditions releasing the handle.
IntPtr handle = m_handle;
// Free the handle if it hasn't already been freed.
if (handle != IntPtr.Zero && Interlocked.CompareExchange(ref m_handle, IntPtr.Zero, handle) == handle)
{
#if MDA_SUPPORTED
// If this handle was passed out to unmanaged code, we need to remove it
// from the cookie table.
// NOTE: the entry in the cookie table must be released before the
// internal handle is freed to prevent a race with reusing GC handles.
if (s_probeIsActive)
s_cookieTable.RemoveHandleIfPresent(handle);
#endif
#if WIN32
InternalFree((IntPtr)(((int)handle) & ~1));
#else
InternalFree((IntPtr)(((long)handle) & ~1L));
#endif
}
else
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
}
}
// Target property - allows getting / updating of the handle's referent.
public Object Target
{
[System.Security.SecurityCritical] // auto-generated_required
get
{
// Check if the handle was never initialized or was freed.
if (m_handle == IntPtr.Zero)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
return InternalGet(GetHandleValue());
}
[System.Security.SecurityCritical] // auto-generated_required
set
{
// Check if the handle was never initialized or was freed.
if (m_handle == IntPtr.Zero)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
InternalSet(GetHandleValue(), value, IsPinned());
}
}
// Retrieve the address of an object in a Pinned handle. This throws
// an exception if the handle is any type other than Pinned.
[System.Security.SecurityCritical] // auto-generated_required
public IntPtr AddrOfPinnedObject()
{
// Check if the handle was not a pinned handle.
if (!IsPinned())
{
// Check if the handle was never initialized for was freed.
if (m_handle == IntPtr.Zero)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
// You can only get the address of pinned handles.
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned"));
}
// Get the address.
return InternalAddrOfPinnedObject(GetHandleValue());
}
// Determine whether this handle has been allocated or not.
public bool IsAllocated
{
get
{
return m_handle != IntPtr.Zero;
}
}
// Used to create a GCHandle from an int. This is intended to
// be used with the reverse conversion.
[System.Security.SecurityCritical] // auto-generated_required
public static explicit operator GCHandle(IntPtr value)
{
return FromIntPtr(value);
}
[System.Security.SecurityCritical] // auto-generated_required
public static GCHandle FromIntPtr(IntPtr value)
{
if (value == IntPtr.Zero)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
Contract.EndContractBlock();
IntPtr handle = value;
#if MDA_SUPPORTED
if (s_probeIsActive)
{
// Make sure this cookie matches up with a GCHandle we've passed out a cookie for.
handle = s_cookieTable.GetHandle(value);
if (IntPtr.Zero == handle)
{
// Fire an MDA if we were unable to retrieve the GCHandle.
Mda.FireInvalidGCHandleCookieProbe(value);
return new GCHandle(IntPtr.Zero);
}
}
#endif
return new GCHandle(handle);
}
// Used to get the internal integer representation of the handle out.
public static explicit operator IntPtr(GCHandle value)
{
return ToIntPtr(value);
}
public static IntPtr ToIntPtr(GCHandle value)
{
#if MDA_SUPPORTED
if (s_probeIsActive)
{
// Remember that we passed this GCHandle out by storing the cookie we returned so we
// can later validate.
return s_cookieTable.FindOrAddHandle(value.m_handle);
}
#endif
return value.m_handle;
}
public override int GetHashCode()
{
return m_handle.GetHashCode();
}
public override bool Equals(Object o)
{
GCHandle hnd;
// Check that o is a GCHandle first
if(o == null || !(o is GCHandle))
return false;
else
hnd = (GCHandle) o;
return m_handle == hnd.m_handle;
}
public static bool operator ==(GCHandle a, GCHandle b)
{
return a.m_handle == b.m_handle;
}
public static bool operator !=(GCHandle a, GCHandle b)
{
return a.m_handle != b.m_handle;
}
internal IntPtr GetHandleValue()
{
#if WIN32
return new IntPtr(((int)m_handle) & ~1);
#else
return new IntPtr(((long)m_handle) & ~1L);
#endif
}
internal bool IsPinned()
{
#if WIN32
return (((int)m_handle) & 1) != 0;
#else
return (((long)m_handle) & 1) != 0;
#endif
}
internal void SetIsPinned()
{
#if WIN32
m_handle = new IntPtr(((int)m_handle) | 1);
#else
m_handle = new IntPtr(((long)m_handle) | 1L);
#endif
}
// Internal native calls that this implementation uses.
[System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[ResourceExposure(ResourceScope.None)]
internal static extern IntPtr InternalAlloc(Object value, GCHandleType type);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void InternalFree(IntPtr handle);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern Object InternalGet(IntPtr handle);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void InternalSet(IntPtr handle, Object value, bool isPinned);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern Object InternalCompareExchange(IntPtr handle, Object value, Object oldValue, bool isPinned);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern IntPtr InternalAddrOfPinnedObject(IntPtr handle);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void InternalCheckDomain(IntPtr handle);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern GCHandleType InternalGetHandleType(IntPtr handle);
// The actual integer handle value that the EE uses internally.
private IntPtr m_handle;
#if MDA_SUPPORTED
// The GCHandle cookie table.
static private volatile GCHandleCookieTable s_cookieTable = null;
static private volatile bool s_probeIsActive = false;
#endif
}
}
|