// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+#if !FULL_AOT_RUNTIME
using Mono.Interop;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
+using System.Threading;
namespace System
{
// many times that obj.GetType().FullName == "System.__ComObject" and
// Type.GetType("System.__ComObject") may be used.
+ [StructLayout (LayoutKind.Sequential)]
internal class __ComObject : MarshalByRefObject
{
+#pragma warning disable 169
#region Sync with object-internals.h
+ IntPtr iunknown;
IntPtr hash_table;
+ SynchronizationContext synchronization_context;
#endregion
+#pragma warning restore 169
- // this is used internally and for the the methods
- // Marshal.GetComObjectData and Marshal.SetComObjectData
- Hashtable hashtable;
+ // keep a reference to the proxy so it doesn't get garbage collected before the RCW
+ ComInteropProxy proxy;
- [ThreadStatic]
- static bool coinitialized;
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ internal static extern __ComObject CreateRCW (Type t);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
- internal extern void Finalizer ();
+ private extern void ReleaseInterfaces ();
~__ComObject ()
- {
- ComInteropProxy.ReleaseComObject (this);
- Finalizer ();
+ {
+ if (hash_table != IntPtr.Zero) {
+ if (synchronization_context != null)
+ synchronization_context.Post ((state) => ReleaseInterfaces (), this);
+ else
+ ReleaseInterfaces ();
+ }
+ proxy = null;
}
public __ComObject ()
{
- // call CoInitialize once per thread
- if (!coinitialized) {
- CoInitialize (IntPtr.Zero);
- coinitialized = true;
- }
+ Initialize (GetType ());
+ }
- hashtable = new Hashtable ();
+ internal __ComObject (Type t) {
+ Initialize (t);
+ }
- IntPtr ppv;
- Type t = GetType ();
- int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
+ internal __ComObject (IntPtr pItf, ComInteropProxy p)
+ {
+ proxy = p;
+ InitializeApartmentDetails ();
+ Guid iid = IID_IUnknown;
+ int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
Marshal.ThrowExceptionForHR (hr);
+ }
- SetIUnknown (ppv);
+ internal void Initialize (IntPtr pUnk, ComInteropProxy p)
+ {
+ proxy = p;
+ InitializeApartmentDetails ();
+ iunknown = pUnk;
}
- internal __ComObject (Type t)
+ internal void Initialize (Type t)
{
- // call CoInitialize once per thread
- if (!coinitialized) {
- CoInitialize (IntPtr.Zero);
- coinitialized = true;
- }
+ InitializeApartmentDetails ();
+ // Guard multiple invocation.
+ if (iunknown != IntPtr.Zero)
+ return;
- hashtable = new Hashtable ();
+ iunknown = CreateIUnknown (t);
+ }
- IntPtr ppv;
- int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out ppv);
- Marshal.ThrowExceptionForHR (hr);
+ internal static IntPtr CreateIUnknown(Type t)
+ {
+ System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (t.TypeHandle);
+
+ IntPtr iunknown;
+ ObjectCreationDelegate ocd = ExtensibleClassFactory.GetObjectCreationCallback (t);
+ if (ocd != null) {
+ iunknown = ocd (IntPtr.Zero);
+ if (iunknown == IntPtr.Zero)
+ throw new COMException (string.Format("ObjectCreationDelegate for type {0} failed to return a valid COM object", t));
+ }
+ else {
+ int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
+ Marshal.ThrowExceptionForHR (hr);
+ }
- SetIUnknown (ppv);
+ return iunknown;
}
- private Guid GetCLSID (Type t)
+ private void InitializeApartmentDetails ()
+ {
+ // Only synchronization_context if thread is STA.
+ if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
+ return;
+
+ synchronization_context = SynchronizationContext.Current;
+
+ // Check whether the current context is a plain SynchronizationContext object
+ // and handle this as if no context was set at all.
+ if (synchronization_context != null &&
+ synchronization_context.GetType () == typeof(SynchronizationContext))
+ synchronization_context = null;
+ }
+
+ 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);
+ internal extern IntPtr GetInterfaceInternal (Type t, bool throwException);
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- extern void CacheInterface (Type t, IntPtr pItf);
+ internal IntPtr GetInterface (Type t, bool throwException) {
+ CheckIUnknown ();
+ return GetInterfaceInternal (t, throwException);
+ }
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);
- if (pItf != IntPtr.Zero) {
- return pItf;
- }
+ return GetInterface (t, true);
+ }
- Guid iid = t.GUID;
- IntPtr ppv;
- int hr = Marshal.QueryInterface (pUnk, ref iid, out ppv);
- Marshal.ThrowExceptionForHR (hr);
- CacheInterface (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;
}
}
{
get
{
- IntPtr pUnk = GetInterface (typeof (IDispatchMono));
+ IntPtr pUnk = GetInterface (typeof (IDispatch));
if (pUnk == IntPtr.Zero)
throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
return pUnk;
}
}
- [Guid ("00020400-0000-0000-C000-000000000046")]
- internal interface IDispatchMono
- {
- }
-
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)]
- static extern int CoInitialize (IntPtr pvReserved);
-
[DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
static extern int CoCreateInstance (
[In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,
out IntPtr pUnk);
}
}
+#else
+namespace System
+{
+ // this is a shim class so we can AOT during mobile_static build without --enable-minimal=com
+ internal class __ComObject
+ {
+ __ComObject ()
+ {
+ throw new NotSupportedException ();
+ }
+ }
+}
+#endif