//
//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
//
using System;
+using System.Threading;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Runtime.InteropServices
{
-#if NET_2_0
[ComVisible(true)]
-#endif
[MonoTODO("Struct should be [StructLayout(LayoutKind.Sequential)] but will need to be reordered for that.")]
public struct GCHandle
{
: this(obj, GCHandleType.Normal)
{}
- private GCHandle(object value, GCHandleType type)
+ internal GCHandle(object value, GCHandleType type)
{
+ // MS does not crash/throw on (most) invalid GCHandleType values (except -1)
+ if ((type < GCHandleType.Weak) || (type > GCHandleType.Pinned))
+ type = GCHandleType.Normal;
handle = GetTargetHandle (value, 0, type);
}
{
get
{
+ if (!IsAllocated)
+ throw new InvalidOperationException (Locale.GetText ("Handle is not allocated"));
return GetTarget (handle);
}
set
public IntPtr AddrOfPinnedObject()
{
IntPtr res = GetAddrOfPinnedObject(handle);
- if (res == IntPtr.Zero)
- throw new InvalidOperationException("The handle is not of Pinned type");
if (res == (IntPtr)(-1))
throw new ArgumentException ("Object contains non-primitive or non-blittable data.");
+ if (res == (IntPtr)(-2))
+ throw new InvalidOperationException("Handle is not pinned.");
return res;
}
public void Free()
{
- FreeHandle(handle);
- handle = 0;
+ // Copy the handle instance member to a local variable. This is required to prevent
+ // race conditions releasing the handle.
+ int local_handle = handle;
+
+ // Free the handle if it hasn't already been freed.
+ if (local_handle != 0 && Interlocked.CompareExchange (ref handle, 0, local_handle) == local_handle) {
+ FreeHandle (local_handle);
+ }
+ else {
+ throw new InvalidOperationException ("Handle is not initialized.");
+ }
}
public static explicit operator IntPtr (GCHandle value)
public static explicit operator GCHandle(IntPtr value)
{
if (value == IntPtr.Zero)
- throw new ArgumentException ("GCHandle value cannot be zero");
+ throw new InvalidOperationException ("GCHandle value cannot be zero");
if (!CheckCurrentDomain ((int)value))
throw new ArgumentException ("GCHandle value belongs to a different domain");
return new GCHandle (value);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static IntPtr GetAddrOfPinnedObject(int handle);
-#if NET_2_0
public static bool operator ==(GCHandle a, GCHandle b)
{
- return a.Equals(b);
+ return a.handle == b.handle;
}
public static bool operator !=(GCHandle a, GCHandle b)
{
- return (!(a.Equals(b)));
+ return !(a == b);
}
public override bool Equals(object o)
{
- if (o == null || !(o is GCHandle))
- return false;
-
- return (handle == ((GCHandle)o).handle);
+ return o is GCHandle ? this == (GCHandle)o : false;
}
public override int GetHashCode()
{
return (IntPtr)value;
}
-#endif
}
}