// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // // // File: MarshalNative.cpp // // // FCall's for the PInvoke classlibs // #include "common.h" #include "clsload.hpp" #include "method.hpp" #include "class.h" #include "object.h" #include "field.h" #include "util.hpp" #include "excep.h" #include "siginfo.hpp" #include "threads.h" #include "stublink.h" #include "dllimport.h" #include "jitinterface.h" #include "eeconfig.h" #include "log.h" #include "fieldmarshaler.h" #include "cgensys.h" #include "gc.h" #include "security.h" #include "dbginterface.h" #include "objecthandle.h" #include "marshalnative.h" #include "fcall.h" #include "dllimportcallback.h" #ifdef FEATURE_REMOTING #include "remoting.h" #endif #include "comdelegate.h" #include "handletablepriv.h" #include "mdaassistants.h" #include "typestring.h" #include "appdomain.inl" #ifdef FEATURE_COMINTEROP #include "comcallablewrapper.h" #include "cominterfacemarshaler.h" #include "commtmemberinfomap.h" #include "runtimecallablewrapper.h" #include "olevariant.h" #include "interoputil.h" #include "stubhelpers.h" #endif // FEATURE_COMINTEROP #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT #include "olecontexthelpers.h" #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT // // NumParamBytes // Counts # of parameter bytes INT32 QCALLTYPE MarshalNative::NumParamBytes(MethodDesc * pMD) { QCALL_CONTRACT; // Arguments are check on managed side PRECONDITION(pMD != NULL); INT32 cbParamBytes = 0; BEGIN_QCALL; if (!(pMD->IsNDirect())) COMPlusThrow(kArgumentException, IDS_EE_NOTNDIRECT); // Read the unmanaged stack size from the stub MethodDesc. For vararg P/Invoke, // this function returns size of the fixed portion of the stack. // Note that the following code does not throw if the DllImport declaration is // incorrect (such as a vararg method not marked as CallingConvention.Cdecl). MethodDesc * pStubMD = NULL; PCODE pTempStub = NULL; pTempStub = GetStubForInteropMethod(pMD, NDIRECTSTUB_FL_FOR_NUMPARAMBYTES, &pStubMD); _ASSERTE(pTempStub == NULL); _ASSERTE(pStubMD != NULL && pStubMD->IsILStub()); cbParamBytes = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize(); #ifdef _X86_ if (((NDirectMethodDesc *)pMD)->IsThisCall()) { // The size of 'this' is not included in native stack arg size. cbParamBytes += sizeof(LPVOID); } #endif // _X86_ END_QCALL; return cbParamBytes; } // Prelink // Does advance loading of an N/Direct library VOID QCALLTYPE MarshalNative::Prelink(MethodDesc * pMD) { QCALL_CONTRACT; // Arguments are check on managed side PRECONDITION(pMD != NULL); // If the code is already ready, we are done. Else, we need to execute the prestub // This is a perf thing since it's always safe to execute the prestub twice. if (!pMD->IsPointingToPrestub()) return; // Silently ignore if not N/Direct and not runtime generated. if (!(pMD->IsNDirect()) && !(pMD->IsRuntimeSupplied())) return; BEGIN_QCALL; pMD->CheckRestore(); pMD->DoPrestub(NULL); END_QCALL; } FCIMPL3(VOID, MarshalNative::StructureToPtr, Object* pObjUNSAFE, LPVOID ptr, CLR_BOOL fDeleteOld) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(ptr, NULL_OK)); } CONTRACTL_END; OBJECTREF pObj = (OBJECTREF) pObjUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(pObj); if (ptr == NULL) COMPlusThrowArgumentNull(W("ptr")); if (pObj == NULL) COMPlusThrowArgumentNull(W("structure")); // Code path will accept both regular layout objects and boxed value classes // with layout. MethodTable *pMT = pObj->GetMethodTable(); if (pMT->HasInstantiation()) COMPlusThrowArgumentException(W("structure"), W("Argument_NeedNonGenericObject")); if (pMT->IsBlittable()) { memcpyNoGCRefs(ptr, pObj->GetData(), pMT->GetNativeSize()); } else if (pMT->HasLayout()) { if (fDeleteOld) LayoutDestroyNative(ptr, pMT); FmtClassUpdateNative( &(pObj), (LPBYTE)(ptr), NULL ); } else { COMPlusThrowArgumentException(W("structure"), W("Argument_MustHaveLayoutOrBeBlittable")); } HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL3(VOID, MarshalNative::PtrToStructureHelper, LPVOID ptr, Object* pObjIn, CLR_BOOL allowValueClasses) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(ptr, NULL_OK)); } CONTRACTL_END; OBJECTREF pObj = ObjectToOBJECTREF(pObjIn); if (ptr == NULL) FCThrowArgumentNullVoid(W("ptr")); if (pObj == NULL) FCThrowArgumentNullVoid(W("structure")); // Code path will accept regular layout objects. MethodTable *pMT = pObj->GetMethodTable(); // Validate that the object passed in is not a value class. if (!allowValueClasses && pMT->IsValueType()) { FCThrowArgumentVoid(W("structure"), W("Argument_StructMustNotBeValueClass")); } else if (pMT->IsBlittable()) { memcpyNoGCRefs(pObj->GetData(), ptr, pMT->GetNativeSize()); } else if (pMT->HasLayout()) { HELPER_METHOD_FRAME_BEGIN_1(pObj); LayoutUpdateCLR((LPVOID*) &(pObj), Object::GetOffsetOfFirstField(), pMT, (LPBYTE)(ptr)); HELPER_METHOD_FRAME_END(); } else { FCThrowArgumentVoid(W("structure"), W("Argument_MustHaveLayoutOrBeBlittable")); } } FCIMPLEND FCIMPL2(VOID, MarshalNative::DestroyStructure, LPVOID ptr, ReflectClassBaseObject* refClassUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(ptr, NULL_OK)); } CONTRACTL_END; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refClass); if (ptr == NULL) COMPlusThrowArgumentNull(W("ptr")); if (refClass == NULL) COMPlusThrowArgumentNull(W("structureType")); if (refClass->GetMethodTable() != g_pRuntimeTypeClass) COMPlusThrowArgumentException(W("structureType"), W("Argument_MustBeRuntimeType")); TypeHandle th = refClass->GetType(); if (th.HasInstantiation()) COMPlusThrowArgumentException(W("structureType"), W("Argument_NeedNonGenericType")); if (th.IsBlittable()) { // ok to call with blittable structure, but no work to do in this case. } else if (th.HasLayout()) { LayoutDestroyNative(ptr, th.GetMethodTable()); } else { COMPlusThrowArgumentException(W("structureType"), W("Argument_MustHaveLayoutOrBeBlittable")); } HELPER_METHOD_FRAME_END(); } FCIMPLEND /************************************************************************ * PInvoke.SizeOf(Class) */ FCIMPL2(UINT32, MarshalNative::SizeOfClass, ReflectClassBaseObject* refClassUNSAFE, CLR_BOOL throwIfNotMarshalable) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(refClassUNSAFE)); } CONTRACTL_END; UINT32 rv = 0; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF)refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(refClass); // refClass is validated to be non-NULL RuntimeType by callers TypeHandle th = refClass->GetType(); if (throwIfNotMarshalable) { // Determine if the type is marshalable if (!IsStructMarshalable(th)) { // It isn't marshalable so throw an ArgumentException. StackSString strTypeName; TypeString::AppendType(strTypeName, th); COMPlusThrow(kArgumentException, IDS_CANNOT_MARSHAL, strTypeName.GetUnicode(), NULL, NULL); } } // The type is marshalable or we don't care so return its size. rv = th.GetMethodTable()->GetNativeSize(); HELPER_METHOD_FRAME_END(); return rv; } FCIMPLEND /************************************************************************ * PInvoke.UnsafeAddrOfPinnedArrayElement(Array arr, int index) */ FCIMPL2(LPVOID, MarshalNative::FCUnsafeAddrOfPinnedArrayElement, ArrayBase *arr, INT32 index) { FCALL_CONTRACT; if (!arr) FCThrowArgumentNull(W("arr")); return (arr->GetDataPtr() + (index*arr->GetComponentSize())); } FCIMPLEND /************************************************************************ * PInvoke.OffsetOfHelper(Class, Field) */ FCIMPL1(UINT32, MarshalNative::OffsetOfHelper, ReflectFieldObject *pFieldUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pFieldUNSAFE)); } CONTRACTL_END; REFLECTFIELDREF refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE); FieldDesc *pField = refField->GetField(); TypeHandle th = TypeHandle(pField->GetApproxEnclosingMethodTable()); // Determine if the type is marshalable. if (!IsStructMarshalable(th)) { // It isn't marshalable so throw an ArgumentException. HELPER_METHOD_FRAME_BEGIN_RET_1(refField); StackSString strTypeName; TypeString::AppendType(strTypeName, th); COMPlusThrow(kArgumentException, IDS_CANNOT_MARSHAL, strTypeName.GetUnicode(), NULL, NULL); HELPER_METHOD_FRAME_END(); } FieldMarshaler *pFM = th.GetMethodTable()->GetLayoutInfo()->GetFieldMarshalers(); UINT numReferenceFields = th.GetMethodTable()->GetLayoutInfo()->GetNumCTMFields(); while (numReferenceFields--) { if (pFM->GetFieldDesc() == pField) { return pFM->GetExternalOffset(); } ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE; } UNREACHABLE_MSG("We should never hit this point since we already verified that the requested field was present from managed code"); } FCIMPLEND FCIMPL2(Object*, MarshalNative::GetDelegateForFunctionPointerInternal, LPVOID FPtr, ReflectClassBaseObject* refTypeUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(refTypeUNSAFE != NULL); } CONTRACTL_END; OBJECTREF refDelegate = NULL; REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF) refTypeUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_2(refType, refDelegate); // Retrieve the method table from the RuntimeType. We already verified in managed // code that the type was a RuntimeType that represented a delegate. Because type handles // for delegates must have a method table, we are safe in telling prefix to assume it below. MethodTable* pMT = refType->GetType().GetMethodTable(); PREFIX_ASSUME(pMT != NULL); refDelegate = COMDelegate::ConvertToDelegate(FPtr, pMT); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(refDelegate); } FCIMPLEND FCIMPL1(LPVOID, MarshalNative::GetFunctionPointerForDelegateInternal, Object* refDelegateUNSAFE) { FCALL_CONTRACT; LPVOID pFPtr = NULL; OBJECTREF refDelegate = (OBJECTREF) refDelegateUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(refDelegate); pFPtr = COMDelegate::ConvertToCallback(refDelegate); HELPER_METHOD_FRAME_END(); return pFPtr; } FCIMPLEND //==================================================================== // map a fiber cookie from the hosting APIs into a managed Thread object //==================================================================== FCIMPL1(THREADBASEREF, MarshalNative::GetThreadFromFiberCookie, int cookie) { FCALL_CONTRACT; _ASSERTE(cookie); THREADBASEREF ret = 0; // Set up a frame HELPER_METHOD_FRAME_BEGIN_RET_0(); // Any host who is sophisticated enough to correctly schedule fibers // had better be sophisticated enough to give us a real fiber cookie. Thread *pThread = *((Thread **) &cookie); // Minimal check that it smells like a thread: _ASSERTE(pThread->m_fPreemptiveGCDisabled.Load() == 0 || pThread->m_fPreemptiveGCDisabled.Load() == 1); ret = (THREADBASEREF)(pThread->GetExposedObject()); HELPER_METHOD_FRAME_END(); return ret; } FCIMPLEND FCIMPL3(LPVOID, MarshalNative::GetUnmanagedThunkForManagedMethodPtr, LPVOID pfnMethodToWrap, PCCOR_SIGNATURE pbSignature, ULONG cbSignature) { CONTRACTL { FCALL_CHECK; INJECT_FAULT(FCThrow(kOutOfMemoryException);); PRECONDITION(CheckPointer(pfnMethodToWrap, NULL_OK)); PRECONDITION(CheckPointer(pbSignature, NULL_OK)); } CONTRACTL_END; LPVOID pThunk = NULL; #ifdef FEATURE_MIXEDMODE HELPER_METHOD_FRAME_BEGIN_RET_0(); if (pfnMethodToWrap == NULL) COMPlusThrowArgumentNull(W("pfnMethodToWrap")); if (pbSignature == NULL) COMPlusThrowArgumentNull(W("pbSignature")); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4996) // Suppress warning on call to deprecated method #endif Module *pModule = SystemDomain::GetCallersModule(1); #ifdef _MSC_VER #pragma warning(pop) #endif PREFIX_ASSUME(pModule != NULL); pThunk = pModule->GetUMThunk(pfnMethodToWrap, pbSignature, cbSignature); if (!pThunk) COMPlusThrowOM(); HELPER_METHOD_FRAME_END(); #endif // FEATURE_MIXEDMODE return pThunk; } FCIMPLEND /************************************************************************ * PInvoke.GetManagedThunkForUnmanagedMethodPtr() */ FCIMPL3(LPVOID, MarshalNative::GetManagedThunkForUnmanagedMethodPtr, LPVOID pfnMethodToWrap, PCCOR_SIGNATURE pbSignature, ULONG cbSignature) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pfnMethodToWrap, NULL_OK)); PRECONDITION(CheckPointer(pbSignature, NULL_OK)); } CONTRACTL_END; LPVOID pThunk = NULL; #ifdef FEATURE_MIXEDMODE HELPER_METHOD_FRAME_BEGIN_RET_0(); if (pfnMethodToWrap == NULL) COMPlusThrowArgumentNull(W("pfnMethodToWrap")); if (pbSignature == NULL) COMPlusThrowArgumentNull(W("pbSignature")); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4996) // Suppress warning on call to deprecated method #endif Module *pModule = SystemDomain::GetCallersModule(1); #ifdef _MSC_VER #pragma warning(pop) #endif if (!pModule) ThrowOutOfMemory(); pThunk = pModule->GetMUThunk(pfnMethodToWrap, pbSignature, cbSignature); if (!pThunk) ThrowOutOfMemory(); HELPER_METHOD_FRAME_END(); #endif // FEATURE_MIXEDMODE return pThunk; } FCIMPLEND FCIMPL0(UINT32, MarshalNative::GetSystemMaxDBCSCharSize) { FCALL_CONTRACT; return GetMaxDBCSCharByteSize(); } FCIMPLEND /************************************************************************ * Handles all PInvoke.Copy(array source, ....) methods. */ FCIMPL4(void, MarshalNative::CopyToNative, Object* psrcUNSAFE, INT32 startindex, LPVOID pdst, INT32 length) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pdst, NULL_OK)); } CONTRACTL_END; // The BCL code guarantees that Array will be passed in _ASSERTE(!psrcUNSAFE || psrcUNSAFE->GetMethodTable()->IsArray()); BASEARRAYREF psrc = (BASEARRAYREF)(OBJECTREF)psrcUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(psrc); if (pdst == NULL) COMPlusThrowArgumentNull(W("destination")); if (psrc == NULL) COMPlusThrowArgumentNull(W("source")); SIZE_T numelem = psrc->GetNumComponents(); if (startindex < 0 || length < 0 || (SIZE_T)startindex + (SIZE_T)length > numelem) { COMPlusThrow(kArgumentOutOfRangeException, IDS_EE_COPY_OUTOFRANGE); } SIZE_T componentsize = psrc->GetComponentSize(); memcpyNoGCRefs(pdst, componentsize*startindex + (BYTE*)(psrc->GetDataPtr()), componentsize*length); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL4(void, MarshalNative::CopyToManaged, LPVOID psrc, Object* pdstUNSAFE, INT32 startindex, INT32 length) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(psrc, NULL_OK)); } CONTRACTL_END; // The BCL code guarantees that Array will be passed in _ASSERTE(!pdstUNSAFE || pdstUNSAFE->GetMethodTable()->IsArray()); BASEARRAYREF pdst = (BASEARRAYREF)(OBJECTREF)pdstUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(pdst); if (pdst == NULL) COMPlusThrowArgumentNull(W("destination")); if (psrc == NULL) COMPlusThrowArgumentNull(W("source")); if (startindex < 0) COMPlusThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Count")); if (length < 0) COMPlusThrowArgumentOutOfRange(W("length"), W("ArgumentOutOfRange_NeedNonNegNum")); SIZE_T numelem = pdst->GetNumComponents(); if ((SIZE_T)startindex + (SIZE_T)length > numelem) { COMPlusThrow(kArgumentOutOfRangeException, IDS_EE_COPY_OUTOFRANGE); } SIZE_T componentsize = pdst->GetComponentSize(); _ASSERTE(CorTypeInfo::IsPrimitiveType(pdst->GetArrayElementTypeHandle().GetInternalCorElementType())); memcpyNoGCRefs(componentsize*startindex + (BYTE*)(pdst->GetDataPtr()), psrc, componentsize*length); HELPER_METHOD_FRAME_END(); } FCIMPLEND /************************************************************************ * PInvoke.GetLastWin32Error */ FCIMPL0(int, MarshalNative::GetLastWin32Error) { FCALL_CONTRACT; return (UINT32)(GetThread()->m_dwLastError); } FCIMPLEND /************************************************************************ * PInvoke.SetLastWin32Error */ FCIMPL1(void, MarshalNative::SetLastWin32Error, int error) { FCALL_CONTRACT; GetThread()->m_dwLastError = (DWORD)error; } FCIMPLEND /************************************************************************ * Support for the GCHandle class. */ // Check that the supplied object is valid to put in a pinned handle. // Throw an exception if not. void GCHandleValidatePinnedObject(OBJECTREF obj) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; } CONTRACTL_END; // NULL is fine. if (obj == NULL) return; if (obj->GetMethodTable() == g_pStringClass) return; if (obj->GetMethodTable()->IsArray()) { BASEARRAYREF asArray = (BASEARRAYREF) obj; if (CorTypeInfo::IsPrimitiveType(asArray->GetArrayElementType())) return; TypeHandle th = asArray->GetArrayElementTypeHandle(); if (!th.IsTypeDesc()) { MethodTable *pMT = th.AsMethodTable(); if (pMT->IsValueType() && pMT->IsBlittable()) return; } } else if (obj->GetMethodTable()->IsBlittable()) { return; } COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC); } FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type) { FCALL_CONTRACT; OBJECTREF objRef(obj); OBJECTHANDLE hnd = 0; HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL(); // If it is a pinned handle, check the object type. if (type == HNDTYPE_PINNED) GCHandleValidatePinnedObject(objRef); // Create the handle. hnd = GetAppDomain()->CreateTypedHandle(objRef, type); HELPER_METHOD_FRAME_END_POLL(); return (LPVOID) hnd; } FCIMPLEND // Free a GC handle. FCIMPL1(VOID, MarshalNative::GCHandleInternalFree, OBJECTHANDLE handle) { FCALL_CONTRACT; HELPER_METHOD_FRAME_BEGIN_0(); #ifdef MDA_SUPPORTED UINT handleType = HandleFetchType(handle); #endif DestroyTypedHandle(handle); #ifdef MDA_SUPPORTED if (handleType == HNDTYPE_PINNED) { MDA_TRIGGER_ASSISTANT(GcManagedToUnmanaged, TriggerGC()); } #endif HELPER_METHOD_FRAME_END(); } FCIMPLEND // Get the object referenced by a GC handle. FCIMPL1(LPVOID, MarshalNative::GCHandleInternalGet, OBJECTHANDLE handle) { FCALL_CONTRACT; OBJECTREF objRef; objRef = ObjectFromHandle(handle); return *((LPVOID*)&objRef); } FCIMPLEND // Update the object referenced by a GC handle. FCIMPL3(VOID, MarshalNative::GCHandleInternalSet, OBJECTHANDLE handle, Object *obj, CLR_BOOL isPinned) { FCALL_CONTRACT; OBJECTREF objRef(obj); HELPER_METHOD_FRAME_BEGIN_1(objRef); //@todo: If the handle is pinned check the object type. if (isPinned) { GCHandleValidatePinnedObject(objRef); } // Update the stored object reference. StoreObjectInHandle(handle, objRef); HELPER_METHOD_FRAME_END(); } FCIMPLEND // Update the object referenced by a GC handle. FCIMPL4(Object*, MarshalNative::GCHandleInternalCompareExchange, OBJECTHANDLE handle, Object *obj, Object* oldObj, CLR_BOOL isPinned) { FCALL_CONTRACT; OBJECTREF newObjref(obj); OBJECTREF oldObjref(oldObj); LPVOID ret = NULL; HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL(); //@todo: If the handle is pinned check the object type. if (isPinned) GCHandleValidatePinnedObject(newObjref); // Update the stored object reference. ret = InterlockedCompareExchangeObjectInHandle(handle, newObjref, oldObjref); HELPER_METHOD_FRAME_END_POLL(); return (Object*)ret; } FCIMPLEND // Get the address of a pinned object referenced by the supplied pinned // handle. This routine assumes the handle is pinned and does not check. FCIMPL1(LPVOID, MarshalNative::GCHandleInternalAddrOfPinnedObject, OBJECTHANDLE handle) { FCALL_CONTRACT; LPVOID p; OBJECTREF objRef = ObjectFromHandle(handle); if (objRef == NULL) { p = NULL; } else { // Get the interior pointer for the supported pinned types. if (objRef->GetMethodTable() == g_pStringClass) p = ((*(StringObject **)&objRef))->GetBuffer(); else if (objRef->GetMethodTable()->IsArray()) p = (*((ArrayBase**)&objRef))->GetDataPtr(); else p = objRef->GetData(); } return p; } FCIMPLEND // Make sure the handle is accessible from the current domain. (Throw if not.) FCIMPL1(VOID, MarshalNative::GCHandleInternalCheckDomain, OBJECTHANDLE handle) { FCALL_CONTRACT; if (handle == NULL) FCThrowArgumentVoid(W("handle"), W("Argument_ArgumentZero")); ADIndex index = HndGetHandleTableADIndex(HndGetHandleTable(handle)); if (index.m_dwIndex != 1 && index != GetAppDomain()->GetIndex()) FCThrowArgumentVoid(W("handle"), W("Argument_HandleLeak")); } FCIMPLEND // Make sure the handle is accessible from the current domain. (Throw if not.) FCIMPL1(INT32, MarshalNative::GCHandleInternalGetHandleType, OBJECTHANDLE handle) { FCALL_CONTRACT; return HandleFetchType(handle); } FCIMPLEND FCIMPL1(INT32, MarshalNative::CalculateCount, ArrayWithOffsetData* pArrayWithOffset) { FCALL_CONTRACT; INT32 uRetVal = 0; BASEARRAYREF arrayObj = pArrayWithOffset->m_Array; HELPER_METHOD_FRAME_BEGIN_RET_1(arrayObj); SIZE_T cbTotalSize = 0; if (arrayObj != NULL) { if (!(arrayObj->GetMethodTable()->IsArray())) COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC); if (arrayObj->GetMethodTable()->IsMultiDimArray()) COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC); GCHandleValidatePinnedObject(arrayObj); } if (arrayObj == NULL) { if (pArrayWithOffset->m_cbOffset != 0) COMPlusThrow(kIndexOutOfRangeException, IDS_EE_ARRAYWITHOFFSETOVERFLOW); goto lExit; } cbTotalSize = arrayObj->GetNumComponents() * arrayObj->GetComponentSize(); if (cbTotalSize > MAX_SIZE_FOR_INTEROP) COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE); if (pArrayWithOffset->m_cbOffset > (INT32)cbTotalSize) COMPlusThrow(kIndexOutOfRangeException, IDS_EE_ARRAYWITHOFFSETOVERFLOW); uRetVal = (INT32)cbTotalSize - pArrayWithOffset->m_cbOffset; _ASSERTE(uRetVal >= 0); lExit: ; HELPER_METHOD_FRAME_END(); return uRetVal; } FCIMPLEND //==================================================================== // *** Interop Helpers *** //==================================================================== FCIMPL2(Object *, MarshalNative::GetExceptionForHR, INT32 errorCode, LPVOID errorInfo) { CONTRACTL { FCALL_CHECK; PRECONDITION(FAILED(errorCode)); PRECONDITION(CheckPointer(errorInfo, NULL_OK)); } CONTRACTL_END; OBJECTREF RetExceptionObj = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(RetExceptionObj); // Retrieve the IErrorInfo to use. IErrorInfo *pErrorInfo = (IErrorInfo*)errorInfo; if (pErrorInfo == (IErrorInfo*)(-1)) { pErrorInfo = NULL; } else if (!pErrorInfo) { if (SafeGetErrorInfo(&pErrorInfo) != S_OK) pErrorInfo = NULL; } ::GetExceptionForHR(errorCode, pErrorInfo, &RetExceptionObj); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(RetExceptionObj); } FCIMPLEND FCIMPL2(void, MarshalNative::ThrowExceptionForHR, INT32 errorCode, LPVOID errorInfo) { CONTRACTL { FCALL_CHECK; PRECONDITION(FAILED(errorCode)); PRECONDITION(CheckPointer(errorInfo, NULL_OK)); } CONTRACTL_END; HELPER_METHOD_FRAME_BEGIN_0(); // Retrieve the IErrorInfo to use. IErrorInfo *pErrorInfo = (IErrorInfo*)errorInfo; if (pErrorInfo == (IErrorInfo*)(-1)) { pErrorInfo = NULL; } else if (!pErrorInfo) { if (SafeGetErrorInfo(&pErrorInfo) != S_OK) pErrorInfo = NULL; } // Throw the exception based on the HR and the IErrorInfo. COMPlusThrowHR(errorCode, pErrorInfo); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL1(int, MarshalNative::GetHRForException, Object* eUNSAFE) { CONTRACTL { NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; int retVal = 0; OBJECTREF e = (OBJECTREF) eUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1({ retVal = COR_E_STACKOVERFLOW; }, e); retVal = SetupErrorInfo(e); HELPER_METHOD_FRAME_END_NOTHROW(); return retVal; } FCIMPLEND FCIMPL1(int, MarshalNative::GetHRForException_WinRT, Object* eUNSAFE) { CONTRACTL { NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; int retVal = 0; OBJECTREF e = (OBJECTREF) eUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1({ retVal = COR_E_STACKOVERFLOW; }, e); retVal = SetupErrorInfo(e, /* isWinRTScenario = */ TRUE); HELPER_METHOD_FRAME_END_NOTHROW(); return retVal; } FCIMPLEND #ifdef FEATURE_COMINTEROP //==================================================================== // map GUID to Type //==================================================================== /*OBJECTREF */ FCIMPL1(Object*, MarshalNative::GetLoadedTypeForGUID, GUID* pGuid) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pGuid, NULL_OK)); } CONTRACTL_END; OBJECTREF refRetVal = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); if (!pGuid) COMPlusThrowArgumentNull(W("pGuid")); AppDomain* pDomain = SystemDomain::GetCurrentDomain(); _ASSERTE(pDomain); MethodTable* pMT = pDomain->LookupClass(*(pGuid)); if (pMT) refRetVal = pMT->GetManagedClassObject(); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(refRetVal); } FCIMPLEND //==================================================================== // map Type to ITypeInfo* //==================================================================== FCIMPL1(ITypeInfo*, MarshalNative::GetITypeInfoForType, ReflectClassBaseObject* refClassUNSAFE) { FCALL_CONTRACT; ITypeInfo* pTI = NULL; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(refClass); // Check for null arguments. if(!refClass) COMPlusThrowArgumentNull(W("t")); MethodTable *pRefMT = refClass->GetMethodTable(); if (pRefMT != g_pRuntimeTypeClass && pRefMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); TypeHandle th = refClass->GetType(); if (th.GetMethodTable() != NULL && (th.IsProjectedFromWinRT() || th.IsExportedToWinRT())) COMPlusThrowArgumentException(W("t"), W("Argument_ObjIsWinRTObject")); if (th.HasInstantiation()) COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType")); // Make sure the type is visible from COM. if (!::IsTypeVisibleFromCom(th)) COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom")); // Retrieve the EE class from the reflection type. MethodTable* pMT = th.GetMethodTable(); _ASSERTE(pMT); // Retrieve the ITypeInfo for the class. IfFailThrow(GetITypeInfoForEEClass(pMT, &pTI, true)); _ASSERTE(pTI != NULL); HELPER_METHOD_FRAME_END(); return pTI; } FCIMPLEND //==================================================================== // return the IUnknown* for an Object. //==================================================================== FCIMPL2(IUnknown*, MarshalNative::GetIUnknownForObjectNative, Object* orefUNSAFE, CLR_BOOL fOnlyInContext) { FCALL_CONTRACT; IUnknown* retVal = NULL; OBJECTREF oref = (OBJECTREF) orefUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if(!oref) COMPlusThrowArgumentNull(W("o")); // Ensure COM is started up. EnsureComStarted(); if (fOnlyInContext && !IsObjectInContext(&oref)) retVal = NULL; else retVal = GetComIPFromObjectRef(&oref, ComIpType_OuterUnknown, NULL); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND //==================================================================== // return the raw IUnknown* for a COM Object not related to current // context. // Does not AddRef the returned pointer //==================================================================== FCIMPL1(IUnknown*, MarshalNative::GetRawIUnknownForComObjectNoAddRef, Object* orefUNSAFE) { FCALL_CONTRACT; IUnknown* retVal = NULL; OBJECTREF oref = (OBJECTREF) orefUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if(!oref) COMPlusThrowArgumentNull(W("o")); MethodTable* pMT = oref->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if(!pMT->IsComObjectType()) COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT); // Ensure COM is started up. EnsureComStarted(); RCWHolder pRCW(GetThread()); pRCW.Init(oref); // Retrieve raw IUnknown * without AddRef for better performance retVal = pRCW->GetRawIUnknown_NoAddRef(); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND //==================================================================== // return the IDispatch* for an Object. //==================================================================== FCIMPL2(IDispatch*, MarshalNative::GetIDispatchForObjectNative, Object* orefUNSAFE, CLR_BOOL fOnlyInContext) { FCALL_CONTRACT; IDispatch* retVal = NULL; OBJECTREF oref = (OBJECTREF) orefUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if(!oref) COMPlusThrowArgumentNull(W("o")); // Ensure COM is started up. EnsureComStarted(); if (fOnlyInContext && !IsObjectInContext(&oref)) retVal = NULL; else retVal = (IDispatch*)GetComIPFromObjectRef(&oref, ComIpType_Dispatch, NULL); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND //==================================================================== // return the IUnknown* representing the interface for the Object // Object o should support Type T //==================================================================== FCIMPL4(IUnknown*, MarshalNative::GetComInterfaceForObjectNative, Object* orefUNSAFE, ReflectClassBaseObject* refClassUNSAFE, CLR_BOOL fOnlyInContext, CLR_BOOL bEnableCustomizedQueryInterface) { FCALL_CONTRACT; IUnknown* retVal = NULL; OBJECTREF oref = (OBJECTREF) orefUNSAFE; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_2(oref, refClass); HRESULT hr = S_OK; if(!oref) COMPlusThrowArgumentNull(W("o")); if(!refClass) COMPlusThrowArgumentNull(W("t")); // Ensure COM is started up. EnsureComStarted(); if (refClass->GetMethodTable() != g_pRuntimeTypeClass) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); TypeHandle th = refClass->GetType(); if (!th.SupportsGenericInterop(TypeHandle::Interop_NativeToManaged)) { if (th.HasInstantiation()) COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType")); if (oref->GetMethodTable()->HasInstantiation()) COMPlusThrowArgumentException(W("o"), W("Argument_NeedNonGenericObject")); } // If the IID being asked for does not represent an interface then // throw an argument exception. if (!th.IsInterface()) COMPlusThrowArgumentException(W("t"), W("Arg_MustBeInterface")); // If the interface being asked for is not visible from COM then // throw an argument exception. if (!::IsTypeVisibleFromCom(th)) COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom")); if (fOnlyInContext && !IsObjectInContext(&oref)) retVal = NULL; else retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), TRUE, bEnableCustomizedQueryInterface); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND //==================================================================== // return an Object for IUnknown //==================================================================== FCIMPL1(Object*, MarshalNative::GetObjectForIUnknown, IUnknown* pUnk) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; OBJECTREF oref = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if(!pUnk) COMPlusThrowArgumentNull(W("pUnk")); // Ensure COM is started up. EnsureComStarted(); GetObjectRefFromComIP(&oref, pUnk); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(oref); } FCIMPLEND FCIMPL1(Object*, MarshalNative::GetUniqueObjectForIUnknown, IUnknown* pUnk) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; OBJECTREF oref = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if(!pUnk) COMPlusThrowArgumentNull(W("pUnk")); // Ensure COM is started up. EnsureComStarted(); GetObjectRefFromComIP(&oref, pUnk, NULL, NULL, ObjFromComIP::UNIQUE_OBJECT); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(oref); } FCIMPLEND //==================================================================== // return an Object for IUnknown, using the Type T, // NOTE: // Type T should be either a COM imported Type or a sub-type of COM imported Type //==================================================================== FCIMPL2(Object*, MarshalNative::GetTypedObjectForIUnknown, IUnknown* pUnk, ReflectClassBaseObject* refClassUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; OBJECTREF oref = NULL; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, oref); HRESULT hr = S_OK; MethodTable* pMTClass = NULL; if(!pUnk) COMPlusThrowArgumentNull(W("pUnk")); if(refClass != NULL) { if (refClass->GetMethodTable() != g_pRuntimeTypeClass) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); TypeHandle th = refClass->GetType(); if (th.GetMethodTable() != NULL && (th.IsProjectedFromWinRT() || th.IsExportedToWinRT())) COMPlusThrowArgumentException(W("t"), W("Argument_ObjIsWinRTObject")); if (th.HasInstantiation()) COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType")); pMTClass = th.GetMethodTable(); } else COMPlusThrowArgumentNull(W("t")); // Ensure COM is started up. EnsureComStarted(); GetObjectRefFromComIP(&oref, pUnk, pMTClass); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(oref); } FCIMPLEND FCIMPL2(IUnknown*, MarshalNative::CreateAggregatedObject, IUnknown* pOuter, Object* refObjUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pOuter, NULL_OK)); } CONTRACTL_END; IUnknown* pInner = NULL; OBJECTREF oref = (OBJECTREF)refObjUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(oref); HRESULT hr = S_OK; if (!pOuter) COMPlusThrowArgumentNull(W("pOuter")); if (oref == NULL) COMPlusThrowArgumentNull(W("o")); MethodTable *pMT = oref->GetTrueMethodTable(); if (pMT->IsWinRTObjectType() || pMT->IsExportedToWinRT()) COMPlusThrowArgumentException(W("o"), W("Argument_ObjIsWinRTObject")); // Ensure COM is started up. EnsureComStarted(); if (NULL != ComCallWrapper::GetWrapperForObject(oref)) COMPlusThrowArgumentException(W("o"), W("Argument_AlreadyACCW")); //get wrapper for the object, this could enable GC CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&oref); // Aggregation support, pWrap->InitializeOuter(pOuter); IfFailThrow(pWrap->GetInnerUnknown((LPVOID*)&pInner)); HELPER_METHOD_FRAME_END(); return pInner; } FCIMPLEND //==================================================================== // Free unused RCWs in the current COM+ context. //==================================================================== FCIMPL0(void, MarshalNative::CleanupUnusedObjectsInCurrentContext) { FCALL_CONTRACT; HELPER_METHOD_FRAME_BEGIN_0(); if (g_pRCWCleanupList) { g_pRCWCleanupList->CleanupWrappersInCurrentCtxThread( TRUE, // fWait TRUE, // fManualCleanupRequested TRUE // bIgnoreComObjectEagerCleanupSetting ); } HELPER_METHOD_FRAME_END(); } FCIMPLEND //==================================================================== // Checks whether there are RCWs from any context available for cleanup. //==================================================================== FCIMPL0(FC_BOOL_RET, MarshalNative::AreComObjectsAvailableForCleanup) { FCALL_CONTRACT; BOOL retVal = FALSE; if (g_pRCWCleanupList) { retVal = !g_pRCWCleanupList->IsEmpty(); } FC_RETURN_BOOL(retVal); } FCIMPLEND //==================================================================== // check if the object is classic COM component //==================================================================== FCIMPL1(FC_BOOL_RET, MarshalNative::IsComObject, Object* objUNSAFE) { FCALL_CONTRACT; BOOL retVal = FALSE; OBJECTREF obj = (OBJECTREF) objUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(obj); if(!obj) COMPlusThrowArgumentNull(W("o")); MethodTable* pMT = obj->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); retVal = pMT->IsComObjectType(); HELPER_METHOD_FRAME_END(); FC_RETURN_BOOL(retVal); } FCIMPLEND //==================================================================== // free the COM component and zombie this object if the ref count hits 0 // further usage of this Object might throw an exception, //==================================================================== FCIMPL1(INT32, MarshalNative::ReleaseComObject, Object* objUNSAFE) { FCALL_CONTRACT; INT32 retVal = 0; OBJECTREF obj = (OBJECTREF) objUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(obj); if(!obj) COMPlusThrowArgumentNull(W("o")); MethodTable* pMT = obj->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if(!pMT->IsComObjectType()) COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT); // remove the wrapper from the object retVal = RCW::ExternalRelease(&obj); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND //==================================================================== // free the COM component and zombie this object // further usage of this Object might throw an exception, //==================================================================== FCIMPL1(void, MarshalNative::FinalReleaseComObject, Object* objUNSAFE) { FCALL_CONTRACT; OBJECTREF obj = (OBJECTREF) objUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(obj); if(!obj) COMPlusThrowArgumentNull(W("o")); MethodTable* pMT = obj->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if(!pMT->IsComObjectType()) COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT); // remove the wrapper from the object RCW::FinalExternalRelease(&obj); HELPER_METHOD_FRAME_END(); } FCIMPLEND //==================================================================== // This method takes the given COM object and wraps it in an object // of the specified type. The type must be derived from __ComObject. //==================================================================== FCIMPL2(Object*, MarshalNative::InternalCreateWrapperOfType, Object* objUNSAFE, ReflectClassBaseObject* refClassUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(objUNSAFE != NULL); PRECONDITION(refClassUNSAFE != NULL); } CONTRACTL_END; struct _gc { OBJECTREF refRetVal; OBJECTREF obj; REFLECTCLASSBASEREF refClass; } gc; gc.refRetVal = NULL; gc.obj = (OBJECTREF) objUNSAFE; gc.refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); // Validate the arguments. if (gc.refClass->GetMethodTable() != g_pRuntimeTypeClass) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); // Retrieve the class of the COM object. MethodTable *pObjMT = gc.obj->GetMethodTable(); // Retrieve the method table for new wrapper type. MethodTable *pNewWrapMT = gc.refClass->GetType().GetMethodTable(); // Validate that the destination type is a COM object. _ASSERTE(pNewWrapMT->IsComObjectType()); BOOL fSet = FALSE; // Start by checking if we can cast the obj to the wrapper type. #ifdef FEATURE_REMOTING if (pObjMT->IsTransparentProxy()) { if (CRemotingServices::CheckCast(gc.obj, pNewWrapMT)) { gc.refRetVal = gc.obj; fSet = TRUE; } } else #endif if (TypeHandle(pObjMT).CanCastTo(TypeHandle(pNewWrapMT))) { gc.refRetVal = gc.obj; fSet = TRUE; } if (!fSet) { // Validate that the source object is a valid COM object. _ASSERTE(pObjMT->IsComObjectType()); RCWHolder pRCW(GetThread()); RCWPROTECT_BEGIN(pRCW, gc.obj); // Make sure the COM object supports all the COM imported interfaces that the new // wrapper class implements. MethodTable::InterfaceMapIterator it = pNewWrapMT->IterateInterfaceMap(); while (it.Next()) { MethodTable *pItfMT = it.GetInterface(); if (pItfMT->IsComImport()) { if (!Object::SupportsInterface(gc.obj, pItfMT)) COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_COMOBJECT); } } // Create the duplicate wrapper object. { RCWHolder pNewRCW(GetThread()); pRCW->CreateDuplicateWrapper(pNewWrapMT, &pNewRCW); gc.refRetVal = pNewRCW->GetExposedObject(); } RCWPROTECT_END(pRCW); } HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(gc.refRetVal); } FCIMPLEND //==================================================================== // check if the type is visible from COM. //==================================================================== FCIMPL1(FC_BOOL_RET, MarshalNative::IsTypeVisibleFromCom, ReflectClassBaseObject* refClassUNSAFE) { FCALL_CONTRACT; BOOL retVal = FALSE; REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(refClass); // Validate the arguments. if (refClass == NULL) COMPlusThrowArgumentNull(W("t")); MethodTable *pRefMT = refClass->GetMethodTable(); if (pRefMT != g_pRuntimeTypeClass && pRefMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); // Call the internal version of IsTypeVisibleFromCom. retVal = ::IsTypeVisibleFromCom(refClass->GetType()); HELPER_METHOD_FRAME_END(); FC_RETURN_BOOL(retVal); } FCIMPLEND //==================================================================== // IUnknown Helpers //==================================================================== // IUnknown::QueryInterface FCIMPL3(HRESULT, MarshalNative::QueryInterface, IUnknown* pUnk, REFGUID iid, void** ppv) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); PRECONDITION(CheckPointer(ppv)); } CONTRACTL_END; HRESULT hr = S_OK; HELPER_METHOD_FRAME_BEGIN_RET_0(); if (!pUnk) COMPlusThrowArgumentNull(W("pUnk")); hr = SafeQueryInterface(pUnk,iid,(IUnknown**)ppv); LogInteropQI(pUnk, iid, hr, "PInvoke::QI"); HELPER_METHOD_FRAME_END(); return hr; } FCIMPLEND // IUnknown::AddRef FCIMPL1(ULONG, MarshalNative::AddRef, IUnknown* pUnk) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; ULONG cbRef = 0; HELPER_METHOD_FRAME_BEGIN_RET_0(); if (!pUnk) COMPlusThrowArgumentNull(W("pUnk")); cbRef = SafeAddRef(pUnk); LogInteropAddRef(pUnk, cbRef, "PInvoke.AddRef"); HELPER_METHOD_FRAME_END(); return cbRef; } FCIMPLEND //IUnknown::Release FCIMPL1(ULONG, MarshalNative::Release, IUnknown* pUnk) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; ULONG cbRef = 0; HELPER_METHOD_FRAME_BEGIN_RET_0(); if (!pUnk) COMPlusThrowArgumentNull(W("pUnk")); cbRef = SafeRelease(pUnk); LogInteropRelease(pUnk, cbRef, "PInvoke.Release"); HELPER_METHOD_FRAME_END(); return cbRef; } FCIMPLEND FCIMPL2(void, MarshalNative::GetNativeVariantForObject, Object* ObjUNSAFE, LPVOID pDestNativeVariant) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pDestNativeVariant, NULL_OK)); } CONTRACTL_END; OBJECTREF Obj = (OBJECTREF) ObjUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(Obj); if (pDestNativeVariant == NULL) COMPlusThrowArgumentNull(W("pDstNativeVariant")); if (Obj == NULL) { // Will return empty variant in MarshalOleVariantForObject } else if (Obj->GetMethodTable()->HasInstantiation()) { COMPlusThrowArgumentException(W("obj"), W("Argument_NeedNonGenericObject")); } // intialize the output variant SafeVariantInit((VARIANT*)pDestNativeVariant); OleVariant::MarshalOleVariantForObject(&Obj, (VARIANT*)pDestNativeVariant); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL1(Object*, MarshalNative::GetObjectForNativeVariant, LPVOID pSrcNativeVariant) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pSrcNativeVariant, NULL_OK)); } CONTRACTL_END; OBJECTREF Obj = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(Obj); if (pSrcNativeVariant == NULL) COMPlusThrowArgumentNull(W("pSrcNativeVariant")); OleVariant::MarshalObjectForOleVariant((VARIANT*)pSrcNativeVariant, &Obj); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(Obj); } FCIMPLEND FCIMPL2(Object*, MarshalNative::GetObjectsForNativeVariants, VARIANT* aSrcNativeVariant, int cVars) { CONTRACTL { FCALL_CHECK; INJECT_FAULT(FCThrow(kOutOfMemoryException);); PRECONDITION(CheckPointer(aSrcNativeVariant, NULL_OK)); } CONTRACTL_END; PTRARRAYREF Array = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(Array); if (aSrcNativeVariant == NULL) COMPlusThrowArgumentNull(W("aSrcNativeVariant")); if (cVars < 0) COMPlusThrowArgumentOutOfRange(W("cVars"), W("ArgumentOutOfRange_NeedNonNegNum")); OBJECTREF Obj = NULL; GCPROTECT_BEGIN(Obj) { // Allocate the array of objects. Array = (PTRARRAYREF)AllocateObjectArray(cVars, g_pObjectClass); // Convert each VARIANT in the array into an object. for (int i = 0; i < cVars; i++) { OleVariant::MarshalObjectForOleVariant(&aSrcNativeVariant[i], &Obj); Array->SetAt(i, Obj); } } GCPROTECT_END(); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(Array); } FCIMPLEND FCIMPL2(void, MarshalNative::DoGenerateGuidForType, GUID * result, ReflectClassBaseObject* refTypeUNSAFE) { FCALL_CONTRACT; REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF) refTypeUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refType); GCPROTECT_BEGININTERIOR (result); // Validate the arguments. if (refType == NULL) COMPlusThrowArgumentNull(W("type")); MethodTable *pRefMT = refType->GetMethodTable(); if (pRefMT != g_pRuntimeTypeClass && pRefMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("type"), W("Argument_MustBeRuntimeType")); if (result == NULL) COMPlusThrow(kArgumentNullException, W("ArgumentNull_GUID")); // Check to see if the type is a COM object or not. if (IsComObjectClass(refType->GetType())) { #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION // The type is a COM object then we get the GUID from the class factory. SyncBlock* pSyncBlock = refType->GetSyncBlock(); ComClassFactory* pComClsFac = pSyncBlock->GetInteropInfo()->GetComClassFactory(); memcpy(result, &pComClsFac->m_rclsid, sizeof(GUID)); #else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION memset(result,0,sizeof(GUID)); #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION } else { // The type is a normal COM+ class so we need to generate the GUID. TypeHandle classTH = refType->GetType(); classTH.GetMethodTable()->GetGuid(result, TRUE); } GCPROTECT_END (); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL2(void, MarshalNative::DoGetTypeLibGuid, GUID * result, Object* refTlbUNSAFE) { FCALL_CONTRACT; OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refTlb); GCPROTECT_BEGININTERIOR (result); if (refTlb == NULL) COMPlusThrowArgumentNull(W("pTLB"), W("ArgumentNull_Generic")); // Ensure COM is started up. EnsureComStarted(); SafeComHolder pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib); if (!pTLB) COMPlusThrow(kArgumentException, W("Arg_NoITypeLib")); GCX_PREEMP(); // Retrieve the TLIBATTR. TLIBATTR *pAttr; IfFailThrow(pTLB->GetLibAttr(&pAttr)); // Extract the guid from the TLIBATTR. *result = pAttr->guid; // Release the TLIBATTR now that we have the GUID. pTLB->ReleaseTLibAttr(pAttr); GCPROTECT_END (); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL1(LCID, MarshalNative::GetTypeLibLcid, Object* refTlbUNSAFE) { FCALL_CONTRACT; LCID retVal = 0; OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(refTlb); if (refTlb == NULL) COMPlusThrowArgumentNull(W("pTLB"), W("ArgumentNull_Generic")); // Ensure COM is started up. EnsureComStarted(); SafeComHolder pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib); if (!pTLB) COMPlusThrow(kArgumentException, W("Arg_NoITypeLib")); GCX_PREEMP(); // Retrieve the TLIBATTR. TLIBATTR *pAttr; IfFailThrow(pTLB->GetLibAttr(&pAttr)); // Extract the LCID from the TLIBATTR. retVal = pAttr->lcid; // Release the TLIBATTR now that we have the LCID. pTLB->ReleaseTLibAttr(pAttr); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND FCIMPL3(void, MarshalNative::GetTypeLibVersion, Object* refTlbUNSAFE, int *pMajor, int *pMinor) { FCALL_CONTRACT; OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refTlb); if (refTlb == NULL) COMPlusThrowArgumentNull(W("typeLibrary"), W("ArgumentNull_Generic")); // Ensure COM is started up. EnsureComStarted(); SafeComHolder pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib); if (!pTLB) COMPlusThrow(kArgumentException, W("Arg_NoITypeLib")); GCX_PREEMP(); // Retrieve the TLIBATTR. TLIBATTR *pAttr; IfFailThrow(pTLB->GetLibAttr(&pAttr)); // Extract the LCID from the TLIBATTR. *pMajor = pAttr->wMajorVerNum; *pMinor = pAttr->wMinorVerNum; // Release the TLIBATTR now that we have the version numbers. pTLB->ReleaseTLibAttr(pAttr); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL2(void, MarshalNative::DoGetTypeInfoGuid, GUID * result, Object* refTypeInfoUNSAFE) { FCALL_CONTRACT; OBJECTREF refTypeInfo = (OBJECTREF) refTypeInfoUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refTypeInfo); GCPROTECT_BEGININTERIOR (result); if (refTypeInfo == NULL) COMPlusThrowArgumentNull(W("typeInfo"), W("ArgumentNull_Generic")); // Ensure COM is started up. EnsureComStarted(); SafeComHolder pTI = (ITypeInfo*)GetComIPFromObjectRef(&refTypeInfo, IID_ITypeInfo); if (!pTI) COMPlusThrow(kArgumentException, W("Arg_NoITypeInfo")); GCX_PREEMP(); // Retrieve the TYPEATTR. TYPEATTR *pAttr; IfFailThrow(pTI->GetTypeAttr(&pAttr)); // Extract the guid from the TYPEATTR. *result = pAttr->guid; // Release the TYPEATTR now that we have the GUID. pTI->ReleaseTypeAttr(pAttr); GCPROTECT_END (); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL2(void, MarshalNative::DoGetTypeLibGuidForAssembly, GUID * result, AssemblyBaseObject* refAsmUNSAFE) { FCALL_CONTRACT; // Validate the arguments. _ASSERTE(refAsmUNSAFE != NULL); _ASSERTE(result != NULL); ASSEMBLYREF refAsm = (ASSEMBLYREF) refAsmUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refAsm); GCPROTECT_BEGININTERIOR (result) HRESULT hr = S_OK; // Retrieve the assembly from the ASSEMBLYREF. Assembly *pAssembly = refAsm->GetAssembly(); _ASSERTE(pAssembly); // Retrieve the TLBID for the assembly. IfFailThrow(::GetTypeLibGuidForAssembly(pAssembly, result)); GCPROTECT_END (); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL3(void, MarshalNative::GetTypeLibVersionForAssembly, AssemblyBaseObject* refAsmUNSAFE, INT32 *pMajorVersion, INT32 *pMinorVersion) { FCALL_CONTRACT; // Validate the arguments. _ASSERTE(refAsmUNSAFE != NULL); ASSEMBLYREF refAsm = (ASSEMBLYREF) refAsmUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(refAsm); HRESULT hr = S_OK; // Retrieve the assembly from the ASSEMBLYREF. Assembly *pAssembly = refAsm->GetAssembly(); _ASSERTE(pAssembly); // Retrieve the version for the assembly. USHORT usMaj, usMin; IfFailThrow(::GetTypeLibVersionForAssembly(pAssembly, &usMaj, &usMin)); // Set the out parameters. *pMajorVersion = usMaj; *pMinorVersion = usMin; HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL1(int, MarshalNative::GetStartComSlot, ReflectClassBaseObject* tUNSAFE) { FCALL_CONTRACT; int retVal = 0; REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(t); if (!(t)) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); MethodTable *pTMT = t->GetMethodTable(); if (pTMT != g_pRuntimeTypeClass && pTMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); MethodTable *pMT = t->GetType().GetMethodTable(); if (NULL == pMT) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); // The service does not make any sense to be called for non COM visible types. if (!::IsTypeVisibleFromCom(TypeHandle(pMT))) COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom")); retVal = GetComSlotInfo(pMT, &pMT); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND FCIMPL1(int, MarshalNative::GetEndComSlot, ReflectClassBaseObject* tUNSAFE) { FCALL_CONTRACT; int retVal = 0; REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_1(t); int StartSlot = -1; if (!(t)) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); MethodTable *pTMT = t->GetMethodTable(); if (pTMT != g_pRuntimeTypeClass && pTMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); TypeHandle classTH = t->GetType(); MethodTable *pMT = classTH.GetMethodTable(); if (NULL == pMT) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); // The service does not make any sense to be called for non COM visible types. if (!::IsTypeVisibleFromCom(classTH)) COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom")); // Retrieve the start slot and the default interface class. StartSlot = GetComSlotInfo(pMT, &pMT); if (StartSlot == -1) { retVal = StartSlot; } else { // Retrieve the map of members. ComMTMemberInfoMap MemberMap(pMT); MemberMap.Init(sizeof(void*)); // The end slot is the start slot plus the number of user defined methods. retVal = int(StartSlot + MemberMap.GetMethods().Size() - 1); } HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND FCIMPL1(int, MarshalNative::GetComSlotForMethodInfo, ReflectMethodObject* pMethodUNSAFE) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pMethodUNSAFE)); PRECONDITION(pMethodUNSAFE->GetMethod()->GetMethodTable()->IsInterface()); } CONTRACTL_END; REFLECTMETHODREF refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE); MethodDesc *pMeth = refMethod->GetMethod(); _ASSERTE(pMeth); int retVal = 0; HELPER_METHOD_FRAME_BEGIN_RET_1(refMethod); retVal = pMeth->GetComSlot(); HELPER_METHOD_FRAME_END(); return retVal; } FCIMPLEND FCIMPL3(Object*, MarshalNative::GetMethodInfoForComSlot, ReflectClassBaseObject* tUNSAFE, INT32 slot, ComMemberType* pMemberType) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pMemberType, NULL_OK)); } CONTRACTL_END; OBJECTREF refRetVal = NULL; REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE; REFLECTCLASSBASEREF tInterface = NULL; HELPER_METHOD_FRAME_BEGIN_RET_2(t, tInterface); int StartSlot = -1; OBJECTREF MemberInfoObj = NULL; if (!(t)) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); MethodTable *pTMT = t->GetMethodTable(); if (pTMT != g_pRuntimeTypeClass && pTMT != MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY)) COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType")); TypeHandle type = t->GetType(); MethodTable *pMT= type.GetMethodTable(); if (NULL == pMT) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Generic")); // The service does not make any sense to be called for non COM visible types. if (!::IsTypeVisibleFromCom(type)) COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom")); // Retrieve the start slot and the default interface class. StartSlot = GetComSlotInfo(pMT, &pMT); if (StartSlot == -1) COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count")); // Retrieve the map of members. ComMTMemberInfoMap MemberMap(pMT); MemberMap.Init(sizeof(void*)); CQuickArray &rProps = MemberMap.GetMethods(); // Update the typehandle we'll be using based on the interface returned by GetComSlotInfo. tInterface = (REFLECTCLASSBASEREF)pMT->GetManagedClassObject(); type = TypeHandle(pMT); // Make sure the specified slot is valid. if (slot < StartSlot) COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count")); if (slot >= StartSlot + (int)rProps.Size()) COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count")); ComMTMethodProps *pProps = &rProps[slot - StartSlot]; if (pProps->semantic >= FieldSemanticOffset) { // We are dealing with a field. ComCallMethodDesc *pFieldMeth = reinterpret_cast(pProps->pMeth); FieldDesc *pField = pFieldMeth->GetFieldDesc(); // call the managed code to get the FieldInfo MethodDescCallSite getFieldInfo(METHOD__CLASS__GET_FIELD_INFO); ARG_SLOT args[] = { ObjToArgSlot(tInterface), (ARG_SLOT)pField }; MemberInfoObj = getFieldInfo.Call_RetOBJECTREF(args); *(pMemberType) = (pProps->semantic == (FieldSemanticOffset + msGetter)) ? CMT_PropGet : CMT_PropSet; } else if (pProps->property == mdPropertyNil) { // We are dealing with a normal property. // call the managed code to get the MethodInfo MethodDescCallSite getMethodBase(METHOD__CLASS__GET_METHOD_BASE); ARG_SLOT args[] = { ObjToArgSlot(tInterface), (ARG_SLOT)pProps->pMeth }; MemberInfoObj = getMethodBase.Call_RetOBJECTREF(args); *(pMemberType) = CMT_Method; } else { // We are dealing with a property. mdProperty tkProp; if (TypeFromToken(pProps->property) == mdtProperty) tkProp = pProps->property; else tkProp = rProps[pProps->property].property; // call the managed code to get the PropertyInfo MethodDescCallSite getPropertyInfo(METHOD__CLASS__GET_PROPERTY_INFO); ARG_SLOT args[] = { ObjToArgSlot(tInterface), tkProp }; MemberInfoObj = getPropertyInfo.Call_RetOBJECTREF(args); *(pMemberType) = (pProps->semantic == msGetter) ? CMT_PropGet : CMT_PropSet; } refRetVal = MemberInfoObj; HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(refRetVal); } FCIMPLEND //+---------------------------------------------------------------------------- // // Method: MarshalNative::WrapIUnknownWithComObject // Synopsis: unmarshal the buffer and return IUnknown // // //+---------------------------------------------------------------------------- FCIMPL1(Object*, MarshalNative::WrapIUnknownWithComObject, IUnknown* pUnk) { CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pUnk, NULL_OK)); } CONTRACTL_END; OBJECTREF cref = NULL; HELPER_METHOD_FRAME_BEGIN_RET_0(); if(pUnk == NULL) COMPlusThrowArgumentNull(W("punk")); EnsureComStarted(); COMInterfaceMarshaler marshaler; marshaler.Init(pUnk, g_pBaseCOMObject, GET_THREAD()); cref = marshaler.WrapWithComObject(); if (cref == NULL) COMPlusThrowOM(); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(cref); } FCIMPLEND //+---------------------------------------------------------------------------- // // Method: CLR_BOOL __stdcall MarshalNative::SwitchCCW(switchCCWArgs* pArgs) // // Synopsis: switch the wrapper from oldtp to newtp // // //+---------------------------------------------------------------------------- FCIMPL2(FC_BOOL_RET, MarshalNative::SwitchCCW, Object* oldtpUNSAFE, Object* newtpUNSAFE) { FCALL_CONTRACT; BOOL retVal = FALSE; OBJECTREF oldtp = (OBJECTREF) oldtpUNSAFE; OBJECTREF newtp = (OBJECTREF) newtpUNSAFE; HELPER_METHOD_FRAME_BEGIN_RET_2(oldtp, newtp); if (oldtp == NULL) COMPlusThrowArgumentNull(W("oldtp")); if (newtp == NULL) COMPlusThrowArgumentNull(W("newtp")); // defined in interoputil.cpp retVal = ReconnectWrapper(&oldtp, &newtp); HELPER_METHOD_FRAME_END(); FC_RETURN_BOOL(retVal); } FCIMPLEND FCIMPL2(void, MarshalNative::ChangeWrapperHandleStrength, Object* orefUNSAFE, CLR_BOOL fIsWeak) { FCALL_CONTRACT; OBJECTREF oref = (OBJECTREF) orefUNSAFE; HELPER_METHOD_FRAME_BEGIN_1(oref); if(oref == NULL) COMPlusThrowArgumentNull(W("otp")); if ( #ifdef FEATURE_REMOTING CRemotingServices::IsTransparentProxy(OBJECTREFToObject(oref)) || #endif !oref->GetMethodTable()->IsComImport()) { CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&oref); if (pWrap == NULL) COMPlusThrowOM(); AppDomainFromIDHolder pDomain(pWrap->GetDomainID(), FALSE); pDomain.ThrowIfUnloaded(); if (fIsWeak != 0) pWrap->MarkHandleWeak(); else pWrap->ResetHandleStrength(); pDomain.Release(); } HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL2(void, MarshalNative::InitializeWrapperForWinRT, Object *unsafe_pThis, IUnknown **ppUnk) { FCALL_CONTRACT; OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis); HELPER_METHOD_FRAME_BEGIN_1(oref); _ASSERTE(ppUnk != NULL); if (*ppUnk == NULL) { // this should never happen but it's not nice to AV if the factory method is busted and returns NULL COMPlusThrow(kNullReferenceException); } // the object does not have the right RCW yet COMInterfaceMarshaler marshaler; marshaler.Init(*ppUnk, oref->GetMethodTable(), GET_THREAD(), RCW::CF_SupportsIInspectable | RCW::CF_QueryForIdentity); // the following will assign NULL to *ppUnk which signals to the caller that we successfully // initialized the RCW so (*ppUnk)->Release() should be suppressed marshaler.InitializeExistingComObject(&oref, ppUnk); HELPER_METHOD_FRAME_END(); } FCIMPLEND FCIMPL2(void, MarshalNative::InitializeManagedWinRTFactoryObject, Object *unsafe_pThis, ReflectClassBaseObject *unsafe_pType) { FCALL_CONTRACT; OBJECTREF orefThis = ObjectToOBJECTREF(unsafe_pThis); REFLECTCLASSBASEREF orefType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(unsafe_pType); HELPER_METHOD_FRAME_BEGIN_2(orefThis, orefType); MethodTable *pMT = orefType->GetType().GetMethodTable(); // get the special "factory" template for the type _ASSERTE(pMT->IsExportedToWinRT()); WinRTManagedClassFactory *pFactory = GetComClassFactory(pMT)->AsWinRTManagedClassFactory(); ComCallWrapperTemplate *pTemplate = pFactory->GetOrCreateComCallWrapperTemplate(orefThis->GetMethodTable()); // create a CCW for the factory object using the template CCWHolder pCCWHold = ComCallWrapper::InlineGetWrapper(&orefThis, pTemplate); HELPER_METHOD_FRAME_END(); } FCIMPLEND // // Create activation factory and wraps it with a unique RCW // // This is necessary because WinRT factories are often implemented as a singleton, // and getting back a RCW for such WinRT factory would usually get back a RCW from // another apartment, even if the interface pointe returned from GetActivationFactory // is a raw pointer. As a result, user would randomly get back RCWs for activation // factories from other apartments and make transiton to those apartments and cause // deadlocks and create objects in incorrect apartments // // The solution here is to always create a unique RCW // FCIMPL1(Object *, MarshalNative::GetNativeActivationFactory, ReflectClassBaseObject *unsafe_pType) { FCALL_CONTRACT; REFLECTCLASSBASEREF orefType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(unsafe_pType); OBJECTREF orefFactory = NULL; HELPER_METHOD_FRAME_BEGIN_RET_2(orefFactory, orefType); MethodTable *pMT = orefType->GetType().GetMethodTable(); // Must be a native WinRT type _ASSERTE(pMT->IsProjectedFromWinRT()); // // Get the activation factory instance for this WinRT type and create a RCW for it // GetNativeWinRTFactoryObject( pMT, GET_THREAD(), NULL, // No factory interface available at this point TRUE, // Create unique RCW - See comments for this function for more details NULL, // No callback necessary &orefFactory // return value ); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(orefFactory); } FCIMPLEND void QCALLTYPE MarshalNative::GetInspectableIIDs( QCall::ObjectHandleOnStack hobj, QCall::ObjectHandleOnStack retArrayGuids) { CONTRACTL { QCALL_CHECK; PRECONDITION(CheckPointer(*hobj.m_ppObject)); } CONTRACTL_END; BEGIN_QCALL; SyncBlock * pSyncBlock = NULL; { GCX_COOP(); // set return to failure value retArrayGuids.Set(NULL); OBJECTREF orComObject = NULL; GCPROTECT_BEGIN(orComObject); orComObject = ObjectToOBJECTREF(*hobj.m_ppObject); // Validation: hobj represents a non-NULL System.__ComObject instance if(orComObject == NULL) COMPlusThrowArgumentNull(W("obj")); MethodTable* pMT = orComObject->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if(!pMT->IsComObjectType()) COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT); // while in cooperative mode, retrieve the object's sync block pSyncBlock = orComObject->PassiveGetSyncBlock(); GCPROTECT_END(); } // close the GCX_COOP scope InteropSyncBlockInfo * pInteropInfo; RCW * pRCW; SafeComHolderPreemp pInspectable; // Retrieve obj's IInspectable interface pointer if (pSyncBlock != NULL && (pInteropInfo = pSyncBlock->GetInteropInfoNoCreate()) != NULL && (pRCW = pInteropInfo->GetRawRCW()) != NULL && (pInspectable = pRCW->GetIInspectable()) != NULL) { // retrieve IIDs using IInspectable::GetIids() ULONG size = 0; CoTaskMemHolder rgIIDs(NULL); if (SUCCEEDED(pInspectable->GetIids(&size, &rgIIDs))) { retArrayGuids.SetGuidArray(rgIIDs, size); } } END_QCALL; } void QCALLTYPE MarshalNative::GetCachedWinRTTypes( QCall::ObjectHandleOnStack hadObj, int * pEpoch, QCall::ObjectHandleOnStack retArrayMT) { CONTRACTL { QCALL_CHECK; PRECONDITION(CheckPointer(*hadObj.m_ppObject, NULL_OK)); } CONTRACTL_END; BEGIN_QCALL; AppDomain * pDomain = GetAppDomain(); { GCX_COOP(); // set return to failure value retArrayMT.Set(NULL); OBJECTREF orDomain = NULL; GCPROTECT_BEGIN(orDomain); orDomain = ObjectToOBJECTREF(*hadObj.m_ppObject); // Validation: hadObj represents a non-NULL System.AppDomain instance if(orDomain != NULL) { MethodTable* pMT = orDomain->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if (!pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__APP_DOMAIN))) // TODO: find better resource string COMPlusThrow(kArgumentException, IDS_EE_ADUNLOAD_DEFAULT); pDomain = ((AppDomainBaseObject*)(OBJECTREFToObject(orDomain)))->GetDomain(); } GCPROTECT_END(); } if (pDomain != NULL) { SArray types; SArray guids; UINT e = *(UINT*)pEpoch; pDomain->GetCachedWinRTTypes(&types, &guids, e, (UINT*)pEpoch); retArrayMT.SetIntPtrArray((void**)(&types[0]), types.GetCount()); } END_QCALL; } void QCALLTYPE MarshalNative::GetCachedWinRTTypeByIID( QCall::ObjectHandleOnStack hadObj, GUID guid, void * * ppMT) { CONTRACTL { QCALL_CHECK; PRECONDITION(CheckPointer(*hadObj.m_ppObject, NULL_OK)); } CONTRACTL_END; BEGIN_QCALL; AppDomain * pDomain = GetAppDomain(); { GCX_COOP(); // set return to failure value *ppMT = NULL; OBJECTREF orDomain = NULL; GCPROTECT_BEGIN(orDomain); orDomain = ObjectToOBJECTREF(*hadObj.m_ppObject); // Validation: hadObj represents a non-NULL System.AppDomain instance if(orDomain != NULL) { MethodTable* pMT = orDomain->GetTrueMethodTable(); PREFIX_ASSUME(pMT != NULL); if (!pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__APP_DOMAIN))) // TODO: find better resource string COMPlusThrow(kArgumentException, IDS_EE_ADUNLOAD_DEFAULT); pDomain = ((AppDomainBaseObject*)(OBJECTREFToObject(orDomain)))->GetDomain(); } GCPROTECT_END(); } if (pDomain != NULL) { *ppMT = pDomain->LookupTypeByGuid(guid);; } END_QCALL; } //==================================================================== // Helper function used in the COM slot to method info mapping. //==================================================================== int MarshalNative::GetComSlotInfo(MethodTable *pMT, MethodTable **ppDefItfMT) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_ANY; PRECONDITION(CheckPointer(pMT)); PRECONDITION(CheckPointer(ppDefItfMT)); } CONTRACTL_END; *ppDefItfMT = NULL; // If a class was passed in then retrieve the default interface. if (!pMT->IsInterface()) { TypeHandle hndDefItfClass; DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass); if (DefItfType == DefaultInterfaceType_AutoDual || DefItfType == DefaultInterfaceType_Explicit) { pMT = hndDefItfClass.GetMethodTable(); PREFIX_ASSUME(pMT != NULL); } else { // The default interface does not have any user defined methods. return -1; } } // Set the default interface class. *ppDefItfMT = pMT; if (pMT->IsInterface()) { // Return the right number of slots depending on interface type. return ComMethodTable::GetNumExtraSlots(pMT->GetComInterfaceType()); } else { // We are dealing with an IClassX which are always IDispatch based. return ComMethodTable::GetNumExtraSlots(ifDispatch); } } BOOL MarshalNative::IsObjectInContext(OBJECTREF *pObj) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(pObj != NULL); } CONTRACTL_END; SyncBlock* pBlock = (*pObj)->GetSyncBlock(); InteropSyncBlockInfo* pInteropInfo = pBlock->GetInteropInfo(); ComCallWrapper* pCCW = pInteropInfo->GetCCW(); if((pCCW) || (!pInteropInfo->RCWWasUsed())) { // We are dealing with a CCW. Since CCW's are agile, they are always in the // correct context. return TRUE; } else { RCWHolder pRCW(GetThread()); pRCW.Init(pBlock); // We are dealing with an RCW, we need to check to see if the current // context is the one it was first seen in. LPVOID pCtxCookie = GetCurrentCtxCookie(); _ASSERTE(pCtxCookie != NULL); return pCtxCookie == pRCW->GetWrapperCtxCookie(); } } #endif // FEATURE_COMINTEROP