// 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
+ // keep a reference to the proxy so it doesn't get garbage collected before the RCW
+ ComInteropProxy proxy;
+
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern __ComObject CreateRCW (Type t);
private extern void ReleaseInterfaces ();
~__ComObject ()
- {
- ReleaseInterfaces ();
+ {
+ if (hash_table != IntPtr.Zero) {
+ if (synchronization_context != null)
+ synchronization_context.Post ((state) => ReleaseInterfaces (), this);
+ else
+ ReleaseInterfaces ();
+ }
+ proxy = null;
}
public __ComObject ()
{
- Type t = GetType ();
- 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);
- }
+ Initialize (GetType ());
}
internal __ComObject (Type t) {
+ Initialize (t);
+ }
+
+ 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);
+ }
+
+ internal void Initialize (IntPtr pUnk, ComInteropProxy p)
+ {
+ proxy = p;
+ InitializeApartmentDetails ();
+ iunknown = pUnk;
+ }
+
+ internal void Initialize (Type t)
+ {
+ InitializeApartmentDetails ();
+ // Guard multiple invocation.
+ if (iunknown != IntPtr.Zero)
+ return;
+
+ iunknown = CreateIUnknown (t);
+ }
+
+ 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);
int hr = CoCreateInstance (GetCLSID (t), IntPtr.Zero, 0x1 | 0x4 | 0x10, IID_IUnknown, out iunknown);
Marshal.ThrowExceptionForHR (hr);
}
+
+ return iunknown;
}
- internal __ComObject (IntPtr pItf)
+ private void InitializeApartmentDetails ()
{
- Guid iid = IID_IUnknown;
- int hr = Marshal.QueryInterface (pItf, ref iid, out iunknown);
- Marshal.ThrowExceptionForHR (hr);
+ // 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)
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