summaryrefslogtreecommitdiff
path: root/src/vm/classfactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/classfactory.cpp')
-rw-r--r--src/vm/classfactory.cpp999
1 files changed, 999 insertions, 0 deletions
diff --git a/src/vm/classfactory.cpp b/src/vm/classfactory.cpp
new file mode 100644
index 0000000000..9d60b5b086
--- /dev/null
+++ b/src/vm/classfactory.cpp
@@ -0,0 +1,999 @@
+// 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.
+
+
+#include "common.h"
+
+//#include "ClassFactory3.h"
+#include "winwrap.h"
+#include "comcallablewrapper.h"
+#include "frames.h"
+#include "excep.h"
+#include "registration.h"
+#ifdef FEATURE_REMOTING
+#include "remoting.h"
+#endif
+#include "typeparse.h"
+#include "mdaassistants.h"
+
+
+#ifdef FEATURE_COMINTEROP_MANAGED_ACTIVATION
+
+// Allocate a managed object given the method table pointer.
+HRESULT STDMETHODCALLTYPE EEAllocateInstance(LPUNKNOWN pOuter, MethodTable* pMT, BOOL fHasLicensing, REFIID riid, BOOL fDesignTime, BSTR bstrKey, void** ppv);
+extern BOOL g_fEEComActivatedStartup;
+extern BOOL g_fEEHostedStartup;
+extern GUID g_EEComObjectGuid;
+
+// ---------------------------------------------------------------------------
+// %%Class EEClassFactory
+// IClassFactory implementation for COM+ objects
+// ---------------------------------------------------------------------------
+class EEClassFactory : public IClassFactory2
+{
+public:
+ EEClassFactory(CLSID* pClsId, MethodTable* pTable)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pTable));
+ PRECONDITION(CheckPointer(pClsId));
+ }
+ CONTRACTL_END;
+
+ LOG((LF_INTEROP, LL_INFO100, "EEClassFactory::EEClassFactory for class %s\n", pTable->GetDebugClassName()));
+ m_pMethodTable = pTable;
+ m_cbRefCount = 0;
+ memcpy(&m_ClsId, pClsId, sizeof(GUID));
+ m_hasLicensing = FALSE;
+
+ while (pTable != NULL && pTable != g_pObjectClass)
+ {
+ if (pTable->GetMDImport()->GetCustomAttributeByName(pTable->GetCl(), "System.ComponentModel.LicenseProviderAttribute", 0,0) == S_OK)
+ {
+ m_hasLicensing = TRUE;
+ break;
+ }
+ pTable = pTable->GetParentMethodTable();
+ }
+ }
+
+ ~EEClassFactory()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ LOG((LF_INTEROP, LL_INFO100, "EEClassFactory::~ for class %s\n", m_pMethodTable->GetDebugClassName()));
+ }
+
+ STDMETHODIMP QueryInterface( REFIID iid, void **ppv)
+ {
+ SetupForComCallDWORDNoHostNotif();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(ppv, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (ppv == NULL)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (iid == IID_IClassFactory || ((iid == IID_IClassFactory2) && m_hasLicensing ) || iid == IID_IUnknown)
+ {
+ *ppv = (IClassFactory2 *)this;
+ AddRef();
+ }
+
+ return (*ppv != NULL) ? S_OK : E_NOINTERFACE;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+{
+ SetupForComCallDWORDNoHostNotif();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ ULONG l = FastInterlockIncrement(&m_cbRefCount);
+ return l;
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ SetupForComCallDWORD();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ PRECONDITION(m_cbRefCount > 0);
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ ULONG l = -1;
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr)
+ {
+ l = FastInterlockDecrement(&m_cbRefCount);
+ if (l == 0)
+ delete this;
+ }
+ END_EXTERNAL_ENTRYPOINT;
+
+ return l;
+ }
+
+ STDMETHODIMP CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void** ppv)
+ {
+ HRESULT hr = S_OK;
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ // SetupForComCallHR uses "SO_INTOLERANT_CODE_NOTHROW" to setup the SO-Intolerant transition
+ // for COM Interop. However, "SO_INTOLERANT_CODE_NOTHROW" expects that no exception can escape
+ // through this boundary but all it does is (in addition to checking that no exception has escaped it)
+ // do stack probing.
+ //
+ // However, Corrupting Exceptions [CE] can escape the COM Interop boundary. Thus, to address that scenario,
+ // we use the macro below that uses BEGIN_SO_INTOLERANT_CODE_NOTHROW to do the equivalent of
+ // SO_INTOLERANT_CODE_NOTHROW and yet allow for CEs to escape through. Since there will be a corresponding
+ // END_SO_INTOLERANT_CODE, the call is splitted into two parts: the Begin and End (see below).
+ BeginSetupForComCallHRWithEscapingCorruptingExceptions();
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ SetupForComCallHR();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ CONTRACTL
+ {
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ THROWS; // CSE can escape out of this function
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ NOTHROW;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ hr = UpdateMethodTable();
+
+ // allocate a com+ object
+ // this will allocate the object in the correct context
+ // we might end up with a tear-off on our COM+ context proxy
+ if (SUCCEEDED(hr))
+ {
+ hr = EEAllocateInstance(punkOuter, m_pMethodTable, m_hasLicensing, riid, TRUE, NULL, ppv);
+ }
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ EndSetupForComCallHRWithEscapingCorruptingExceptions();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ return hr;
+ }
+
+ STDMETHODIMP LockServer(BOOL fLock)
+ {
+ SetupForComCallHR();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ return S_OK;
+ }
+
+ // The implementation of these two functions is provided below. Prefast chocks if their implementation is here.
+ STDMETHODIMP GetLicInfo(LPLICINFO pLicInfo);
+ STDMETHODIMP RequestLicKey(DWORD dwReserved, BSTR * pbstrKey);
+
+ STDMETHODIMP CreateInstanceLic(IUnknown *punkOuter, IUnknown* pUnkReserved, REFIID riid, BSTR bstrKey, void **ppUnk)
+ {
+ HRESULT hr = S_OK;
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ // SetupForComCallHR uses "SO_INTOLERANT_CODE_NOTHROW" to setup the SO-Intolerant transition
+ // for COM Interop. However, "SO_INTOLERANT_CODE_NOTHROW" expects that no exception can escape
+ // through this boundary but all it does is (in addition to checking that no exception has escaped it)
+ // do stack probing.
+ //
+ // However, Corrupting Exceptions [CE] can escape the COM Interop boundary. Thus, to address that scenario,
+ // we use the macro below that uses BEGIN_SO_INTOLERANT_CODE_NOTHROW to do the equivalent of
+ // SO_INTOLERANT_CODE_NOTHROW and yet allow for CEs to escape through. Since there will be a corresponding
+ // END_SO_INTOLERANT_CODE, the call is splitted into two parts: the Begin and End (see below).
+ BeginSetupForComCallHRWithEscapingCorruptingExceptions();
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ SetupForComCallHR();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ CONTRACTL
+ {
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ THROWS; // CSE can escape out of this function
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ NOTHROW;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ if (!ppUnk)
+ {
+ hr = E_POINTER;
+ goto done;
+ }
+
+ *ppUnk = NULL;
+
+ if (pUnkReserved != NULL)
+ {
+ hr = E_INVALIDARG;
+ goto done;
+ }
+
+ if (bstrKey == NULL)
+ {
+ hr = E_POINTER;
+ goto done;
+ }
+
+ hr = UpdateMethodTable();
+
+ // allocate a com+ object
+ // this will allocate the object in the correct context
+ // we might end up with a tear-off on our COM+ context proxy
+ if (SUCCEEDED(hr))
+ {
+ hr = EEAllocateInstance(punkOuter, m_pMethodTable, m_hasLicensing, riid, /*fDesignTime=*/FALSE, bstrKey, ppUnk);
+ }
+
+done: ;
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ EndSetupForComCallHRWithEscapingCorruptingExceptions();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ return hr;
+ }
+
+ STDMETHODIMP CreateInstanceWithContext(LPUNKNOWN punkContext, LPUNKNOWN punkOuter, REFIID riid, void** ppv)
+ {
+ HRESULT hr = S_OK;
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ // SetupForComCallHR uses "SO_INTOLERANT_CODE_NOTHROW" to setup the SO-Intolerant transition
+ // for COM Interop. However, "SO_INTOLERANT_CODE_NOTHROW" expects that no exception can escape
+ // through this boundary but all it does is (in addition to checking that no exception has escaped it)
+ // do stack probing.
+ //
+ // However, Corrupting Exceptions [CE] can escape the COM Interop boundary. Thus, to address that scenario,
+ // we use the macro below that uses BEGIN_SO_INTOLERANT_CODE_NOTHROW to do the equivalent of
+ // SO_INTOLERANT_CODE_NOTHROW and yet allow for CEs to escape through. Since there will be a corresponding
+ // END_SO_INTOLERANT_CODE, the call is splitted into two parts: the Begin and End (see below).
+ BeginSetupForComCallHRWithEscapingCorruptingExceptions();
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ SetupForComCallHR();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ CONTRACTL
+ {
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ THROWS; // CSE can escape out of this function
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ NOTHROW;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ hr = UpdateMethodTable();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = EEAllocateInstance(punkOuter, m_pMethodTable, m_hasLicensing, riid, TRUE, NULL, ppv);
+ }
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ EndSetupForComCallHRWithEscapingCorruptingExceptions();
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ return hr;
+ }
+
+private:
+ // If we happen to be called from the same AD last time, we can use a cached MT
+ // If not, we need to use the CLSID to find the correct MT for the current domain.
+ CLSID m_ClsId;
+ MethodTable* m_pMethodTable; // most recently used MT
+ ADID m_dwDomainId; // the AD we were in when this ClassFact was last used
+ LONG m_cbRefCount;
+ BOOL m_hasLicensing;
+
+ // Ensure that m_pMethodTable and m_dwDomainId are valid for the current AppDomain. If we're
+ // not in the AD m_dwDomainId use the CLSID to get the MT.
+ STDMETHODIMP UpdateMethodTable()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ Thread *pThread = GetThread();
+ ADID adid = pThread->GetDomain()->GetId();
+ if (adid != m_dwDomainId)
+ {
+ MethodTable* tempMT = NULL;
+ EX_TRY
+ {
+ BEGIN_SO_INTOLERANT_CODE(pThread);
+ GCX_COOP();
+ tempMT = GetTypeForCLSID(m_ClsId);
+ END_SO_INTOLERANT_CODE;
+ }
+ EX_CATCH
+ {
+ hr = E_FAIL;
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ if (tempMT != NULL && SUCCEEDED(hr))
+ {
+ m_pMethodTable = tempMT;
+ m_dwDomainId = adid;
+ }
+ }
+ return hr;
+ }
+
+};
+
+
+STDMETHODIMP EEClassFactory::GetLicInfo(LPLICINFO pLicInfo)
+{
+ SetupForComCallHR();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ if (!pLicInfo)
+ return E_POINTER;
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr)
+ {
+ GCX_COOP_THREAD_EXISTS(GET_THREAD());
+
+ Thread *pThread = GET_THREAD();
+ hr = UpdateMethodTable();
+ if (SUCCEEDED(hr))
+ {
+ MethodTable *pHelperMT = pThread->GetDomain()->GetLicenseInteropHelperMethodTable();
+ MethodDesc *pMD = MemberLoader::FindMethod(pHelperMT, "GetLicInfo", &gsig_IM_LicenseInteropHelper_GetLicInfo);
+ MethodDescCallSite getLicInfo(pMD);
+
+ struct _gc {
+ OBJECTREF pHelper;
+ OBJECTREF pType;
+ } gc;
+ gc.pHelper = NULL; // LicenseInteropHelper
+ gc.pType = NULL;
+
+ GCPROTECT_BEGIN(gc);
+
+ gc.pHelper = pHelperMT->Allocate();
+ gc.pType = m_pMethodTable->GetManagedClassObject();
+
+ {
+ INT32 fRuntimeKeyAvail = 0;
+ INT32 fLicVerified = 0;
+
+ ARG_SLOT args[4];
+ args[0] = ObjToArgSlot(gc.pHelper);
+ args[1] = ObjToArgSlot(gc.pType);
+ args[2] = (ARG_SLOT)&fRuntimeKeyAvail;
+ args[3] = (ARG_SLOT)&fLicVerified;
+ getLicInfo.Call(args);
+
+ pLicInfo->cbLicInfo = sizeof(LICINFO);
+ pLicInfo->fRuntimeKeyAvail = fRuntimeKeyAvail;
+ pLicInfo->fLicVerified = fLicVerified;
+ }
+ GCPROTECT_END();
+ }
+ }
+ END_EXTERNAL_ENTRYPOINT;
+
+ return hr;
+}
+
+STDMETHODIMP EEClassFactory::RequestLicKey(DWORD dwReserved, BSTR * pbstrKey)
+{
+ SetupForComCallHR();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ if (dwReserved != 0)
+ return E_INVALIDARG;
+
+ if (!pbstrKey)
+ return E_POINTER;
+
+ *pbstrKey = NULL;
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr)
+ {
+ GCX_COOP_THREAD_EXISTS(GET_THREAD());
+
+ Thread *pThread = GET_THREAD();
+ hr = UpdateMethodTable();
+ if (SUCCEEDED(hr))
+ {
+ MethodTable *pHelperMT = pThread->GetDomain()->GetLicenseInteropHelperMethodTable();
+ MethodDesc *pMD = MemberLoader::FindMethod(pHelperMT, "RequestLicKey", &gsig_SM_LicenseInteropHelper_RequestLicKey);
+ MethodDescCallSite requestLicKey(pMD);
+
+ OBJECTREF pType = NULL;
+
+ GCPROTECT_BEGIN(pType);
+
+ pType = m_pMethodTable->GetManagedClassObject();
+ ARG_SLOT args[2];
+ args[0] = ObjToArgSlot(pType);
+ args[1] = (ARG_SLOT)pbstrKey;
+ hr = requestLicKey.Call_RetHR(args);
+ GCPROTECT_END();
+ }
+ }
+ END_EXTERNAL_ENTRYPOINT;
+
+ return hr;
+}
+
+void EEAllocateInstanceWorker(LPUNKNOWN pOuter, MethodTable* pMT, BOOL fHasLicensing, REFIID riid, BOOL fDesignTime, BSTR bstrKey, void** ppv)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(!pMT->IsComImport());
+ }
+ CONTRACTL_END;
+
+ *ppv = NULL;
+ OBJECTREF newobj;
+ CCWHolder pWrap = NULL;
+ BOOL fCtorAlreadyCalled = FALSE;
+ Thread* pThread = GetThread();
+
+ // classes that extend COM Imported class are special
+ if (ExtendsComImport(pMT))
+ {
+ pMT->EnsureInstanceActive();
+ newobj = AllocateObject(pMT);
+ }
+ else if (CRemotingServices::RequiresManagedActivation(pMT) != NoManagedActivation)
+ {
+ fCtorAlreadyCalled = TRUE;
+ newobj = CRemotingServices::CreateProxyOrObject(pMT, TRUE);
+ }
+ else
+ {
+ // If the class doesn't have a LicenseProviderAttribute, let's not
+ // pull in the LicenseManager class and friends.
+ if (!fHasLicensing)
+ {
+ pMT->EnsureInstanceActive();
+ newobj = AllocateObject( pMT, false );
+ }
+ else
+ {
+ MethodTable *pHelperMT = pThread->GetDomain()->GetLicenseInteropHelperMethodTable();
+ MethodDesc *pMD = MemberLoader::FindMethod(pHelperMT, "AllocateAndValidateLicense", &gsig_SM_LicenseInteropHelper_AllocateAndValidateLicense);
+ MethodDescCallSite allocateAndValidateLicense(pMD);
+
+ pHelperMT->EnsureInstanceActive();
+
+ OBJECTREF pType = NULL;
+
+ GCPROTECT_BEGIN(pType);
+
+ pType = pMT->GetManagedClassObject();
+
+ ARG_SLOT args[3];
+ args[0] = ObjToArgSlot(pType);
+ args[1] = (ARG_SLOT)bstrKey;
+ args[2] = fDesignTime ? 1 : 0;
+ newobj = allocateAndValidateLicense.Call_RetOBJECTREF(args);
+ fCtorAlreadyCalled = TRUE;
+
+ GCPROTECT_END();
+ }
+ }
+
+ GCPROTECT_BEGIN(newobj);
+ {
+ //get wrapper for the object, this could enable GC
+ pWrap = ComCallWrapper::InlineGetWrapper(&newobj);
+
+ // don't call any constructors if we already have called them
+ if (!fCtorAlreadyCalled && !pMT->IsValueType())
+ CallDefaultConstructor(newobj);
+ }
+ GCPROTECT_END();
+
+ if (pOuter == NULL)
+ {
+ // Return the tear-off
+ *ppv = ComCallWrapper::GetComIPFromCCW(pWrap, riid, NULL, GetComIPFromCCW::CheckVisibility);
+ if (!*ppv)
+ COMPlusThrowHR(E_NOINTERFACE);
+ }
+ else
+ {
+ // Aggregation support,
+ pWrap->InitializeOuter(pOuter);
+ IfFailThrow(pWrap->GetInnerUnknown(ppv));
+ }
+}
+
+// Allocate a managed object given the method table pointer
+HRESULT STDMETHODCALLTYPE EEAllocateInstance(LPUNKNOWN pOuter, MethodTable* pMT, BOOL fHasLicensing, REFIID riid, BOOL fDesignTime, BSTR bstrKey, void** ppv)
+{
+ CONTRACTL
+ {
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ THROWS; // CSE can escape out of this function
+#else // !FEATURE_CORRUPTING_EXCEPTIONS
+ NOTHROW;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(CheckPointer(ppv, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+
+ if ((!fDesignTime) && bstrKey == NULL)
+ return E_POINTER;
+
+ // aggregating objects should QI for IUnknown
+ if (pOuter != NULL && !IsEqualIID(riid, IID_IUnknown))
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ // Get the MethodDesc of the type being instantiated. Based upon it,
+ // we will decide whether to rethrow a CSE or not in
+ // END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX below.
+ PTR_MethodDesc pMDDefConst = NULL;
+ BOOL fHasConstructor = FALSE;
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr)
+ {
+ GCX_COOP_THREAD_EXISTS(GET_THREAD());
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ // Get the MethodDesc of the type being instantiated. Based upon it,
+ // we will decide whether to rethrow a CSE or not in
+ // END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX below.
+ if (pMT->HasDefaultConstructor())
+ {
+ pMDDefConst = pMT->GetDefaultConstructor();
+ fHasConstructor = (pMDDefConst != NULL);
+ }
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+ EEAllocateInstanceWorker(pOuter, pMT, fHasLicensing, riid, fDesignTime, bstrKey, ppv);
+ }
+ END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX((fHasConstructor && (!CEHelper::CanMethodHandleException(UseLast,pMDDefConst))) ||
+ (!fHasConstructor));
+
+ LOG((LF_INTEROP, LL_INFO100, "EEAllocateInstance for class %s object %8.8x\n", pMT->GetDebugClassName(), *ppv));
+
+ return hr;
+}
+
+IUnknown *AllocateEEClassFactoryHelper(CLSID *pClsId, MethodTable *pMT)
+{
+ CONTRACT (IUnknown*)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(CheckPointer(pClsId));
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ RETURN ((IUnknown*)new EEClassFactory(pClsId, pMT));
+}
+
+void InitializeClass(TypeHandle th)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(!th.IsNull());
+ }
+ CONTRACTL_END;
+
+ // Make sure the type isn't an interface or an abstract class.
+ if (th.IsAbstract() || th.IsInterface())
+ COMPlusThrowHR(COR_E_MEMBERACCESS);
+
+ // Unless we are dealing with a value class, the type must have a public
+ // default constructor.
+ if (!th.GetMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor())
+ {
+ COMPlusThrowHR(COR_E_MEMBERACCESS);
+ }
+
+ // Call class init if necessary
+ th.GetMethodTable()->EnsureInstanceActive();
+ th.GetMethodTable()->CheckRunClassInitThrowing();
+}
+
+// Try to load a managed class and give out an IClassFactory
+void EEDllGetClassObjectHelper(REFCLSID rclsid, MethodTable* pMT, REFIID riid, LPVOID FAR *ppv)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(CheckPointer(ppv));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ CLSID clsId;
+ SafeComHolder<IUnknown> pUnk = NULL;
+
+ memcpy(&clsId, &rclsid, sizeof(GUID));
+ pUnk = AllocateEEClassFactoryHelper(&clsId, pMT);
+
+ // Bump up the count to protect the object
+ ULONG cbRef = SafeAddRef(pUnk);
+ LogInteropAddRef(pUnk, cbRef, "EEDllGetClassObjectHelper: Bump up refcount to protect object during call");
+
+ // Query for the requested interface.
+ hr = SafeQueryInterface(pUnk, riid, (IUnknown**)ppv);
+ LogInteropQI(pUnk, riid, hr, "EDllGetClassObjectHelper: QI for requested interface");
+ IfFailThrow(hr);
+}
+
+HRESULT STDMETHODCALLTYPE EEDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
+{
+ HRESULT hr = S_OK;
+ g_fEEComActivatedStartup = TRUE;
+ g_EEComObjectGuid = rclsid;
+
+ // The EE must be started before SetupForComCallHR is called and the contract is set up.
+ if (FAILED(hr = EnsureEEStarted(COINITEE_DEFAULT)))
+ return hr;
+
+ SetupForComCallHR();
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(ppv, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (ppv == NULL)
+ return E_POINTER;
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr);
+ {
+ GCX_COOP_THREAD_EXISTS(GET_THREAD());
+
+ // We are about to use COM IPs so make sure COM is started up.
+ EnsureComStarted();
+
+ MethodTable *pMT;
+
+ {
+ Thread *pThread = GetThread();
+ BEGIN_SO_INTOLERANT_CODE(pThread);
+ GCX_COOP();
+ pMT = GetTypeForCLSID(rclsid);
+ END_SO_INTOLERANT_CODE;
+ }
+
+ // If we can't find the class based on the CLSID or if the registered managed
+ // class is ComImport class then fail the call. Also, if the type is a generic
+ // type (either opened or closed) then fail the call.
+ if (!pMT || pMT->IsComImport() || (pMT->GetNumGenericArgs() != 0))
+ {
+ COMPlusThrowHR(REGDB_E_CLASSNOTREG);
+ }
+
+ // Verify that the class is indeed creatable and run it's .cctor if it
+ // hasn't been run yet.
+ InitializeClass(TypeHandle(pMT));
+
+ // Allocate the IClassFactory for the type.
+ EEDllGetClassObjectHelper(rclsid, pMT, riid, ppv);
+ }
+ END_EXTERNAL_ENTRYPOINT;
+
+ return hr;
+} //EEDllGetClassObject
+
+// Helper Functions to get a object based on a name
+void ClrCreateManagedInstanceHelper(MethodTable* pMT, REFIID riid, LPVOID FAR *ppv)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(CheckPointer(ppv));
+ }
+ CONTRACTL_END;
+
+ GCX_PREEMP();
+
+ HRESULT hr = S_OK;
+ SafeComHolderPreemp<IUnknown> pUnk = NULL;
+ SafeComHolderPreemp<IClassFactory> pFactory = NULL;
+
+ GUID guid;
+ pMT->GetGuid(&guid, TRUE);
+ pUnk = AllocateEEClassFactoryHelper(&guid, pMT);
+
+ // Bump up the count to protect the object for the duration of this function
+ ULONG cbRef = SafeAddRef(pUnk);
+ LogInteropAddRef(pUnk, cbRef, "ClrCreateManagedInstanceHelper: Bumping refcount to protect object during call");
+
+ // Query the factory for the IClassFactory interface.
+ hr = SafeQueryInterface(pUnk, IID_IClassFactory, (IUnknown**) &pFactory);
+ LogInteropQI(pUnk, IID_IClassFactory, hr, "ClrCreateManagedInstanceHelper: QI for IID_IClassFactory");
+ IfFailThrow(hr);
+
+ // Create an instance of the type.
+ IfFailThrow(pFactory->CreateInstance(NULL, riid, ppv));
+}
+
+STDAPI ClrCreateManagedInstance(LPCWSTR typeName, REFIID riid, LPVOID FAR *ppv)
+{
+ HRESULT hr = S_OK;
+
+ // The EE must be started before SetupForComCallHR is called and the contract is set up.
+ g_fEEHostedStartup = TRUE;
+ if (FAILED(hr = EnsureEEStarted(COINITEE_DEFAULT)))
+ return hr;
+
+ SetupForComCallHR();
+
+ CONTRACTL
+ {
+ DISABLED(NOTHROW);
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(typeName, NULL_OK));
+ PRECONDITION(CheckPointer(ppv, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (ppv == NULL)
+ return E_POINTER;
+
+ if (typeName == NULL)
+ return E_INVALIDARG;
+
+ BEGIN_EXTERNAL_ENTRYPOINT(&hr);
+ {
+ GCX_COOP_THREAD_EXISTS(GET_THREAD());
+
+ // We are about to use COM IPs so make sure COM is started up.
+ EnsureComStarted();
+
+ MAKE_UTF8PTR_FROMWIDE(pName, typeName);
+
+ AppDomain* pDomain = SystemDomain::GetCurrentDomain();
+ MethodTable *pMT = TypeName::GetTypeUsingCASearchRules(pName, NULL).GetMethodTable();
+ if (!pMT || pMT->IsComImport())
+ COMPlusThrowHR(REGDB_E_CLASSNOTREG);
+
+ // Verify that the class is indeed creatable and run it's .cctor if it
+ // hasn't been run yet.
+ InitializeClass(TypeHandle(pMT));
+
+ // Allocate the instance of the type.
+ ClrCreateManagedInstanceHelper(pMT, riid, ppv);
+ }
+ END_EXTERNAL_ENTRYPOINT;
+
+ return hr;
+}
+
+DWORD RegisterTypeForComClientsHelper(MethodTable *pMT, GUID *pGuid, CLSCTX clsContext, REGCLS flags)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pMT != NULL);
+ PRECONDITION(pGuid != NULL);
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ DWORD dwCookie = 0;
+ SafeComHolder<IUnknown> pUnk = NULL;
+
+ // We are about to perform COM operations so ensure COM is started up.
+ EnsureComStarted();
+
+ // Allocate an EE class factory for the type.
+ pUnk = AllocateEEClassFactoryHelper(pGuid, pMT);
+
+ // bump up the count to protect the object
+ ULONG cbRef = SafeAddRef(pUnk);
+ LogInteropAddRef(pUnk, cbRef, "RegisterTypeForComClientsNative: Bumping refcount to protect class factory");
+
+ {
+ // Enable GC
+ GCX_PREEMP();
+
+ // Call CoRegisterClassObject.
+ IfFailThrow(CoRegisterClassObject(*(pGuid), pUnk, clsContext, flags, &dwCookie));
+ }
+
+ // CoRegisterClassObject will bump up the ref count so we must release
+ // the extra ref count we added above.
+ return dwCookie;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Method: RegisterTypeForComClientsNative
+//
+// Synopsis: Registers a class factory with COM classic for a given type
+// and CLSID. Later we can receive activations on this factory
+// and we return a CCW.
+//
+
+//
+//+----------------------------------------------------------------------------
+FCIMPL2(VOID, RegisterTypeForComClientsNative, ReflectClassBaseObject* pTypeUNSAFE, GUID* pGuid)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pTypeUNSAFE != NULL);
+ PRECONDITION(pGuid != NULL);
+ }
+ CONTRACTL_END;
+
+ REFLECTCLASSBASEREF pType = (REFLECTCLASSBASEREF) pTypeUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_1(pType);
+
+ // Retrieve the method table from the type.
+ MethodTable *pMT = pType->GetType().GetMethodTable();
+
+ // Call the helper to perform the registration.
+ RegisterTypeForComClientsHelper(pMT, pGuid, (CLSCTX)(CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER), REGCLS_MULTIPLEUSE);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+//+----------------------------------------------------------------------------
+//
+// Method: RegisterTypeForComClientsExNative
+//
+// Synopsis: Registers a class factory with COM classic for a given type.
+//
+//+----------------------------------------------------------------------------
+FCIMPL3(DWORD, RegisterTypeForComClientsExNative, ReflectClassBaseObject* pTypeUNSAFE, CLSCTX clsContext, REGCLS flags)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pTypeUNSAFE != NULL);
+ }
+ CONTRACTL_END;
+
+ DWORD dwCookie = 0;
+ GUID clsid;
+
+ REFLECTCLASSBASEREF pType = (REFLECTCLASSBASEREF) pTypeUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_RET_1(pType);
+
+ // Retrieve the method table from the type.
+ MethodTable *pMT = pType->GetType().GetMethodTable();
+
+ // Retrieve the CLSID from the type.
+ pMT->GetGuid(&clsid, TRUE);
+
+ // Call the helper to perform the registration.
+ dwCookie = RegisterTypeForComClientsHelper(pMT, &clsid, clsContext, flags);
+
+ HELPER_METHOD_FRAME_END();
+
+ return dwCookie;
+}
+FCIMPLEND
+
+#else // FEATURE_COMINTEROP_MANAGED_ACTIVATION
+
+STDAPI ClrCreateManagedInstance(LPCWSTR typeName, REFIID riid, LPVOID FAR *ppv)
+{
+
+ return E_NOTIMPL; // @TODO: CoreCLR_REMOVED: completely remove this function
+}
+
+#endif // FEATURE_COMINTEROP_MANAGED_ACTIVATION
+