Xamarin Public Jenkins (auto-signing) 6bdd276d05 Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
2017-04-10 11:41:01 +00:00

268 lines
7.3 KiB
C#

//
// System.__ComObject
//
// Authors:
// Sebastien Pouliot <sebastien@ximian.com>
// Kornél Pál <http://www.kornelpal.hu/>
// Jonathan Chambers <joncham@gmail.com>
//
// Copyright (C) 2004 Novell (http://www.novell.com)
// Copyright (C) 2005 Kornél Pál
// Copyright (C) 2006 Jonathan Chambers
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// 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
{
// This is a private class that is used as a generic wrapper class
// for COM objects that have no specific wrapper class.
//
// It has no public methods, it's functionality is exposed trough
// System.Runtime.InteropServices.Marshal class and can be casted to
// any interface that is implemented by the wrapped COM object.
//
// This class is referenced in .NET Framework SDK Documentation so
// 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);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern void ReleaseInterfaces ();
~__ComObject ()
{
if (hash_table != IntPtr.Zero) {
if (synchronization_context != null)
synchronization_context.Post ((state) => ReleaseInterfaces (), this);
else
ReleaseInterfaces ();
}
proxy = null;
}
public __ComObject ()
{
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);
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);
}
return iunknown;
}
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;
// look at supertypes
Type super = t.BaseType;
while (super != typeof (object)) {
if (super.IsImport)
return super.GUID;
super = super.BaseType;
}
throw new COMException ("Could not find base COM type for type " + t.ToString());
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal extern IntPtr GetInterfaceInternal (Type t, bool throwException);
internal IntPtr GetInterface (Type t, bool throwException) {
CheckIUnknown ();
return GetInterfaceInternal (t, throwException);
}
internal IntPtr GetInterface(Type t)
{
return GetInterface (t, true);
}
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
{
if (iunknown == IntPtr.Zero)
throw new InvalidComObjectException ("COM object that has been separated from its underlying RCW cannot be used.");
return iunknown;
}
}
internal IntPtr IDispatch
{
get
{
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;
}
}
internal static Guid IID_IUnknown
{
get
{
return new Guid("00000000-0000-0000-C000-000000000046");
}
}
internal static Guid IID_IDispatch
{
get
{
return new Guid ("00020400-0000-0000-C000-000000000046");
}
}
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);
}
public override int GetHashCode ()
{
CheckIUnknown ();
// not what MS seems to do,
// but IUnknown is identity in COM
return iunknown.ToInt32 ();
}
[DllImport ("ole32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, PreserveSig = true)]
static extern int CoCreateInstance (
[In, MarshalAs (UnmanagedType.LPStruct)] Guid rclsid,
IntPtr pUnkOuter,
uint dwClsContext,
[In, MarshalAs (UnmanagedType.LPStruct)] Guid riid,
out IntPtr pUnk);
}
}
#else
namespace System
{
// this is a shim class so we can AOT during full AOT builds without --enable-minimal=com
internal class __ComObject
{
__ComObject ()
{
throw new NotSupportedException ();
}
}
}
#endif