summaryrefslogtreecommitdiff
path: root/src/vm/cominterfacemarshaler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/cominterfacemarshaler.cpp')
-rw-r--r--src/vm/cominterfacemarshaler.cpp1334
1 files changed, 1334 insertions, 0 deletions
diff --git a/src/vm/cominterfacemarshaler.cpp b/src/vm/cominterfacemarshaler.cpp
new file mode 100644
index 0000000000..251beff352
--- /dev/null
+++ b/src/vm/cominterfacemarshaler.cpp
@@ -0,0 +1,1334 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: ComInterfaceMarshaler.cpp
+//
+
+//
+
+
+#include "common.h"
+
+#include "vars.hpp"
+#include "excep.h"
+#include "stdinterfaces.h"
+#include "interoputil.h"
+#include "comcallablewrapper.h"
+#include "runtimecallablewrapper.h"
+#include "cominterfacemarshaler.h"
+#include "interopconverter.h"
+#ifdef FEATURE_REMOTING
+#include "remoting.h"
+#include "appdomainhelper.h"
+#include "crossdomaincalls.h"
+#endif
+#include "notifyexternals.h"
+#include "comdelegate.h"
+#include "winrttypenameconverter.h"
+#include "olecontexthelpers.h"
+
+
+//--------------------------------------------------------------------------------
+// COMInterfaceMarshaler::COMInterfaceMarshaler()
+// ctor
+//--------------------------------------------------------------------------------
+COMInterfaceMarshaler::COMInterfaceMarshaler()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_pWrapperCache = RCWCache::GetRCWCache();
+ _ASSERTE(m_pWrapperCache);
+
+ m_pUnknown = NULL;
+ m_pIdentity = NULL;
+ m_pIManaged = NULL;
+
+ INDEBUG(m_fFlagsInited = false;)
+ m_fIsRemote = false;
+ m_fIReference = false;
+ m_fIReferenceArray = false;
+ m_fNonRCWType = false;
+ m_flags = RCW::CF_None;
+ m_pCallback = NULL;
+ m_pThread = NULL;
+
+ m_dwServerSyncBlockIndex = 0;
+}
+
+//--------------------------------------------------------------------------------
+// COMInterfaceMarshaler::~COMInterfaceMarshaler()
+// dtor
+//--------------------------------------------------------------------------------
+COMInterfaceMarshaler::~COMInterfaceMarshaler()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (m_pIManaged)
+ {
+ ULONG cbRef = SafeRelease(m_pIManaged);
+ LogInteropRelease(m_pIManaged, cbRef, "COMInterfaceMarshaler::~COMInterfaceMarshaler: Releasing IManaged interface");
+ m_pIManaged = NULL;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// VOID COMInterfaceMarshaler::Init(IUnknown* pUnk, MethodTable* pClassMT, Thread *pThread, DWORD flags)
+// init
+//--------------------------------------------------------------------------------
+VOID COMInterfaceMarshaler::Init(IUnknown* pUnk, MethodTable* pClassMT, Thread *pThread, DWORD flags /*= RCW::CF_None*/)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pUnk));
+ PRECONDITION(CheckPointer(pClassMT, NULL_OK));
+ PRECONDITION(CheckPointer(pThread));
+ PRECONDITION(m_typeHandle.IsNull() && m_pUnknown == NULL && m_pIdentity == NULL);
+ }
+ CONTRACTL_END;
+
+ // NOTE ** this struct is temporary,
+ // so NO ADDREF of the COM Interface pointers
+ m_pUnknown = pUnk;
+
+ // for now use the IUnknown as the Identity
+ m_pIdentity = pUnk;
+
+ m_typeHandle = TypeHandle(pClassMT);
+
+ m_pThread = pThread;
+
+ m_flags = flags;
+
+ if (!SupportsIInspectable())
+ {
+ if (!m_typeHandle.IsNull() && m_typeHandle.IsProjectedFromWinRT())
+ m_flags |= RCW::CF_SupportsIInspectable;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// VOID COMInterfaceMarshaler::InitializeFlags()
+//--------------------------------------------------------------------------------
+VOID COMInterfaceMarshaler::InitializeFlags()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(false == m_fFlagsInited);
+ PRECONDITION(NULL == m_pIManaged);
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ if (SupportsIInspectable() || GetAppDomain()->GetPreferComInsteadOfManagedRemoting())
+ {
+ // User has set flag / disable IManagedObject check or we know that the object supports IInspectable
+ // so COM remoting will be used. We have to be careful here and only use the CF_SupportsIInspectable
+ // flag that came in statically. All managed objects support IInspectable so performing the check
+ // after CF_SupportsIInspectable has been updated based on QI(IID_IInspectable) would break classic
+ // managed <-> managed COM interop scenarios.
+ hr = E_NOINTERFACE;
+ }
+
+
+ if (SUCCEEDED(hr))
+ {
+ hr = SafeQueryInterface(m_pUnknown, IID_IManagedObject, (IUnknown**)&m_pIManaged);
+ LogInteropQI(m_pUnknown, IID_IManagedObject, hr, "COMInterfaceMarshaler::InitializeFlags: QI for IManagedObject");
+ }
+
+ if (hr == S_OK)
+ {
+ _ASSERTE(m_pIManaged);
+ BSTRHolder bstrProcessGUID;
+
+ {
+ GCX_PREEMP();
+
+ INT_PTR pCCW;
+ IfFailThrow(m_pIManaged->GetObjectIdentity(&bstrProcessGUID, (int*)&m_dwServerDomainId, (CCW_PTR)&pCCW));
+
+ // we may get back a pointer-sized value but only the lower 32-bits are guaranteed to be valid and
+ // contain syncblock index of the managed object
+ m_dwServerSyncBlockIndex = (DWORD)pCCW;
+ }
+
+ // if hr2 != S_OK then we throw an exception
+ // coz GetProcessID shouldn't fail..
+ // one reason where it fails is JIT Activation of the object
+ // failed
+ _ASSERTE(bstrProcessGUID != NULL);
+
+ // compare the strings to check if this is in-proc
+ BSTR processGuid = GetProcessGUID();
+
+ if (NULL == processGuid)
+ ThrowOutOfMemory();
+
+ m_fIsRemote = (wcscmp((WCHAR *)bstrProcessGUID, processGuid) != 0);
+ }
+
+ INDEBUG(m_fFlagsInited = true;)
+}
+
+// Returns true if the type is WinRT-redirected and requires special marshaler functionality
+// to convert an interface pointer to its corresponding managed instance.
+static bool IsRedirectedToNonRCWType(MethodTable *pMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (pMT == nullptr)
+ {
+ return false;
+ }
+
+ WinMDAdapter::RedirectedTypeIndex index;
+ if (!WinRTTypeNameConverter::ResolveRedirectedType(pMT, &index))
+ {
+ return false;
+ }
+
+ if (index == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair)
+ {
+ // we need to convert IKeyValuePair to boxed KeyValuePair
+ return true;
+ }
+
+ // redirected runtime classes are not RCWs
+ WinMDAdapter::WinMDTypeKind kind;
+ WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, nullptr, nullptr, &kind);
+
+ return kind == WinMDAdapter::WinMDTypeKind_Runtimeclass;
+}
+
+//--------------------------------------------------------------------------------
+// VOID COMInterfaceMarshaler::InitializeObjectClass()
+//--------------------------------------------------------------------------------
+VOID COMInterfaceMarshaler::InitializeObjectClass(IUnknown *pIncomingIP)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (!DontResolveClass())
+ {
+
+ // If we are not in an APPX process, and an object could have a strongly typed RCW as a COM CoClass,
+ // we prefer that to the WinRT class.This preserves compatibility for exisitng code.
+ // If we are in an APPX process we do not check for IProvideClassInfo.
+ if (m_typeHandle.IsNull() && !AppX::IsAppXProcess() && !m_fIsRemote)
+ {
+ EX_TRY
+ {
+ m_typeHandle = GetClassFromIProvideClassInfo(m_pUnknown);
+
+ if (!m_typeHandle.IsNull() && !m_typeHandle.IsComObjectType())
+ {
+ m_typeHandle = TypeHandle(); // Clear the existing one.
+ }
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+ if(!m_typeHandle.IsNull())
+ return;
+ }
+
+ // Note that the actual type may be a subtype of m_typeHandle if it's not sealed.
+ if ((m_typeHandle.IsNull() || !m_typeHandle.GetMethodTable()->IsSealed()) && WinRTSupported())
+ {
+ bool fInspectable = SupportsIInspectable();
+ EX_TRY
+ {
+ // QI for IInspectable first. m_fInspectable at this point contains information about the interface
+ // pointer that we could gather from the signature or API call. But, since an object can be acquired
+ // as a plain IUnknown and later started being treated as a WinRT object, we always eagerly QI for
+ // IInspectable as part of the IInspectable::GetRuntimeClassName call. Also note that we may discover
+ // this IInspectable is really a IReference<T> or IReferenceArray<T> for WinRT-compatible T's.
+ TypeHandle typeHandle = GetClassFromIInspectable(pIncomingIP, &fInspectable, &m_fIReference, &m_fIReferenceArray);
+
+ if (!typeHandle.IsNull())
+ {
+ // GetRuntimeClassName could return a interface or projected value type name
+ if (m_fIReference || m_fIReferenceArray)
+ {
+ // this has already been pre-processed - it is the IReference/IReferenceArray generic argument
+ m_typeHandle = typeHandle;
+ }
+ if (typeHandle.IsInterface())
+ {
+ m_itfTypeHandle = typeHandle;
+ }
+ else if (IsRedirectedToNonRCWType(typeHandle.GetMethodTable()))
+ {
+ m_typeHandle = typeHandle;
+ m_fNonRCWType = true;
+ }
+ else if (!typeHandle.IsValueType())
+ {
+ // if the type returned from GetRuntimeClassName is a class, it must be derived from __ComObject
+ // or be a WinRT delegate for us to be able to build an RCW for it
+ if (typeHandle.IsComObjectType() ||
+ (!typeHandle.IsTypeDesc() && typeHandle.GetMethodTable()->IsDelegate() && (typeHandle.IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(typeHandle.GetMethodTable()))))
+ {
+ m_typeHandle = typeHandle;
+ }
+ }
+ }
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+
+ if (fInspectable)
+ {
+ m_flags |= RCW::CF_SupportsIInspectable;
+ }
+ else
+ {
+ _ASSERTE_MSG(m_typeHandle.IsNull() || !SupportsIInspectable(),
+ "Acquired an object which should be IInspectable according to metadata but the QI failed.");
+ }
+ }
+ }
+
+ if (m_typeHandle.IsNull())
+ m_typeHandle = TypeHandle(g_pBaseCOMObject);
+}
+
+//--------------------------------------------------------------------
+// OBJECTREF COMInterfaceMarshaler::GetCCWObject()
+//--------------------------------------------------------------------
+OBJECTREF COMInterfaceMarshaler::GetCCWObject()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(!m_fIsRemote);
+ }
+ CONTRACTL_END;
+
+ OBJECTREF oref = NULL;
+
+ if (m_dwServerSyncBlockIndex != 0)
+ {
+ AppDomain* pCurrDomain = m_pThread->GetDomain();
+ if (m_dwServerDomainId == pCurrDomain->GetId())
+ {
+ // if we are in the right AD, we know for sure that the object is still alive
+ // since we keep the CCW addref'ed and the AD could not have been unloaded
+ oref = ObjectToOBJECTREF(g_pSyncTable[m_dwServerSyncBlockIndex].m_Object);
+ }
+ else
+ {
+ // otherwise we have to make sure that the AD hasn't been unloaded
+ AppDomainFromIDHolder ad(m_dwServerDomainId, TRUE);
+ if (!ad.IsUnloaded())
+ {
+ oref = ObjectToOBJECTREF(g_pSyncTable[m_dwServerSyncBlockIndex].m_Object);
+ }
+ }
+ }
+
+ return oref;
+}
+
+//--------------------------------------------------------------------
+// OBJECTREF COMInterfaceMarshaler::HandleInProcManagedComponents()
+//--------------------------------------------------------------------
+OBJECTREF COMInterfaceMarshaler::HandleInProcManagedComponent()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(!m_fIsRemote);
+ }
+ CONTRACTL_END;
+
+ AppDomain* pCurrDomain = m_pThread->GetDomain();
+
+ OBJECTREF oref = NULL;
+ if (m_dwServerDomainId == pCurrDomain->GetId())
+ {
+ oref = GetCCWObject();
+ }
+ else
+ {
+#ifdef FEATURE_CORECLR
+ _ASSERTE(!"NYI");
+ COMPlusThrowHR(COR_E_NOTSUPPORTED);
+#else // FEATURE_CORECLR
+ // TODO: probably we can cache the object on a per App domain bases
+ // using CCW as the key
+ OBJECTREF pwrap = NULL;
+ GCPROTECT_BEGIN(pwrap);
+ {
+ pwrap = GetCCWObject();
+ oref = AppDomainHelper::CrossContextCopyFrom(m_dwServerDomainId, &pwrap);
+ }
+ GCPROTECT_END();
+#endif // FEATURE_CORECLR
+ }
+
+ return oref;
+}
+
+#ifdef FEATURE_REMOTING
+
+OBJECTREF COMInterfaceMarshaler::GetObjectForRemoteManagedComponentNoThrow()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ OBJECTREF oref = NULL;
+
+ EX_TRY
+ {
+ oref = GetObjectForRemoteManagedComponent();
+ }
+ EX_CATCH
+ {
+ oref = NULL;
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+
+ return oref;
+}
+
+
+//--------------------------------------------------------------------
+// OBJECTREF COMInterfaceMarshaler::GetObjectForRemoteManagedComponent()
+// setup managed proxy to remote object
+//--------------------------------------------------------------------
+OBJECTREF COMInterfaceMarshaler::GetObjectForRemoteManagedComponent()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(m_fIsRemote == true);
+ PRECONDITION(CheckPointer(m_pIManaged));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF oref = NULL;
+
+ GCPROTECT_BEGIN(oref)
+ {
+ BSTR bstr;
+ HRESULT hr;
+
+ {
+ GCX_PREEMP();
+ hr = m_pIManaged->GetSerializedBuffer(&bstr);
+ }
+
+ if (hr == S_OK)
+ {
+ if (bstr != NULL)
+ {
+ // this could throw an exception
+ // also this would free up the BSTR that we pass in
+ BOOL fLegacyMode = (GetAppDomain()->GetComOrRemotingFlag() == COMorRemoting_LegacyMode);
+ oref = ConvertBSTRToObject(bstr, !fLegacyMode);
+
+ if (oref != NULL)
+ {
+ // setup a COM call wrapper
+ ComCallWrapper* pComCallWrap = ComCallWrapper::InlineGetWrapper(&oref);
+ _ASSERTE(pComCallWrap != NULL);
+
+ // InlineGetWrapper AddRef's the wrapper
+ pComCallWrap->Release();
+ }
+ }
+ }
+ else
+ {
+ COMPlusThrowHR(hr);
+ }
+ }
+ GCPROTECT_END();
+
+ return oref;
+}
+#endif // FEATURE_REMOTING
+
+//--------------------------------------------------------------------------------
+// void COMInterfaceMarshaler::CreateObjectRef(BOOL fDuplicate, OBJECTREF *pComObj)
+// Creates an RCW of the proper type.
+//--------------------------------------------------------------------------------
+void COMInterfaceMarshaler::CreateObjectRef(BOOL fDuplicate, OBJECTREF *pComObj, IUnknown **ppIncomingIP, MethodTable *pIncomingItfMT, bool bIncomingIPAddRefed)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(IsProtectedByGCFrame(pComObj));
+ PRECONDITION(!m_typeHandle.IsNull());
+ PRECONDITION(m_typeHandle.IsComObjectType() || (m_typeHandle.GetMethodTable()->IsDelegate() && (m_typeHandle.GetMethodTable()->IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(m_typeHandle.GetMethodTable()))));
+ PRECONDITION(m_pThread == GetThread());
+ PRECONDITION(pIncomingItfMT == NULL || pIncomingItfMT->IsInterface());
+ }
+ CONTRACTL_END;
+
+ BOOL fExisting = FALSE;
+
+ // instantiate an instance of m_typeHandle
+ if (*pComObj != NULL)
+ {
+ // the instance already exists and was passed in *pComObj
+ fExisting = TRUE;
+ }
+ else if (m_typeHandle.IsComObjectType())
+ {
+ // ordinary RCW
+ *pComObj = ComObject::CreateComObjectRef(m_typeHandle.GetMethodTable());
+ }
+ else
+ {
+ // If delegates were to take this path, we need to fix the identity in MethodPtrAux later
+ _ASSERTE(!(m_flags & RCW::CF_QueryForIdentity));
+
+ // delegate backed by a WinRT interface pointer
+ *pComObj = COMDelegate::ConvertWinRTInterfaceToDelegate(m_pIdentity, m_typeHandle.GetMethodTable());
+ }
+
+ // make sure we "pin" the syncblock before switching to preemptive mode
+ SyncBlock *pSB = (*pComObj)->GetSyncBlock();
+ pSB->SetPrecious();
+ DWORD dwSyncBlockIndex = pSB->GetSyncBlockIndex();
+
+ NewRCWHolder pNewRCW;
+ pNewRCW = RCW::CreateRCW(m_pUnknown, dwSyncBlockIndex, m_flags, m_typeHandle.GetMethodTable());
+
+ if (fDuplicate)
+ {
+ // let us fix the identity to be the wrapper,
+ // so looking up this IUnknown won't return this wrapper
+ // this would allow users to call WrapIUnknownWithCOMObject
+ // to create duplicate wrappers
+ pNewRCW->m_pIdentity = pNewRCW;
+ m_pIdentity = (IUnknown*)(LPVOID)pNewRCW;
+ }
+ else if (m_flags & RCW::CF_QueryForIdentity)
+ {
+ // pNewRCW has the real Identity in this case and we need to use it to insert into RCW cache
+ m_pIdentity = (IUnknown *)pNewRCW->m_pIdentity;
+ }
+
+ // If the class is an extensible RCW (managed class deriving from a ComImport class)
+ if (fExisting)
+ {
+ MethodTable *pClassMT = (*pComObj)->GetMethodTable();
+ if (pClassMT != g_pBaseCOMObject && pClassMT->IsExtensibleRCW())
+ {
+ // WinRT scenario: we're initializing an RCW for a managed object that is
+ // already in the process of being constructed (we're at the point of calling
+ // to the base class ctor.
+ // Just mark the RCW as aggregated (in this scenario we don't go down
+ // ComClassFactory::CreateAggregatedInstance)
+ pNewRCW->MarkURTAggregated();
+ }
+ }
+ else
+ {
+ if (m_typeHandle.GetMethodTable() != g_pBaseCOMObject && m_typeHandle.GetMethodTable()->IsExtensibleRCW())
+ {
+ // Normal COM aggregation case - we're just in the process of allocating the object
+ // If the managed class has a default constructor then call it
+ MethodDesc *pCtorMD = m_typeHandle.GetMethodTable()->GetDefaultConstructor();
+ if (pCtorMD)
+ {
+ PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pCtorMD);
+ DECLARE_ARGHOLDER_ARRAY(CtorArgs, 1);
+ CtorArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*pComObj);
+
+ // Call the ctor...
+ CALL_MANAGED_METHOD_NORET(CtorArgs);
+ }
+ }
+ }
+
+ // We expect that, at most, the first entry will already be allocated.
+ // (SetJupiterObject gets the first shot at this.)
+ int nNextFreeIdx = pNewRCW->m_aInterfaceEntries[0].IsFree() ? 0 : 1;
+
+ // Only cache WinRT interfaces
+ // Note that we can't use SupportsIInspectable here because we could be talking to a CCW
+ // which supports IInspectable by default
+ if (ppIncomingIP != NULL &&
+ *ppIncomingIP != NULL &&
+ pIncomingItfMT != NULL &&
+ pIncomingItfMT->IsLegalNonArrayWinRTType())
+ {
+ _ASSERTE(pIncomingItfMT->IsInterface());
+ _ASSERTE(pNewRCW->m_aInterfaceEntries[nNextFreeIdx].IsFree());
+
+ //
+ // The incoming interface pointer is of type m_pItfMT
+ // Cache the result into RCW for better performance and for variance support
+ // For example, GetFilesAsync() returns Windows.Storage.StorageFileView and this type
+ // is not in any WinMD. Because GetFilesAsync actually returns IVectorView<StorageFile>,
+ // we know this RCW supports this interface, and putting it into the cache would make sure
+ // casting this RCW to IVectorView<object> works
+ //
+ pNewRCW->m_aInterfaceEntries[nNextFreeIdx++].Init(pIncomingItfMT, *ppIncomingIP);
+
+ // Don't hold ref count if RCW is aggregated
+ if (!pNewRCW->IsURTAggregated())
+ {
+ if (bIncomingIPAddRefed)
+ {
+ // Transfer the ref from ppIncomingIP to internal cache
+ // This will only happen in WinRT scenarios to reduce risk of this change
+ *ppIncomingIP = NULL;
+ }
+ else
+ {
+ // Otherwise AddRef by ourselves
+ RCW_VTABLEPTR(pNewRCW);
+ SafeAddRef(*ppIncomingIP);
+ }
+
+ RCWWalker::AfterInterfaceAddRef(pNewRCW);
+ }
+
+ // Save GetEnumerator method if necessary
+ // Do this after we "AddRef" on ppIncomingIP otherwise we would call Release on it
+ // without a AddRef
+ pNewRCW->SetGetEnumeratorMethod(pIncomingItfMT);
+ }
+
+ if (!m_itfTypeHandle.IsNull() && !m_itfTypeHandle.IsTypeDesc())
+ {
+ MethodTable *pItfMT = m_itfTypeHandle.AsMethodTable();
+
+ // Just in case we've already cached it with pIncomingItfMT
+ if (pItfMT != pIncomingItfMT)
+ {
+ // We know that the object supports pItfMT but we don't have the right interface pointer at this point
+ // (*ppIncomingIP is not necessarily the right one) so we'll QI for it. Note that this is not just a
+ // perf optimization, we need to store pItfMT in the RCW in case it has variance and/or provide the
+ // non-generic IEnumerable::GetEnumerator method.
+
+ IID iid;
+ SafeComHolder<IUnknown> pItfIP;
+
+ if (SUCCEEDED(pNewRCW->CallQueryInterface(pItfMT, Instantiation(), &iid, &pItfIP)))
+ {
+ _ASSERTE(pNewRCW->m_aInterfaceEntries[nNextFreeIdx].IsFree());
+
+ pNewRCW->m_aInterfaceEntries[nNextFreeIdx].Init(pItfMT, pItfIP);
+
+ // Don't hold ref count if RCW is aggregated
+ if (!pNewRCW->IsURTAggregated())
+ {
+ pItfIP.SuppressRelease();
+
+ RCWWalker::AfterInterfaceAddRef(pNewRCW);
+ }
+ }
+ }
+ }
+
+
+ {
+ // Make sure that RCWHolder is declared before GC is forbidden - its destructor may trigger GC.
+ RCWHolder pRCW(m_pThread);
+ pRCW.InitNoCheck(pNewRCW);
+
+ // We may get back an RCW from another STA thread (mainly in WinRT factory cache scenario,
+ // as those factories are typically singleton), and we can only touch the RCW if we hold the lock,
+ // otherwise we may AV if the STA thread dies and takes the RCW with it
+ RCWCache::LockHolder lh(m_pWrapperCache);
+
+ GCX_FORBID();
+
+ // see if somebody beat us to it..
+ BOOL fInserted = m_pWrapperCache->FindOrInsertWrapper_NoLock(m_pIdentity, &pRCW, !fExisting);
+ if (!fInserted)
+ {
+ // somebody beats us in creating a wrapper. Let's determine whether we should insert our
+ // wrapper as a duplicate, or use the other wrapper that is already in the cache
+
+ // If the object instance already exists, we have no choice but to insert this wrapper
+ // as a duplicate. If we return the one that is already in the cache, we would return
+ // a different object!
+ BOOL fInsertAsDuplicateWrapper = fExisting;
+
+ if (!fInsertAsDuplicateWrapper)
+ {
+ // Shall we use the RCW that is already in the cache?
+ if (m_pCallback && !m_pCallback->ShouldUseThisRCW(pRCW.GetRawRCWUnsafe()))
+ {
+ // No - let's insert our wrapper as a duplicate instead
+ fInsertAsDuplicateWrapper = TRUE;
+
+ // Initialize pRCW again and make sure sure pRCW is indeed our new wrapper
+ pRCW.UnInit();
+ pRCW.InitNoCheck(pNewRCW);
+ }
+ }
+
+ if (fInsertAsDuplicateWrapper)
+ {
+ // we need to keep this wrapper separate so we'll insert it with the alternate identity
+ // (just as if fDuplicate was TRUE)
+ pNewRCW->m_pIdentity = pNewRCW;
+ m_pIdentity = (IUnknown*)(LPVOID)pNewRCW;
+
+ fInserted = m_pWrapperCache->FindOrInsertWrapper_NoLock(m_pIdentity, &pRCW, !fExisting);
+ _ASSERTE(fInserted);
+
+ pNewRCW.SuppressRelease();
+
+ if (m_pCallback)
+ m_pCallback->OnRCWCreated(pRCW.GetRawRCWUnsafe());
+ }
+ else
+ {
+ // Somebody beat us in creating the wrapper. Let's use that
+ if (m_pCallback)
+ m_pCallback->OnRCWCacheHit(pRCW.GetRawRCWUnsafe());
+
+ // grab the new object
+ *pComObj = (OBJECTREF)pRCW->GetExposedObject();
+ }
+ }
+ else
+ {
+ // If we did insert this wrapper in the table, make sure we don't delete it.
+ pNewRCW.SuppressRelease();
+
+ if (m_pCallback)
+ m_pCallback->OnRCWCreated(pRCW.GetRawRCWUnsafe());
+ }
+ }
+
+ _ASSERTE(*pComObj != NULL);
+
+#ifdef _DEBUG
+ if (!m_typeHandle.IsNull() && m_typeHandle.IsComObjectType())
+ {
+ // make sure this object supports all the COM Interfaces in the class
+ EnsureCOMInterfacesSupported(*pComObj, m_typeHandle.GetMethodTable());
+ }
+#endif
+}
+
+
+// OBJECTREF COMInterfaceMarshaler::IReferenceUnbox()
+//--------------------------------------------------------------------------------
+
+void COMInterfaceMarshaler::IReferenceUnbox(IUnknown **ppIncomingIP, OBJECTREF *poref, bool bIncomingIPAddRefed)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(m_fIReference);
+ PRECONDITION(m_pThread == GetThread());
+ }
+ CONTRACTL_END;
+
+ OBJECTREF unboxed = NULL;
+ _ASSERTE(m_typeHandle.AsMethodTable()->IsLegalNonArrayWinRTType());
+
+ // Create a temporary RCW. Call into managed. Let managed query for a closed generic instantiation
+ // like IReference<Int32> (including the GUID calculation & QI) then call the Value property. That
+ // will use the existing interop code to safely marshal the value.
+ // Also, make sure we create a duplicate RCW in this case so that next time we won't end up getting
+ // this RCW from cache
+ COMInterfaceMarshaler marshaler;
+
+ DWORD flags = RCW::CF_DontResolveClass | RCW::CF_NeedUniqueObject;
+
+ marshaler.Init(m_pUnknown, g_pBaseCOMObject, m_pThread, flags);
+
+ if (m_pCallback)
+ marshaler.SetCallback(m_pCallback);
+
+ OBJECTREF oref = marshaler.FindOrCreateObjectRefInternal(ppIncomingIP, /* pIncomingItfMT = */ NULL, bIncomingIPAddRefed);
+
+ IReferenceOrIReferenceArrayUnboxWorker(oref, m_typeHandle, FALSE, poref);
+}
+
+// void COMInterfaceMarshaler::IReferenceOrIReferenceArrayUnboxWorker()
+//--------------------------------------------------------------------------------
+
+// static
+void COMInterfaceMarshaler::IReferenceOrIReferenceArrayUnboxWorker(OBJECTREF oref, TypeHandle thT, BOOL fIsIReferenceArray, OBJECTREF *porefResult)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ GCPROTECT_BEGIN(oref);
+
+ // Get IReference<SomeType> or IReferenceArray<SomeType>
+ Instantiation inst(&thT, 1);
+ TypeHandle openType;
+ MethodDesc* pMD = NULL;
+ if (fIsIReferenceArray)
+ {
+ openType = TypeHandle(MscorlibBinder::GetClass(CLASS__CLRIREFERENCEARRAYIMPL));
+ pMD = MscorlibBinder::GetMethod(METHOD__CLRIREFERENCEARRAYIMPL__UNBOXHELPER);
+ }
+ else
+ {
+ openType = TypeHandle(MscorlibBinder::GetClass(CLASS__CLRIREFERENCEIMPL));
+ pMD = MscorlibBinder::GetMethod(METHOD__CLRIREFERENCEIMPL__UNBOXHELPER);
+ }
+ TypeHandle closedType = openType.Instantiate(inst);
+
+ // Call managed helper to get the real unboxed object now
+ MethodDesc* method = MethodDesc::FindOrCreateAssociatedMethodDesc(
+ pMD,
+ closedType.AsMethodTable(),
+ FALSE,
+ Instantiation(),
+ FALSE);
+ _ASSERTE(method != NULL);
+
+ MethodDescCallSite unboxHelper(method);
+ ARG_SLOT args[] =
+ {
+ ObjToArgSlot(oref),
+ };
+
+ // Call CLRIReferenceImpl::UnboxHelper(Object) or CLRIReferenceArrayImpl::UnboxHelper(Object)
+ *porefResult = unboxHelper.Call_RetOBJECTREF(args);
+ GCPROTECT_END();
+}
+
+// void COMInterfaceMarshaler::IKeyValuePairUnboxWorker()
+//--------------------------------------------------------------------------------
+
+// static
+void COMInterfaceMarshaler::IKeyValuePairUnboxWorker(OBJECTREF oref, OBJECTREF *porefResult)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ GCPROTECT_BEGIN(oref);
+
+ _ASSERTE(oref->GetMethodTable()->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__CLRIKEYVALUEPAIRIMPL)));
+
+ MethodDesc *method = MethodDesc::FindOrCreateAssociatedMethodDesc(
+ MscorlibBinder::GetMethod(METHOD__CLRIKEYVALUEPAIRIMPL__UNBOXHELPER),
+ oref->GetMethodTable(),
+ FALSE,
+ Instantiation(),
+ FALSE);
+ _ASSERTE(method != NULL);
+
+ MethodDescCallSite unboxHelper(method);
+ ARG_SLOT args[] =
+ {
+ ObjToArgSlot(oref),
+ };
+
+ // Call CLRIKeyValuePair::UnboxHelper(Object)
+ *porefResult = unboxHelper.Call_RetOBJECTREF(args);
+ GCPROTECT_END();
+}
+
+// OBJECTREF COMInterfaceMarshaler::IReferenceArrayUnbox()
+//--------------------------------------------------------------------------------
+
+void COMInterfaceMarshaler::IReferenceArrayUnbox(IUnknown **ppIncomingIP, OBJECTREF *poref, bool bIncomingIPAddRefed)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(m_fIReferenceArray);
+ PRECONDITION(m_pThread == GetThread());
+ }
+ CONTRACTL_END;
+
+ OBJECTREF unboxed = NULL;
+ // Remember all reference type array method tables are shared.
+ TypeHandle elementType = m_typeHandle.GetElementType();
+ _ASSERTE(elementType.AsMethodTable()->IsLegalNonArrayWinRTType());
+
+ // Create a temporary RCW. Call into managed. Let managed query for a closed generic instantiation
+ // like IReferenceArray<Int32> (including the GUID calculation & QI) then call the Value property. That
+ // will use the existing interop code to safely marshal the value.
+ // Also, make sure we create a duplicate RCW in this case so that next time we won't end up getting
+ // this RCW from cache
+ COMInterfaceMarshaler marshaler;
+
+ DWORD flags = RCW::CF_DontResolveClass | RCW::CF_NeedUniqueObject;
+
+ marshaler.Init(m_pUnknown, g_pBaseCOMObject, m_pThread, flags);
+
+ if (m_pCallback)
+ marshaler.SetCallback(m_pCallback);
+
+ OBJECTREF oref = marshaler.FindOrCreateObjectRefInternal(ppIncomingIP, /* pIncomingItfMT = */ NULL, bIncomingIPAddRefed);
+
+ IReferenceOrIReferenceArrayUnboxWorker(oref, elementType, TRUE, poref);
+}
+
+void COMInterfaceMarshaler::MarshalToNonRCWType(OBJECTREF *poref)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(m_fNonRCWType);
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(IsRedirectedToNonRCWType(m_typeHandle.GetMethodTable()));
+
+ struct
+ {
+ OBJECTREF refMarshaled;
+ STRINGREF refRawURI;
+ }
+ gc;
+ ZeroMemory(&gc, sizeof(gc));
+
+ WinMDAdapter::RedirectedTypeIndex index = static_cast<WinMDAdapter::RedirectedTypeIndex>(-1);
+ WinRTTypeNameConverter::ResolveRedirectedType(m_typeHandle.GetMethodTable(), &index);
+ _ASSERTE(index != -1);
+
+ GCPROTECT_BEGIN(gc)
+
+ switch (index)
+ {
+ case WinMDAdapter::RedirectedTypeIndex_System_Uri:
+ {
+ WinRtString hsRawUri;
+ {
+ GCX_PREEMP();
+
+ SafeComHolderPreemp<ABI::Windows::Foundation::IUriRuntimeClass> pUriRuntimeClass;
+ HRESULT hr = SafeQueryInterfacePreemp(m_pUnknown, ABI::Windows::Foundation::IID_IUriRuntimeClass, (IUnknown **) &pUriRuntimeClass);
+ LogInteropQI(m_pUnknown, ABI::Windows::Foundation::IID_IUriRuntimeClass, hr, "IUriRuntimeClass");
+ IfFailThrow(hr);
+
+ IfFailThrow(pUriRuntimeClass->get_RawUri(hsRawUri.Address()));
+ }
+
+ UINT32 cchRawUri;
+ LPCWSTR pwszRawUri = hsRawUri.GetRawBuffer(&cchRawUri);
+ gc.refRawURI = StringObject::NewString(pwszRawUri, cchRawUri);
+
+ UriMarshalingInfo *pUriMarshalingInfo = GetAppDomain()->GetMarshalingData()->GetUriMarshalingInfo();
+ MethodDesc* pSystemUriCtorMD = pUriMarshalingInfo->GetSystemUriCtorMD();
+
+ MethodTable *pMTSystemUri = pUriMarshalingInfo->GetSystemUriType().AsMethodTable();
+ pMTSystemUri->EnsureInstanceActive();
+ gc.refMarshaled = AllocateObject(pMTSystemUri, false);
+
+ MethodDescCallSite uriCtor(pSystemUriCtorMD);
+ ARG_SLOT ctorArgs[] =
+ {
+ ObjToArgSlot(gc.refMarshaled),
+ ObjToArgSlot(gc.refRawURI)
+ };
+ uriCtor.Call(ctorArgs);
+ }
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
+ {
+ MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__KEYVALUEPAIRMARSHALER__CONVERT_TO_MANAGED_BOX);
+
+ pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
+ pMD,
+ pMD->GetMethodTable(),
+ FALSE, // forceBoxedEntryPoint
+ m_typeHandle.GetInstantiation(), // methodInst
+ FALSE, // allowInstParam
+ TRUE); // forceRemotableMethod
+
+ MethodDescCallSite marshalMethod(pMD);
+ ARG_SLOT methodArgs[] =
+ {
+ PtrToArgSlot(m_pUnknown)
+ };
+ gc.refMarshaled = marshalMethod.Call_RetOBJECTREF(methodArgs);
+ }
+ break;
+
+ case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
+ case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
+ {
+ MethodDesc *pMD;
+ EventArgsMarshalingInfo *pInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
+
+ if (index == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs)
+ pMD = pInfo->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
+ else
+ pMD = pInfo->GetWinRTPCEventArgsToSystemPCEventArgsMD();
+
+ MethodDescCallSite marshalMethod(pMD);
+ ARG_SLOT methodArgs[] =
+ {
+ PtrToArgSlot(m_pUnknown)
+ };
+ gc.refMarshaled = marshalMethod.Call_RetOBJECTREF(methodArgs);
+ }
+ break;
+
+ default:
+ {
+ // If we get here then there is a new redirected type being introduced to the system. You must
+ // add code to marshal that type above. Additionally, code may need to be added to GetComIPFromObjectRef,
+ // in order to handle the reverse case.
+ UNREACHABLE();
+ }
+ }
+
+ *poref = gc.refMarshaled;
+
+ GCPROTECT_END();
+}
+
+
+// OBJECTREF COMInterfaceMarshaler::HandleTPComponents()
+//--------------------------------------------------------------------------------
+
+OBJECTREF COMInterfaceMarshaler::HandleTPComponents()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(m_pIManaged));
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_REMOTING
+ OBJECTREF oref = NULL;
+
+ if (m_fIsRemote || CRemotingServices::IsTransparentProxy(OBJECTREFToObject(GetCCWObject())))
+ {
+ if (!m_fIsRemote)
+ {
+ oref = HandleInProcManagedComponent();
+ }
+ else
+ {
+ if (!m_typeHandle.IsNull() && !m_typeHandle.IsComObjectType())
+ {
+ // if the user wants explicit calls,
+ // we better serialize/deserialize
+ oref = GetObjectForRemoteManagedComponent();
+ }
+ else
+ {
+ oref = GetObjectForRemoteManagedComponentNoThrow();
+ }
+ }
+
+ if (oref != NULL)
+ {
+ OBJECTREF realProxy = ObjectToOBJECTREF(CRemotingServices::GetRealProxy(OBJECTREFToObject(oref)));
+ if(realProxy != NULL)
+ {
+ // call setIUnknown on real proxy
+ GCPROTECT_BEGIN(oref)
+ {
+ CRemotingServices::CallSetDCOMProxy(realProxy, m_pUnknown);
+ }
+ GCPROTECT_END();
+ return oref;
+ }
+ else
+ {
+ return oref;
+ }
+ }
+ }
+#endif // FEATURE_REMOTING
+
+ return NULL;
+}
+
+//--------------------------------------------------------------------------------
+// OBJECTREF COMInterfaceMarshaler::FindOrCreateObjectRef()
+// Find the wrapper for this COM IP, might have to create one if not found.
+// It will return null for out-of memory scenarios. It also notices if we have
+// an IP that is disguised as an unmanaged object, sitting on top of a
+// managed object.
+//
+// The ppIncomingIP parameter serves two purposes - it lets COMInterfaceMarshaler call methods on the
+// interface pointer that came in from unmanaged code (pUnk could be the result of QI'ing such an IP for IUnknown),
+// and it also implements the CF_SuppressAddRef flag in a reliable way by assigning NULL to *ppIncomingIP if and
+// only if COMInterfaceMarshaler ended up creating a new RCW which took ownership of the interface pointer.
+//
+// If pIncomingItfMT is not NULL, we'll cache ppIncomingIP into the created RCW, so that
+// 1) RCW variance would work if we can't load the right type from RuntimeClassName, but the method returns a interface
+// 2) avoid a second QI for the same interface type
+//--------------------------------------------------------------------
+
+OBJECTREF COMInterfaceMarshaler::FindOrCreateObjectRef(IUnknown **ppIncomingIP, MethodTable *pIncomingItfMT /* = NULL */)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return FindOrCreateObjectRefInternal(ppIncomingIP, pIncomingItfMT, /* bIncomingIPAddRefed = */ true);
+}
+
+OBJECTREF COMInterfaceMarshaler::FindOrCreateObjectRef(IUnknown *pIncomingIP, MethodTable *pIncomingItfMT /* = NULL */)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return FindOrCreateObjectRefInternal(&pIncomingIP, pIncomingItfMT, /* bIncomingIPAddRefed = */ false);
+}
+
+OBJECTREF COMInterfaceMarshaler::FindOrCreateObjectRefInternal(IUnknown **ppIncomingIP, MethodTable *pIncomingItfMT, bool bIncomingIPAddRefed)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(m_pThread == GetThread());
+ PRECONDITION(pIncomingItfMT == NULL || pIncomingItfMT->IsInterface());
+ }
+ CONTRACTL_END;
+
+ OBJECTREF oref = NULL;
+
+ // (I)
+ // Initial check in our cache
+ // Skip if we want a unique object.
+ if (!NeedUniqueObject())
+ {
+ // Protect oref as SafeAddRef may trigger GC
+ GCPROTECT_BEGIN_THREAD(m_pThread, oref);
+
+ {
+ // We may get back an RCW from another STA thread (mainly in WinRT factory cache scenario,
+ // as those factories are typically singleton), and we can only touch the RCW if we hold the lock,
+ // otherwise we may AV if the STA thread dies and takes the RCW with it
+ RCWCache::LockHolder lh(m_pWrapperCache);
+
+ RCWHolder pRCW(m_pThread);
+ m_pWrapperCache->FindWrapperInCache_NoLock(
+ m_pIdentity,
+ &pRCW);
+ if (!pRCW.IsNull())
+ {
+ bool bShouldUseThisRCW = true;
+
+ if (m_pCallback)
+ bShouldUseThisRCW = m_pCallback->ShouldUseThisRCW(pRCW.GetRawRCWUnsafe());
+
+ if (bShouldUseThisRCW)
+ {
+ oref = (OBJECTREF)pRCW->GetExposedObject();
+ if (m_pCallback)
+ m_pCallback->OnRCWCacheHit(pRCW.GetRawRCWUnsafe());
+ }
+ }
+ }
+
+ GCPROTECT_END();
+
+ if (oref != NULL)
+ return oref;
+ }
+
+ // (II)
+ // Initialize all our flags
+ // this should setup all the info we need
+ InitializeFlags();
+
+ // (III)
+ // check for IManaged interface
+ if (m_pIManaged)
+ {
+ oref = HandleTPComponents();
+ if (oref != NULL)
+ return oref;
+ }
+
+ // (IV)
+ // okay let us create a wrapper and an instance for this IUnknown
+
+ // Find a suitable class to instantiate the instance
+ if (ppIncomingIP != NULL)
+ {
+ InitializeObjectClass(*ppIncomingIP);
+ }
+ else
+ {
+ InitializeObjectClass(m_pUnknown);
+ }
+
+
+ GCPROTECT_BEGIN_THREAD(m_pThread, oref)
+ {
+ if (m_fIReference)
+ IReferenceUnbox(ppIncomingIP, &oref, bIncomingIPAddRefed);
+ else if (m_fIReferenceArray)
+ IReferenceArrayUnbox(ppIncomingIP, &oref, bIncomingIPAddRefed);
+ else if (m_fNonRCWType)
+ MarshalToNonRCWType(&oref);
+ else
+ CreateObjectRef(NeedUniqueObject(), &oref, ppIncomingIP, pIncomingItfMT, bIncomingIPAddRefed);
+ }
+ GCPROTECT_END();
+
+ return oref;
+}
+
+VOID COMInterfaceMarshaler::InitializeExistingComObject(OBJECTREF *pComObj, IUnknown **ppIncomingIP)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(!m_typeHandle.IsNull());
+ PRECONDITION(IsProtectedByGCFrame(pComObj));
+ }
+ CONTRACTL_END;
+
+ CreateObjectRef(NeedUniqueObject(), pComObj, ppIncomingIP, /* pIncomingItfMT = */ NULL, /* bIncomingIPAddRefed = */ true);
+}
+
+//--------------------------------------------------------------------------------
+// Helper to wrap an IUnknown with COM object
+//--------------------------------------------------------------------------------
+OBJECTREF COMInterfaceMarshaler::WrapWithComObject()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ OBJECTREF oref = NULL;
+ GCPROTECT_BEGIN(oref)
+ {
+ CreateObjectRef(
+ TRUE, // fDuplicate
+ &oref, // pComObj
+ NULL, // ppIncomingIP
+ NULL, // pIncomingItfMT
+ false // bIncomingIPAdddefed
+ );
+ }
+ GCPROTECT_END();
+
+ return oref;
+}
+
+//--------------------------------------------------------------------------------
+// VOID EnsureCOMInterfacesSupported(OBJECTREF oref, MethodTable* pClassMT)
+// Make sure the oref supports all the COM interfaces in the class
+VOID COMInterfaceMarshaler::EnsureCOMInterfacesSupported(OBJECTREF oref, MethodTable* pClassMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pClassMT));
+ PRECONDITION(pClassMT->IsComObjectType());
+ }
+ CONTRACTL_END;
+
+ // Make sure the COM object supports all the COM imported interfaces that the new
+ // wrapper class implements.
+ GCPROTECT_BEGIN(oref);
+ MethodTable::InterfaceMapIterator it = pClassMT->IterateInterfaceMap();
+
+ while (it.Next())
+ {
+ MethodTable *pItfMT = it.GetInterface();
+ if (!pItfMT)
+ COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_COMOBJECT);
+
+ if (pItfMT->IsComImport())
+ {
+ if (!Object::SupportsInterface(oref, pItfMT))
+ COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_COMOBJECT);
+ }
+ }
+
+ GCPROTECT_END();
+}
+
+bool COMInterfaceMarshaler::SupportsIInspectable()
+{
+ LIMITED_METHOD_CONTRACT;
+ return (m_flags & RCW::CF_SupportsIInspectable) != 0;
+}
+
+bool COMInterfaceMarshaler::DontResolveClass()
+{
+ LIMITED_METHOD_CONTRACT;
+ return (m_flags & RCW::CF_DontResolveClass) != 0;
+}
+
+bool COMInterfaceMarshaler::NeedUniqueObject()
+{
+ LIMITED_METHOD_CONTRACT;
+ return (m_flags & RCW::CF_NeedUniqueObject) != 0;
+}