Add support for COM Callable Wrappers.
svn path=/trunk/mcs/; revision=72505
+2007-02-08 Jonathan Chambers <joncham@gmail.com>
+
+ * ComInteropProxy.cs: Moved some code to unmanaged and cleanup some things.
+
2006-10-18 Jonathan Chambers <joncham@gmail.com>
* IUnknown.cs: Added.
namespace Mono.Interop
{
- internal struct ComInteropProxyEntry
- {
- public int refcount;
- public WeakReference weakref;
-
- public ComInteropProxyEntry (int refcount, WeakReference weak)
- {
- this.refcount = refcount;
- this.weakref = weak;
- }
- }
-
internal class ComInteropProxy : RealProxy, IRemotingTypeInfo
{
- #region Sync with object-internals.h
- private __ComObject com_object;
+ #region Sync with object-internals.h\r
+ private __ComObject com_object;\r
+ int ref_count = 1; // wrapper ref count
#endregion
- private string type_name;
- static Hashtable iunknown_hashtable;
-
- static ComInteropProxy ()
- {
- iunknown_hashtable = new Hashtable ();
- }
+ private string type_name;\r
+\r
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]\r
+ private extern static void AddProxy (IntPtr pItf, ComInteropProxy proxy);\r
+\r
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]\r
+ internal extern static ComInteropProxy FindProxy (IntPtr pItf);
public ComInteropProxy (Type t)
: base (t)
internal void CacheProxy ()
{
// called from unmanaged code after .ctor is invoked
- // we need .ctor to create unmanaged object and thus IUnknown property value
- iunknown_hashtable.Add (com_object.IUnknown, new ComInteropProxyEntry (1, new WeakReference (this)));
+ // we need .ctor to create unmanaged object and thus IUnknown property value\r
+ AddProxy (com_object.IUnknown, this);
}
internal ComInteropProxy (IntPtr pUnk)
internal ComInteropProxy (IntPtr pUnk, Type t)
: base (t)
{
- com_object = new __ComObject (pUnk);
- iunknown_hashtable.Add (com_object.IUnknown, new ComInteropProxyEntry (1, new WeakReference (this)));
- }
-
- internal static int ReleaseComObject (__ComObject co)
- {
- if (co == null)
- throw new ArgumentNullException ("co");
- int refcount = -1;
- IntPtr pUnk = co.IUnknown;
- object obj = iunknown_hashtable[pUnk];
- if (obj != null) {
- ComInteropProxyEntry entry = (ComInteropProxyEntry)obj;
- refcount = entry.refcount - 1;
- if (refcount == 0) {
- iunknown_hashtable.Remove (pUnk);
- ComInteropProxy proxy = (ComInteropProxy)entry.weakref.Target;
- if (proxy != null && proxy.com_object != null)
- proxy.com_object.Finalizer ();
- }
- else {
- iunknown_hashtable[pUnk] = new ComInteropProxyEntry (refcount, entry.weakref);
- }
- }
- return refcount;
+ com_object = new __ComObject (pUnk);\r
+ CacheProxy ();
}
internal static ComInteropProxy GetProxy (IntPtr pItf, Type t)
IntPtr ppv;
Guid iid = __ComObject.IID_IUnknown;
int hr = Marshal.QueryInterface (pItf, ref iid, out ppv);
- Marshal.ThrowExceptionForHR (hr);
- object obj = iunknown_hashtable[ppv];
+ Marshal.ThrowExceptionForHR (hr);\r
+ ComInteropProxy obj = FindProxy (ppv);
if (obj == null) {
return new ComInteropProxy (ppv);
}
- else {
- ComInteropProxyEntry entry = ((ComInteropProxyEntry)obj);
- WeakReference weak_ref = entry.weakref;
- object target = weak_ref.Target;
- if (target == null) {
- return new ComInteropProxy (ppv);
- }
- iunknown_hashtable[ppv] = new ComInteropProxyEntry (entry.refcount + 1, weak_ref);
- return ((ComInteropProxy)target);
+ else {\r
+ System.Threading.Interlocked.Increment (ref obj.ref_count);\r
+ return obj;
}
}
public override IMessage Invoke (IMessage msg)
{
Console.WriteLine ("Invoke");
+ Console.WriteLine (System.Environment.StackTrace);
throw new Exception ("The method or operation is not implemented.");
}
+2007-02-08 Jonathan Chambers <joncham@gmail.com>
+
+ * Marshal.cs: Throw exceptions for AddRef, Release,
+ and QueryInterface in managed code. Implement GetComInterfaceForObject,
+ GetIDispatchForObject, GetIUnknownForObject, GetObjectForIUnknown,
+ GetObjectsForNativeVariants, IsComObject, ReleaseComObject, and
+ FinalReleaseComObject. Unimplement GetComObjectData and SetComObjectData
+ for now to save space and simplify __ComObject for now. MSDN states the
+ user should never call these methods anyway.
+
2007-01-29 Marek Habersack <grendello@gmail.com>
* Marshal.cs: Implement a missing Marshal.Copy overload.
//
using Mono.Interop;
+using System.Collections;
using System.Runtime.CompilerServices;
using System;
using System.Security;
#endif
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- public extern static int AddRef (IntPtr pUnk);
+ private extern static int AddRefInternal (IntPtr pUnk);
+
+ public static int AddRef (IntPtr pUnk)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentException ("Value cannot be null.", "pUnk");
+ return AddRefInternal (pUnk);
+ }
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static IntPtr AllocCoTaskMem (int cb);
throw new NotImplementedException ();
}
- [MonoTODO]
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static IntPtr GetCCW (object o, Type T);
+
+ private static IntPtr GetComInterfaceForObjectInternal (object o, Type T)
+ {
+ if (IsComObject (o))
+ return ((__ComObject)o).GetInterface (T);
+ else
+ return GetCCW (o, T);
+ }
+
public static IntPtr GetComInterfaceForObject (object o, Type T)
{
- __ComObject co = o as __ComObject;
- if (co == null)
- throw new NotSupportedException ("Only RCWs are currently supported");
-
- IntPtr pUnk = co.GetInterface (T);
- AddRef (pUnk);
- return pUnk;
+ IntPtr pItf = GetComInterfaceForObjectInternal (o, T);
+ AddRef (pItf);
+ return pItf;
}
#if NET_2_0
}
#endif
+ [MonoNotSupportedAttribute ("MSDN states user code should never need to call this method.")]
public static object GetComObjectData (object obj, object key)
{
- if (obj == null)
- throw new ArgumentNullException ("obj");
- if (key == null)
- throw new ArgumentNullException ("key");
-
- __ComObject com_object = obj as __ComObject;
- if (com_object == null)
- throw new ArgumentException ("obj is not a COM object", "obj");
-
- return com_object.Hashtable[key];
+ throw new NotSupportedException ("MSDN states user code should never need to call this method.");
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
throw new NotImplementedException ();
}
- [MonoTODO]
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static IntPtr GetIDispatchForObjectInternal (object o);
+
public static IntPtr GetIDispatchForObject (object o)
{
- // only handle case of RCW objects for now
- __ComObject co = o as __ComObject;
- if (co != null) {
- IntPtr pUnk = co.IDispatch;
- AddRef (pUnk);
- return pUnk;
- }
- throw new NotImplementedException ();
+ IntPtr pUnk = GetIDispatchForObjectInternal (o);
+ // Internal method does not AddRef
+ AddRef (pUnk);
+ return pUnk;
}
#if NET_2_0
throw new NotImplementedException ();
}
- [MonoTODO]
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static IntPtr GetIUnknownForObjectInternal (object o);
+
public static IntPtr GetIUnknownForObject (object o)
{
- // only handle case of RCW objects for now
- __ComObject co = o as __ComObject;
- if (co != null) {
- IntPtr pUnk = co.IUnknown;
- AddRef (pUnk);
- return pUnk;
- }
- throw new NotImplementedException ();
+ IntPtr pUnk = GetIUnknownForObjectInternal (o);
+ // Internal method does not AddRef
+ AddRef (pUnk);
+ return pUnk;
}
#if NET_2_0
Marshal.StructureToPtr(vt, pDstNativeVariant, false);
}
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private static extern object GetObjectForCCW (IntPtr pUnk);
+
public static object GetObjectForIUnknown (IntPtr pUnk)
{
- ComInteropProxy proxy = ComInteropProxy.GetProxy (pUnk, typeof(__ComObject));
- return proxy.GetTransparentProxy ();
+ object obj = GetObjectForCCW (pUnk);
+ // was not a CCW
+ if (obj == null) {
+ ComInteropProxy proxy = ComInteropProxy.GetProxy (pUnk, typeof (__ComObject));
+ obj = proxy.GetTransparentProxy ();
+ }
+ return obj;
}
public static object GetObjectForNativeVariant (IntPtr pSrcNativeVariant)
return vt.GetValue();
}
- [MonoTODO]
public static object[] GetObjectsForNativeVariants (IntPtr aSrcNativeVariant, int cVars)
{
- throw new NotImplementedException ();
+ if (cVars < 0)
+ throw new ArgumentOutOfRangeException ("cVars", "cVars cannot be a negative number.");
+ object[] objects = new object[cVars];
+ for (int i = 0; i < cVars; i++)
+ objects[i] = GetObjectForNativeVariant ((IntPtr)(aSrcNativeVariant.ToInt64 () +
+ i * SizeOf (typeof(Variant))));
+ return objects;
}
[MonoTODO]
throw new NotImplementedException ();
}
- public static bool IsComObject (object o)
- {
- Type t = o.GetType ();
- object[] attrs = t.GetCustomAttributes (typeof (ComImportAttribute), true);
- return (attrs != null && attrs.Length > 0);
- }
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ public extern static bool IsComObject (object o);
[MonoTODO]
public static bool IsTypeVisibleFromCom (Type t)
public extern static object PtrToStructure (IntPtr ptr, Type structureType);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- public extern static int QueryInterface (IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+ private extern static int QueryInterfaceInternal (IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+
+ public static int QueryInterface (IntPtr pUnk, ref Guid iid, out IntPtr ppv)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentException ("Value cannot be null.", "pUnk");
+ return QueryInterfaceInternal (pUnk, ref iid, out ppv);
+ }
public static byte ReadByte (IntPtr ptr)
{
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
#endif
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- public extern static int Release (IntPtr pUnk);
+ private extern static int ReleaseInternal (IntPtr pUnk);
+
+ public static int Release (IntPtr pUnk)
+ {
+ if (pUnk == IntPtr.Zero)
+ throw new ArgumentException ("Value cannot be null.", "pUnk");
+ return ReleaseInternal (pUnk);
+ }
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern static int ReleaseComObjectInternal (object co);
public static int ReleaseComObject (object o)
{
if (o == null)
- throw new ArgumentException ("o");
- __ComObject co = o as __ComObject;
- if (co == null)
- throw new ArgumentException ("o");
- return ComInteropProxy.ReleaseComObject (co);
+ throw new ArgumentException ("Value cannot be null.", "o");
+ if (!IsComObject (o))
+ throw new ArgumentException ("Value must be a Com object.", "o");
+ return ReleaseComObjectInternal (o);
}
#if NET_2_0
throw new NotImplementedException ();
}
+ [MonoNotSupportedAttribute ("MSDN states user code should never need to call this method.")]
public static bool SetComObjectData (object obj, object key, object data)
{
- if (obj == null)
- throw new ArgumentNullException ("obj");
- if (key == null)
- throw new ArgumentNullException ("key");
-
- __ComObject com_object = obj as __ComObject;
- if (com_object == null)
- throw new ArgumentException ("obj is not a COM object", "obj");
-
- com_object.Hashtable[key] = data;
- return true;
+ throw new NotSupportedException ("MSDN states user code should never need to call this method.");
}
public static int SizeOf (object structure)
}
#if NET_2_0
- [MonoTODO]
public static int FinalReleaseComObject (object o)
{
- throw new NotImplementedException ();
+ while (ReleaseComObject (o) != 0);
+ return 0;
}
[MonoTODO]
+2007-02-08 Jonathan Chambers <joncham@gmail.com>
+
+ * __ComObject.cs: Add IUnknown field to object. Cleanup icalls.
+
2007-02-03 Zoltan Varga <vargaz@gmail.com>
* BitConverter.cs (ToDouble): Fix this on big-endian machines.
internal class __ComObject : MarshalByRefObject
{
#region Sync with object-internals.h
+ IntPtr iunknown;
IntPtr hash_table;
#endregion
- // this is used internally and for the the methods
- // Marshal.GetComObjectData and Marshal.SetComObjectData
- Hashtable hashtable;
-
[ThreadStatic]
static bool coinitialized;
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- internal extern void Finalizer ();
+ internal static extern __ComObject CreateRCW (Type t);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private static extern void AddInterface (__ComObject co, Type t, IntPtr pItf);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private static extern IntPtr FindInterface (__ComObject co, Type t);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void ReleaseInterfaces ();
~__ComObject ()
{
- ComInteropProxy.ReleaseComObject (this);
- Finalizer ();
+ ReleaseInterfaces ();
}
public __ComObject ()
coinitialized = true;
}
- hashtable = new Hashtable ();
-
- IntPtr ppv;
Type t = GetType ();
- int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+ int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
Marshal.ThrowExceptionForHR (hr);
-
- SetIUnknown (ppv);
}
internal __ComObject (Type t)
coinitialized = true;
}
- hashtable = new Hashtable ();
-
- IntPtr ppv;
- int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+ int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
Marshal.ThrowExceptionForHR (hr);
+ }
- SetIUnknown (ppv);
+ internal __ComObject (IntPtr pItf)
+ {
+ Guid iid = IID_IUnknown;
+ int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
+ Marshal.ThrowExceptionForHR (hr);
}
- private Guid GetCLSID (Type t)
+ private static Guid GetCLSID (Type t)
{
if (t.IsImport)
return t.GUID;
throw new COMException ("Could not find base COM type for type " + t.ToString());
}
- internal __ComObject (IntPtr pItf)
- {
- hashtable = new Hashtable ();
- IntPtr ppv;
- Guid iid = IID_IUnknown;
- int hr = Marshal.QueryInterface (pItf, ref iid, out ppv);
- Marshal.ThrowExceptionForHR (hr);
- SetIUnknown (ppv);
- }
-
- public Hashtable Hashtable
- {
- get
- {
- return hashtable;
- }
- }
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- internal static extern __ComObject CreateRCW (Type t);
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern void SetIUnknown (IntPtr t);
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern IntPtr GetIUnknown ();
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern IntPtr FindInterface (Type t);
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern void CacheInterface (Type t, IntPtr pItf);
-
internal IntPtr GetInterface(Type t)
{
- // this is needed later and checks to see if we are
- // a valid RCW
- IntPtr pUnk = IUnknown;
- IntPtr pItf = FindInterface (t);
+ CheckIUnknown ();
+ IntPtr pItf = FindInterface (this, t);
if (pItf != IntPtr.Zero) {
return pItf;
}
Guid iid = t.GUID;
IntPtr ppv;
- int hr = Marshal.QueryInterface (pUnk, ref iid, out ppv);
+ int hr = Marshal.QueryInterface (iunknown, ref iid, out ppv);
Marshal.ThrowExceptionForHR (hr);
- CacheInterface (t, ppv);
+ AddInterface (this, t, ppv);
return ppv;
}
+ private void CheckIUnknown ()
+ {
+ if (iunknown == IntPtr.Zero)
+ throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
+ }
+
internal IntPtr IUnknown
{
get
{
- IntPtr pUnk = GetIUnknown();
- if (pUnk == IntPtr.Zero)
+ if (iunknown == IntPtr.Zero)
throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
- return pUnk;
+ return iunknown;
}
}
public override bool Equals (object obj)
{
+ CheckIUnknown ();
if (obj == null)
return false;
__ComObject co = obj as __ComObject;
if ((object)co == null)
return false;
-
- return (IUnknown == co.IUnknown);
+ return (iunknown == co.IUnknown);
}
public override int GetHashCode ()
{
+ CheckIUnknown ();
// not what MS seems to do,
// but IUnknown is identity in COM
- return IUnknown.ToInt32 ();
+ return iunknown.ToInt32 ();
}
[DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall)]