summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/src/System/RtType.cs199
-rw-r--r--src/vm/CMakeLists.txt2
-rw-r--r--src/vm/callsiteinspect.cpp516
-rw-r--r--src/vm/callsiteinspect.h45
-rw-r--r--src/vm/clrtocomcall.cpp316
-rw-r--r--src/vm/metasig.h1
-rw-r--r--src/vm/mlinfo.h1
-rw-r--r--src/vm/mscorlib.h37
-rw-r--r--src/vm/stdinterfaces.cpp21
-rw-r--r--src/vm/stdinterfaces.h8
10 files changed, 1088 insertions, 58 deletions
diff --git a/src/System.Private.CoreLib/src/System/RtType.cs b/src/System.Private.CoreLib/src/System/RtType.cs
index 0e5cf8104e..1612be8ba3 100644
--- a/src/System.Private.CoreLib/src/System/RtType.cs
+++ b/src/System.Private.CoreLib/src/System/RtType.cs
@@ -3966,8 +3966,6 @@ namespace System
return members;
}
-#if FEATURE_COMINTEROP
-#endif
[DebuggerStepThroughAttribute]
[Diagnostics.DebuggerHidden]
public override object InvokeMember(
@@ -4009,7 +4007,6 @@ namespace System
}
#endregion
- #region COM Interop
#if FEATURE_COMINTEROP && FEATURE_USE_LCID
if (target != null && target.GetType().IsCOMObject)
{
@@ -4048,7 +4045,6 @@ namespace System
}
}
#endif // FEATURE_COMINTEROP && FEATURE_USE_LCID
- #endregion
#region Check that any named parameters are not null
if (namedParams != null && Array.IndexOf(namedParams, null) != -1)
@@ -4883,8 +4879,199 @@ namespace System
#endregion
- #region COM
- #endregion
+#if FEATURE_COMINTEROP
+ private Object ForwardCallToInvokeMember(
+ String memberName,
+ BindingFlags flags,
+ Object target,
+ Object[] aArgs, // in/out - only byref values are in a valid state upon return
+ bool[] aArgsIsByRef,
+ int[] aArgsWrapperTypes, // _maybe_null_
+ Type[] aArgsTypes,
+ Type retType)
+ {
+ Debug.Assert(
+ aArgs.Length == aArgsIsByRef.Length
+ && aArgs.Length == aArgsTypes.Length
+ && (aArgsWrapperTypes == null || aArgs.Length == aArgsWrapperTypes.Length), "Input arrays should all be of the same length");
+
+ int cArgs = aArgs.Length;
+
+ // Handle arguments that are passed as ByRef and those
+ // arguments that need to be wrapped.
+ ParameterModifier[] aParamMod = null;
+ if (cArgs > 0)
+ {
+ ParameterModifier paramMod = new ParameterModifier(cArgs);
+ for (int i = 0; i < cArgs; i++)
+ {
+ paramMod[i] = aArgsIsByRef[i];
+ }
+
+ aParamMod = new ParameterModifier[] { paramMod };
+ if (aArgsWrapperTypes != null)
+ {
+ WrapArgsForInvokeCall(aArgs, aArgsWrapperTypes);
+ }
+ }
+
+ // For target invocation exceptions, the exception is wrapped.
+ flags |= BindingFlags.DoNotWrapExceptions;
+ Object ret = InvokeMember(memberName, flags, null, target, aArgs, aParamMod, null, null);
+
+ // Convert each ByRef argument that is _not_ of the proper type to
+ // the parameter type.
+ for (int i = 0; i < cArgs; i++)
+ {
+ // Determine if the parameter is ByRef.
+ if (aParamMod[0][i] && aArgs[i] != null)
+ {
+ Type argType = aArgsTypes[i];
+ if (!Object.ReferenceEquals(argType, aArgs[i].GetType()))
+ {
+ aArgs[i] = ForwardCallBinder.ChangeType(aArgs[i], argType, null);
+ }
+ }
+ }
+
+ // If the return type is _not_ of the proper type, then convert it.
+ if (ret != null)
+ {
+ if (!Object.ReferenceEquals(retType, ret.GetType()))
+ {
+ ret = ForwardCallBinder.ChangeType(ret, retType, null);
+ }
+ }
+
+ return ret;
+ }
+
+ private void WrapArgsForInvokeCall(Object[] aArgs, int[] aArgsWrapperTypes)
+ {
+ int cArgs = aArgs.Length;
+ for (int i = 0; i < cArgs; i++)
+ {
+ if (aArgsWrapperTypes[i] == 0)
+ {
+ continue;
+ }
+
+ if (((DispatchWrapperType)aArgsWrapperTypes[i]).HasFlag(DispatchWrapperType.SafeArray))
+ {
+ Type wrapperType = null;
+ bool isString = false;
+
+ // Determine the type of wrapper to use.
+ switch ((DispatchWrapperType)aArgsWrapperTypes[i] & ~DispatchWrapperType.SafeArray)
+ {
+ case DispatchWrapperType.Unknown:
+ wrapperType = typeof(UnknownWrapper);
+ break;
+ case DispatchWrapperType.Dispatch:
+ wrapperType = typeof(DispatchWrapper);
+ break;
+ case DispatchWrapperType.Error:
+ wrapperType = typeof(ErrorWrapper);
+ break;
+ case DispatchWrapperType.Currency:
+ wrapperType = typeof(CurrencyWrapper);
+ break;
+ case DispatchWrapperType.BStr:
+ wrapperType = typeof(BStrWrapper);
+ isString = true;
+ break;
+ default:
+ Debug.Assert(false, "[RuntimeType.WrapArgsForInvokeCall]Invalid safe array wrapper type specified.");
+ break;
+ }
+
+ // Allocate the new array of wrappers.
+ Array oldArray = (Array)aArgs[i];
+ int numElems = oldArray.Length;
+ Object[] newArray = (Object[])Array.UnsafeCreateInstance(wrapperType, numElems);
+
+ // Retrieve the ConstructorInfo for the wrapper type.
+ ConstructorInfo wrapperCons;
+ if (isString)
+ {
+ wrapperCons = wrapperType.GetConstructor(new Type[] {typeof(String)});
+ }
+ else
+ {
+ wrapperCons = wrapperType.GetConstructor(new Type[] {typeof(Object)});
+ }
+
+ // Wrap each of the elements of the array.
+ for (int currElem = 0; currElem < numElems; currElem++)
+ {
+ if(isString)
+ {
+ newArray[currElem] = wrapperCons.Invoke(new Object[] {(String)oldArray.GetValue(currElem)});
+ }
+ else
+ {
+ newArray[currElem] = wrapperCons.Invoke(new Object[] {oldArray.GetValue(currElem)});
+ }
+ }
+
+ // Update the argument.
+ aArgs[i] = newArray;
+ }
+ else
+ {
+ // Determine the wrapper to use and then wrap the argument.
+ switch ((DispatchWrapperType)aArgsWrapperTypes[i])
+ {
+ case DispatchWrapperType.Unknown:
+ aArgs[i] = new UnknownWrapper(aArgs[i]);
+ break;
+ case DispatchWrapperType.Dispatch:
+ aArgs[i] = new DispatchWrapper(aArgs[i]);
+ break;
+ case DispatchWrapperType.Error:
+ aArgs[i] = new ErrorWrapper(aArgs[i]);
+ break;
+ case DispatchWrapperType.Currency:
+ aArgs[i] = new CurrencyWrapper(aArgs[i]);
+ break;
+ case DispatchWrapperType.BStr:
+ aArgs[i] = new BStrWrapper((String)aArgs[i]);
+ break;
+ default:
+ Debug.Assert(false, "[RuntimeType.WrapArgsForInvokeCall]Invalid wrapper type specified.");
+ break;
+ }
+ }
+ }
+ }
+
+ private static OleAutBinder s_ForwardCallBinder;
+ private OleAutBinder ForwardCallBinder
+ {
+ get
+ {
+ // Synchronization is not required.
+ if (s_ForwardCallBinder == null)
+ s_ForwardCallBinder = new OleAutBinder();
+
+ return s_ForwardCallBinder;
+ }
+ }
+
+ [Flags]
+ private enum DispatchWrapperType : int
+ {
+ // This enum must stay in sync with the DispatchWrapperType enum defined in MLInfo.h
+ Unknown = 0x00000001,
+ Dispatch = 0x00000002,
+ // Record = 0x00000004,
+ Error = 0x00000008,
+ Currency = 0x00000010,
+ BStr = 0x00000020,
+ SafeArray = 0x00010000
+ }
+
+#endif // FEATURE_COMINTEROP
}
#region Library
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index 54c73cce44..842fe31f0a 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -286,6 +286,7 @@ set(VM_SOURCES_WKS
cachelinealloc.cpp
callcounter.cpp
callhelpers.cpp
+ callsiteinspect.cpp
ceemain.cpp
clrconfignative.cpp
clrex.cpp
@@ -402,6 +403,7 @@ set(VM_HEADERS_WKS
cachelinealloc.h
callcounter.h
callhelpers.h
+ callsiteinspect.h
ceemain.h
clrconfignative.h
clrex.h
diff --git a/src/vm/callsiteinspect.cpp b/src/vm/callsiteinspect.cpp
new file mode 100644
index 0000000000..953714d910
--- /dev/null
+++ b/src/vm/callsiteinspect.cpp
@@ -0,0 +1,516 @@
+// 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 "object.h"
+#include "callsiteinspect.h"
+
+namespace
+{
+ // Given a frame and value, get a reference to the object
+ OBJECTREF GetOBJECTREFFromStack(
+ _In_ FramedMethodFrame *frame,
+ _In_ PVOID val,
+ _In_ const CorElementType eType,
+ _In_ TypeHandle ty,
+ _In_ BOOL fIsByRef)
+ {
+ CONTRACT(OBJECTREF)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(frame));
+ PRECONDITION(CheckPointer(val));
+ }
+ CONTRACT_END;
+
+ // Value types like Nullable<T> have special unboxing semantics
+ if (eType == ELEMENT_TYPE_VALUETYPE)
+ {
+ // box the value class
+ _ASSERTE(ty.GetMethodTable()->IsValueType() || ty.GetMethodTable()->IsEnum());
+
+ MethodTable* pMT = ty.GetMethodTable();
+
+ // What happens when the type contains a stack pointer?
+ _ASSERTE(!pMT->IsByRefLike());
+
+ PVOID* pVal = (PVOID *)val;
+ if (!fIsByRef)
+ {
+ val = StackElemEndianessFixup(val, pMT->GetNumInstanceFieldBytes());
+ pVal = &val;
+ }
+
+ RETURN (pMT->FastBox(pVal));
+ }
+
+ switch (CorTypeInfo::GetGCType(eType))
+ {
+ case TYPE_GC_NONE:
+ {
+ if (ELEMENT_TYPE_PTR == eType)
+ COMPlusThrow(kNotSupportedException);
+
+ MethodTable *pMT = MscorlibBinder::GetElementType(eType);
+
+ OBJECTREF pObj = pMT->Allocate();
+ if (fIsByRef)
+ {
+ val = *((PVOID *)val);
+ }
+ else
+ {
+ val = StackElemEndianessFixup(val, CorTypeInfo::Size(eType));
+ }
+
+ void *pDest = pObj->UnBox();
+
+#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
+ if (!fIsByRef
+ && (ELEMENT_TYPE_R4 == eType || ELEMENT_TYPE_R8 == eType)
+ && frame != nullptr
+ && !TransitionBlock::IsStackArgumentOffset(static_cast<int>((TADDR) val - frame->GetTransitionBlock())))
+ {
+ if (ELEMENT_TYPE_R4 == eType)
+ *(UINT32*)pDest = (UINT32)FPSpillToR4(val);
+ else
+ *(UINT64*)pDest = (UINT64)FPSpillToR8(val);
+ }
+ else
+#endif // COM_STUBS_SEPARATE_FP_LOCATIONS
+ {
+ memcpyNoGCRefs(pDest, val, CorTypeInfo::Size(eType));
+ }
+
+ RETURN (pObj);
+ }
+
+ case TYPE_GC_REF:
+ if (fIsByRef)
+ val = *((PVOID *)val);
+ RETURN (ObjectToOBJECTREF(*(Object **)val));
+
+ default:
+ COMPlusThrow(kInvalidOperationException, W("InvalidOperation_TypeCannotBeBoxed"));
+ }
+ }
+
+ struct ArgDetails
+ {
+ int Offset;
+ BOOL IsByRef;
+ CorElementType ElementType;
+ TypeHandle Type;
+ };
+
+ ArgDetails GetArgDetails(
+ _In_ FramedMethodFrame *frame,
+ _In_ ArgIterator &pArgIter)
+ {
+ CONTRACT(ArgDetails)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(frame));
+ }
+ CONTRACT_END;
+
+ ArgDetails details{};
+ details.Offset = pArgIter.GetNextOffset();
+ details.ElementType = pArgIter.GetArgType();
+
+#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
+ // BUGBUG do we need to handle this?
+ if ((ELEMENT_TYPE_R4 == details.ElementType || ELEMENT_TYPE_R8 == details.ElementType)
+ && TransitionBlock::IsArgumentRegisterOffset(details.Offset))
+ {
+ int iFPArg = TransitionBlock::GetArgumentIndexFromOffset(details.Offset);
+ details.Offset = static_cast<int>(frame->GetFPArgOffset(iFPArg));
+ }
+#endif // COM_STUBS_SEPARATE_FP_LOCATIONS
+
+ // Get the TypeHandle for the argument's type.
+ MetaSig *pSig = pArgIter.GetSig();
+ details.Type = pSig->GetLastTypeHandleThrowing();
+
+ if (details.ElementType == ELEMENT_TYPE_BYREF)
+ {
+ details.IsByRef = TRUE;
+ // If this is a by-ref arg, GetOBJECTREFFromStack() will dereference "addr" to
+ // get the real argument address. Dereferencing now will open a gc hole if "addr"
+ // points into the gc heap, and we trigger gc between here and the point where
+ // we return the arguments.
+
+ TypeHandle tycopy;
+ details.ElementType = pSig->GetByRefType(&tycopy);
+ if (details.ElementType == ELEMENT_TYPE_VALUETYPE)
+ details.Type = tycopy;
+ }
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ else if (details.ElementType == ELEMENT_TYPE_VALUETYPE)
+ {
+ details.IsByRef = ArgIterator::IsArgPassedByRef(details.Type);
+ }
+#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
+
+ RETURN (details);
+ }
+
+ INT64 CopyOBJECTREFToStack(
+ _In_ OBJECTREF *src,
+ _In_opt_ PVOID pvDest,
+ _In_ CorElementType typ,
+ _In_ TypeHandle ty,
+ _In_ MetaSig *pSig,
+ _In_ BOOL fCopyClassContents)
+ {
+ // Use local to ensure proper alignment
+ INT64 ret = 0;
+
+ CONTRACT(INT64)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pvDest, NULL_OK));
+ PRECONDITION(CheckPointer(pSig));
+ PRECONDITION(typ != ELEMENT_TYPE_VOID);
+ }
+ CONTRACT_END;
+
+ if (fCopyClassContents)
+ {
+ // We have to copy the contents of a value class to pvDest
+
+ // write unboxed version back to memory provided by the caller
+ if (pvDest)
+ {
+ if (ty.IsNull())
+ ty = pSig->GetRetTypeHandleThrowing();
+
+ _ASSERTE((*src) != NULL || Nullable::IsNullableType(ty));
+#ifdef PLATFORM_UNIX
+ // Unboxing on non-Windows ABIs must be special cased
+ COMPlusThrowHR(COR_E_NOTSUPPORTED);
+#else
+ ty.GetMethodTable()->UnBoxIntoUnchecked(pvDest, (*src));
+#endif
+
+ // return the object so it can be stored in the frame and
+ // propagated to the root set
+ *(OBJECTREF*)&ret = (*src);
+ }
+ }
+ else if (CorTypeInfo::IsObjRef(typ))
+ {
+ // We have a real OBJECTREF
+
+ // Check if it is an OBJECTREF (from the GC heap)
+ if (pvDest)
+ SetObjectReferenceUnchecked((OBJECTREF *)pvDest, *src);
+
+ *(OBJECTREF*)&ret = (*src);
+ }
+ else
+ {
+ // We have something that does not have a return buffer associated.
+
+ // Note: this assert includes ELEMENT_TYPE_VALUETYPE because for enums,
+ // ArgIterator::HasRetBuffArg() returns 'false'. This occurs because the
+ // normalized type for enums is ELEMENT_TYPE_I4 even though
+ // MetaSig::GetReturnType() returns ELEMENT_TYPE_VALUETYPE.
+ // Almost all ELEMENT_TYPE_VALUETYPEs will go through the copy class
+ // contents codepath above.
+ // Also, CorTypeInfo::IsPrimitiveType() does not check for IntPtr, UIntPtr
+ // hence we have ELEMENT_TYPE_I and ELEMENT_TYPE_U.
+ _ASSERTE(
+ CorTypeInfo::IsPrimitiveType(typ)
+ || (typ == ELEMENT_TYPE_VALUETYPE)
+ || (typ == ELEMENT_TYPE_I)
+ || (typ == ELEMENT_TYPE_U)
+ || (typ == ELEMENT_TYPE_FNPTR));
+
+ // For a "ref int" arg, if a nasty sink replaces the boxed int with
+ // a null OBJECTREF, this is where we check. We need to be uniform
+ // in our policy w.r.t. this (throw vs ignore).
+ // The branch above throws.
+ if ((*src) != NULL)
+ {
+ PVOID srcData = (*src)->GetData();
+ int cbsize = gElementTypeInfo[typ].m_cbSize;
+ decltype(ret) retBuff;
+
+ // ElementTypeInfo.m_cbSize can be less than zero for cases that need
+ // special handling (e.g. value types) to be sure of the size (see siginfo.cpp).
+ // The type handle has the actual byte count, so we look there for such cases.
+ if (cbsize < 0)
+ {
+ if (ty.IsNull())
+ ty = pSig->GetRetTypeHandleThrowing();
+
+ _ASSERTE(!ty.IsNull());
+ cbsize = ty.GetSize();
+
+ // Assert the value class fits in the buffer
+ _ASSERTE(cbsize <= (int) sizeof(retBuff));
+
+ // Unbox value into a local buffer, this covers the Nullable<T> case.
+ ty.GetMethodTable()->UnBoxIntoUnchecked(&retBuff, *src);
+
+ srcData = &retBuff;
+ }
+
+ if (pvDest)
+ memcpyNoGCRefs(pvDest, srcData, cbsize);
+
+ // need to sign-extend signed types
+ bool fEndianessFixup = false;
+ switch (typ)
+ {
+ case ELEMENT_TYPE_I1:
+ ret = *(INT8*)srcData;
+ fEndianessFixup = true;
+ break;
+ case ELEMENT_TYPE_I2:
+ ret = *(INT16*)srcData;
+ fEndianessFixup = true;
+ break;
+ case ELEMENT_TYPE_I4:
+ ret = *(INT32*)srcData;
+ fEndianessFixup = true;
+ break;
+ default:
+ memcpyNoGCRefs(StackElemEndianessFixup(&ret, cbsize), srcData, cbsize);
+ break;
+ }
+
+#if !defined(_WIN64) && BIGENDIAN
+ if (fEndianessFixup)
+ ret <<= 32;
+#endif
+ }
+ }
+
+ RETURN (ret);
+ }
+}
+
+void CallsiteInspect::GetCallsiteArgs(
+ _In_ CallsiteDetails &callsite,
+ _Outptr_ PTRARRAYREF *args,
+ _Outptr_ BOOLARRAYREF *argsIsByRef,
+ _Outptr_ PTRARRAYREF *argsTypes)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(args));
+ PRECONDITION(CheckPointer(argsIsByRef));
+ PRECONDITION(CheckPointer(argsTypes));
+ }
+ CONTRACTL_END;
+
+ struct _gc
+ {
+ PTRARRAYREF Args;
+ PTRARRAYREF ArgsTypes;
+ BOOLARRAYREF ArgsIsByRef;
+ OBJECTREF CurrArgType;
+ OBJECTREF CurrArg;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+ GCPROTECT_BEGIN(gc);
+ {
+ // Ensure the sig is in a known state
+ callsite.MetaSig.Reset();
+
+ // scan the sig for the argument count
+ INT32 numArgs = callsite.MetaSig.NumFixedArgs();
+ if (callsite.IsDelegate)
+ numArgs -= 2; // Delegates have 2 implicit additional arguments
+
+ // Allocate all needed arrays for callsite arg details
+ gc.Args = (PTRARRAYREF)AllocateObjectArray(numArgs, g_pObjectClass);
+ MethodTable *typeMT = MscorlibBinder::GetClass(CLASS__TYPE);
+ gc.ArgsTypes = (PTRARRAYREF)AllocateObjectArray(numArgs, typeMT);
+ gc.ArgsIsByRef = (BOOLARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_BOOLEAN, numArgs);
+
+ ArgIterator iter{ &callsite.MetaSig };
+ for (int index = 0; index < numArgs; index++)
+ {
+ ArgDetails details = GetArgDetails(callsite.Frame, iter);
+ PVOID addr = (LPBYTE)callsite.Frame->GetTransitionBlock() + details.Offset;
+
+ // How do we handle pointer types?
+ _ASSERTE(details.ElementType != ELEMENT_TYPE_PTR);
+
+ gc.CurrArg = GetOBJECTREFFromStack(
+ callsite.Frame,
+ addr,
+ details.ElementType,
+ details.Type,
+ details.IsByRef);
+
+ // Store argument
+ gc.Args->SetAt(index, gc.CurrArg);
+
+ // Record the argument's type
+ gc.CurrArgType = details.Type.GetManagedClassObject();
+ _ASSERTE(gc.CurrArgType != NULL);
+ gc.ArgsTypes->SetAt(index, gc.CurrArgType);
+
+ // Record if the argument is ByRef
+ *((UCHAR*)gc.ArgsIsByRef->GetDataPtr() + index) = (!!details.IsByRef);
+ }
+ }
+ GCPROTECT_END();
+
+ // Return details
+ *args = gc.Args;
+ *argsTypes = gc.ArgsTypes;
+ *argsIsByRef = gc.ArgsIsByRef;
+}
+
+void CallsiteInspect::PropagateOutParametersBackToCallsite(
+ _In_ PTRARRAYREF outArgs,
+ _In_ OBJECTREF retVal,
+ _In_ CallsiteDetails &callsite)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ struct _gc
+ {
+ OBJECTREF RetVal;
+ PTRARRAYREF OutArgs;
+ OBJECTREF CurrArg;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+ gc.OutArgs = outArgs;
+ gc.RetVal = retVal;
+ GCPROTECT_BEGIN(gc);
+ {
+ FramedMethodFrame *frame = callsite.Frame;
+ const INT32 flags = callsite.Flags;
+ MetaSig *pSig = &callsite.MetaSig;
+ pSig->Reset(); // Ensure the sig is in a known state
+
+ // Construct an ArgIterator from the sig
+ ArgIterator argit{ pSig };
+
+ // Propagate the return value only if the call is not a constructor call
+ // and the return type is non-void
+ if ((flags & CallsiteDetails::Ctor) == 0
+ && pSig->GetReturnType() != ELEMENT_TYPE_VOID)
+ {
+ if (argit.HasRetBuffArg())
+ {
+ // Copy from RetVal into the retBuff.
+ INT64 retVal = CopyOBJECTREFToStack(
+ &gc.RetVal,
+ *(void**)(frame->GetTransitionBlock() + argit.GetRetBuffArgOffset()),
+ pSig->GetReturnType(),
+ TypeHandle{},
+ pSig,
+ TRUE /* should copy */);
+
+ // Copy the return value
+ *(ARG_SLOT *)(frame->GetReturnValuePtr()) = retVal;
+ }
+#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
+ else if (argit.HasNonStandardByvalReturn())
+ {
+ // In these cases, put the pointer to the return buffer into
+ // the frame's return value slot.
+ CopyOBJECTREFToStack(
+ &gc.RetVal,
+ frame->GetReturnValuePtr(),
+ pSig->GetReturnType(),
+ TypeHandle(),
+ pSig,
+ TRUE /* should copy */);
+ }
+#endif // ENREGISTERED_RETURNTYPE_MAXSIZE
+ else
+ {
+ // There is no separate return buffer,
+ // the retVal should fit in an INT64.
+ INT64 retVal = CopyOBJECTREFToStack(
+ &gc.RetVal,
+ nullptr,
+ pSig->GetReturnType(),
+ TypeHandle{},
+ pSig,
+ FALSE /* should copy */);
+
+ // Copy the return value
+ *(ARG_SLOT *)(frame->GetReturnValuePtr()) = retVal;
+ }
+ }
+
+ // Refetch all the variables as GC could have happened
+ // after copying the return value.
+ UINT32 cOutArgs = (gc.OutArgs != NULL) ? gc.OutArgs->GetNumComponents() : 0;
+ if (cOutArgs > 0)
+ {
+ MetaSig syncSig{ callsite.MethodDesc };
+ MetaSig *pSyncSig = nullptr;
+
+ if (flags & CallsiteDetails::EndInvoke)
+ pSyncSig = &syncSig;
+
+ PVOID *argAddr;
+ for (UINT32 i = 0; i < cOutArgs; ++i)
+ {
+ // Determine the address of the argument
+ if (pSyncSig)
+ {
+ CorElementType typ = pSyncSig->NextArg();
+ if (typ == ELEMENT_TYPE_END)
+ break;
+
+ if (typ != ELEMENT_TYPE_BYREF)
+ continue;
+
+ argAddr = reinterpret_cast<PVOID *>(frame->GetTransitionBlock() + argit.GetNextOffset());
+ }
+ else
+ {
+ int ofs = argit.GetNextOffset();
+ if (ofs == TransitionBlock::InvalidOffset)
+ break;
+
+ if (argit.GetArgType() != ELEMENT_TYPE_BYREF)
+ continue;
+
+ argAddr = reinterpret_cast<PVOID *>(frame->GetTransitionBlock() + ofs);
+ }
+
+ TypeHandle ty;
+ CorElementType brType = pSig->GetByRefType(&ty);
+
+ gc.CurrArg = gc.OutArgs->GetAt(i);
+ CopyOBJECTREFToStack(
+ &gc.CurrArg,
+ *argAddr,
+ brType,
+ ty,
+ pSig,
+ ty.IsNull() ? FALSE : ty.IsValueType());
+ }
+ }
+ }
+ GCPROTECT_END();
+}
diff --git a/src/vm/callsiteinspect.h b/src/vm/callsiteinspect.h
new file mode 100644
index 0000000000..8a2d7cca49
--- /dev/null
+++ b/src/vm/callsiteinspect.h
@@ -0,0 +1,45 @@
+// 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.
+
+struct CallsiteDetails
+{
+ // The signature of the current call
+ MetaSig MetaSig;
+
+ // The current call frame
+ FramedMethodFrame *Frame;
+
+ // The relevant method for the callsite
+ MethodDesc *MethodDesc;
+
+ // Is the callsite for a delegate
+ // Note the relevant method may _not_ be a delegate
+ BOOL IsDelegate;
+
+ // Flags for callsite
+ enum
+ {
+ None = 0x0,
+ BeginInvoke = 0x01,
+ EndInvoke = 0x02,
+ Ctor = 0x04,
+ };
+ INT32 Flags;
+};
+
+namespace CallsiteInspect
+{
+ // Get all arguments and associated argument details at the supplied callsite
+ void GetCallsiteArgs(
+ _In_ CallsiteDetails &callsite,
+ _Outptr_ PTRARRAYREF *args,
+ _Outptr_ BOOLARRAYREF *argsIsByRef,
+ _Outptr_ PTRARRAYREF *argsTypes);
+
+ // Properly propagate out parameters
+ void PropagateOutParametersBackToCallsite(
+ _In_ PTRARRAYREF outParams,
+ _In_ OBJECTREF retVal,
+ _In_ CallsiteDetails &callsite);
+}
diff --git a/src/vm/clrtocomcall.cpp b/src/vm/clrtocomcall.cpp
index 372cf6f30a..e56c4b4159 100644
--- a/src/vm/clrtocomcall.cpp
+++ b/src/vm/clrtocomcall.cpp
@@ -16,6 +16,7 @@
#include "excep.h"
#include "clrtocomcall.h"
#include "siginfo.hpp"
+#include "comdelegate.h"
#include "comcallablewrapper.h"
#include "runtimecallablewrapper.h"
#include "dllimport.h"
@@ -25,6 +26,7 @@
#include "reflectioninvocation.h"
#include "mdaassistants.h"
#include "sigbuilder.h"
+#include "callsiteinspect.h"
#define DISPATCH_INVOKE_SLOT 6
@@ -629,6 +631,314 @@ UINT32 CLRToCOMEventCallWorker(ComPlusMethodFrame* pFrame, ComPlusCallMethodDesc
return 0;
}
+CallsiteDetails CreateCallsiteDetails(_In_ FramedMethodFrame *pFrame)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pFrame));
+ }
+ CONTRACTL_END;
+
+ MethodDesc *pMD = pFrame->GetFunction();
+ _ASSERTE(!pMD->ContainsGenericVariables() && pMD->IsRuntimeMethodHandle());
+
+ const BOOL fIsDelegate = pMD->GetMethodTable()->IsDelegate();
+ _ASSERTE(!fIsDelegate && pMD->IsRuntimeMethodHandle());
+
+ MethodDesc *pDelegateMD = nullptr;
+ INT32 callsiteFlags = CallsiteDetails::None;
+ if (fIsDelegate)
+ {
+ // Gather details on the delegate itself
+ DelegateEEClass* delegateCls = (DelegateEEClass*)pMD->GetMethodTable()->GetClass();
+ _ASSERTE(pFrame->GetThis()->GetMethodTable()->IsDelegate());
+
+ if (pMD == delegateCls->m_pBeginInvokeMethod.GetValue())
+ {
+ callsiteFlags |= CallsiteDetails::BeginInvoke;
+ }
+ else
+ {
+ _ASSERTE(pMD == delegateCls->m_pEndInvokeMethod.GetValue());
+ callsiteFlags |= CallsiteDetails::EndInvoke;
+ }
+
+ pDelegateMD = pMD;
+
+ // Get at the underlying method desc for this frame
+ pMD = COMDelegate::GetMethodDesc(pFrame->GetThis());
+ _ASSERTE(pDelegateMD != nullptr
+ && pMD != nullptr
+ && !pMD->ContainsGenericVariables()
+ && pMD->IsRuntimeMethodHandle());
+ }
+
+ if (pMD->IsCtor())
+ callsiteFlags |= CallsiteDetails::Ctor;
+
+ Signature signature;
+ Module *pModule;
+ SigTypeContext typeContext;
+
+ if (fIsDelegate)
+ {
+ _ASSERTE(pDelegateMD != nullptr);
+ signature = pDelegateMD->GetSignature();
+ pModule = pDelegateMD->GetModule();
+
+ // If the delegate is generic, pDelegateMD may not represent the exact instantiation so we recover it from 'this'.
+ SigTypeContext::InitTypeContext(pFrame->GetThis()->GetMethodTable()->GetInstantiation(), Instantiation{}, &typeContext);
+ }
+ else if (pMD->IsVarArg())
+ {
+ VASigCookie *pVACookie = pFrame->GetVASigCookie();
+ signature = pVACookie->signature;
+ pModule = pVACookie->pModule;
+ SigTypeContext::InitTypeContext(&typeContext);
+ }
+ else
+ {
+ // COM doesn't support generics so the type is obvious
+ TypeHandle actualType = TypeHandle{ pMD->GetMethodTable() };
+
+ signature = pMD->GetSignature();
+ pModule = pMD->GetModule();
+ SigTypeContext::InitTypeContext(pMD, actualType, &typeContext);
+ }
+
+ _ASSERTE(!signature.IsEmpty() && pModule != nullptr);
+
+ // Create details
+ return CallsiteDetails{ { signature, pModule, &typeContext }, pFrame, pMD, fIsDelegate };
+}
+
+UINT32 CLRToCOMLateBoundWorker(
+ _In_ ComPlusMethodFrame *pFrame,
+ _In_ ComPlusCallMethodDesc *pMD)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pFrame));
+ PRECONDITION(CheckPointer(pMD));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr;
+
+ LOG((LF_STUBS, LL_INFO1000, "Calling CLRToCOMLateBoundWorker %s::%s \n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
+
+ // Retrieve the method table and the method desc of the call.
+ MethodTable *pItfMT = pMD->GetInterfaceMethodTable();
+ ComPlusCallMethodDesc *pItfMD = pMD;
+
+ // Make sure this is only called on IDispatch only interfaces.
+ _ASSERTE(pItfMT->GetComInterfaceType() == ifDispatch);
+
+ // If this is a method impl MD then we need to retrieve the actual interface MD that
+ // this is a method impl for.
+ // REVISIT_TODO: Stop using ComSlot to convert method impls to interface MD
+ // _ASSERTE(pMD->m_pComPlusCallInfo->m_cachedComSlot == 7);
+ if (!pMD->GetMethodTable()->IsInterface())
+ {
+ const unsigned cbExtraSlots = 7;
+ pItfMD = (ComPlusCallMethodDesc*)pItfMT->GetMethodDescForSlot(pMD->m_pComPlusCallInfo->m_cachedComSlot - cbExtraSlots);
+ CONSISTENCY_CHECK(pMD->GetInterfaceMD() == pItfMD);
+ }
+
+ // Token of member to call
+ mdToken tkMember;
+ DWORD binderFlags = BINDER_AllLookup;
+
+ // Property details
+ mdProperty propToken;
+ LPCUTF8 strMemberName;
+ ULONG uSemantic;
+
+ // See if there is property information for this member.
+ hr = pItfMT->GetModule()->GetPropertyInfoForMethodDef(pItfMD->GetMemberDef(), &propToken, &strMemberName, &uSemantic);
+ if (hr != S_OK)
+ {
+ // Non-property method
+ strMemberName = pItfMD->GetName();
+ tkMember = pItfMD->GetMemberDef();
+ binderFlags |= BINDER_InvokeMethod;
+ }
+ else
+ {
+ // Property accessor
+ tkMember = propToken;
+
+ // Determine which type of accessor we are dealing with.
+ switch (uSemantic)
+ {
+ case msGetter:
+ {
+ // INVOKE_PROPERTYGET
+ binderFlags |= BINDER_GetProperty;
+ break;
+ }
+
+ case msSetter:
+ {
+ // INVOKE_PROPERTYPUT or INVOKE_PROPERTYPUTREF
+ ULONG cAssoc;
+ ASSOCIATE_RECORD* pAssoc;
+
+ IMDInternalImport *pMDImport = pItfMT->GetMDImport();
+
+ // Retrieve all the associates.
+ HENUMInternalHolder henum{ pMDImport };
+ henum.EnumAssociateInit(propToken);
+
+ cAssoc = henum.EnumGetCount();
+ _ASSERTE(cAssoc > 0);
+
+ ULONG allocSize = cAssoc * sizeof(*pAssoc);
+ if (allocSize < cAssoc)
+ COMPlusThrowHR(COR_E_OVERFLOW);
+
+ pAssoc = (ASSOCIATE_RECORD*)_alloca((size_t)allocSize);
+ IfFailThrow(pMDImport->GetAllAssociates(&henum, pAssoc, cAssoc));
+
+ // Check to see if there is both a set and an other. If this is the case
+ // then the setter is a INVOKE_PROPERTYPUTREF otherwise we will make it a
+ // INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF.
+ bool propHasOther = false;
+ for (ULONG i = 0; i < cAssoc; i++)
+ {
+ if (pAssoc[i].m_dwSemantics == msOther)
+ {
+ propHasOther = true;
+ break;
+ }
+ }
+
+ if (propHasOther)
+ {
+ // There is both a INVOKE_PROPERTYPUT and a INVOKE_PROPERTYPUTREF for this
+ // property. Therefore be specific and make this invoke a INVOKE_PROPERTYPUTREF.
+ binderFlags |= BINDER_PutRefDispProperty;
+ }
+ else
+ {
+ // Only a setter so make the invoke a set which maps to
+ // INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF.
+ binderFlags = BINDER_SetProperty;
+ }
+ break;
+ }
+
+ case msOther:
+ {
+ // INVOKE_PROPERTYPUT
+ binderFlags |= BINDER_PutDispProperty;
+ break;
+ }
+
+ default:
+ {
+ _ASSERTE(!"Invalid method semantic!");
+ }
+ }
+ }
+
+ // If the method has a void return type, then set the IgnoreReturn binding flag.
+ if (pItfMD->IsVoid())
+ binderFlags |= BINDER_IgnoreReturn;
+
+ UINT32 fpRetSize = 0;
+
+ struct
+ {
+ OBJECTREF MemberName;
+ OBJECTREF ItfTypeObj;
+ PTRARRAYREF Args;
+ BOOLARRAYREF ArgsIsByRef;
+ PTRARRAYREF ArgsTypes;
+ OBJECTREF ArgsWrapperTypes;
+ OBJECTREF RetValType;
+ OBJECTREF RetVal;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+ GCPROTECT_BEGIN(gc);
+ {
+ // Retrieve the exposed type object for the interface.
+ gc.ItfTypeObj = pItfMT->GetManagedClassObject();
+
+ // Retrieve the name of the target member. If the member
+ // has a DISPID then use that to optimize the invoke.
+ DISPID dispId = DISPID_UNKNOWN;
+ hr = pItfMD->GetMDImport()->GetDispIdOfMemberDef(tkMember, (ULONG*)&dispId);
+ if (hr == S_OK)
+ {
+ WCHAR strTmp[ARRAYSIZE(DISPID_NAME_FORMAT_STRING W("4294967295"))];
+ _snwprintf_s(strTmp, COUNTOF(strTmp), _TRUNCATE, DISPID_NAME_FORMAT_STRING, dispId);
+ gc.MemberName = StringObject::NewString(strTmp);
+ }
+ else
+ {
+ gc.MemberName = StringObject::NewString(strMemberName);
+ }
+
+ CallsiteDetails callsite = CreateCallsiteDetails(pFrame);
+
+ // Arguments
+ CallsiteInspect::GetCallsiteArgs(callsite, &gc.Args, &gc.ArgsIsByRef, &gc.ArgsTypes);
+
+ // If call requires object wrapping, set up the array of wrapper types.
+ if (pMD->RequiresArgumentWrapping())
+ gc.ArgsWrapperTypes = SetUpWrapperInfo(pItfMD);
+
+ // Return type
+ TypeHandle retValHandle = callsite.MetaSig.GetRetTypeHandleThrowing();
+ gc.RetValType = retValHandle.GetManagedClassObject();
+
+ // the return value is written into the Frame's neginfo, so we don't
+ // need to return it directly. We can just have the stub do that work.
+ // However, the stub needs to know what type of FP return this is, if
+ // any, so we return the return size info as the return value.
+ if (callsite.MetaSig.HasFPReturn())
+ {
+ callsite.MetaSig.Reset();
+ ArgIterator argit{ &callsite.MetaSig };
+ fpRetSize = argit.GetFPReturnSize();
+ _ASSERTE(fpRetSize > 0);
+ }
+
+ // Create a call site for the invoke
+ MethodDescCallSite forwardCallToInvoke(METHOD__CLASS__FORWARD_CALL_TO_INVOKE, &gc.ItfTypeObj);
+
+ // Prepare the arguments that will be passed to the method.
+ ARG_SLOT invokeArgs[] =
+ {
+ ObjToArgSlot(gc.ItfTypeObj),
+ ObjToArgSlot(gc.MemberName),
+ (ARG_SLOT)binderFlags,
+ ObjToArgSlot(pFrame->GetThis()),
+ ObjToArgSlot(gc.Args),
+ ObjToArgSlot(gc.ArgsIsByRef),
+ ObjToArgSlot(gc.ArgsWrapperTypes),
+ ObjToArgSlot(gc.ArgsTypes),
+ ObjToArgSlot(gc.RetValType)
+ };
+
+ // Invoke the method
+ gc.RetVal = forwardCallToInvoke.CallWithValueTypes_RetOBJECTREF(invokeArgs);
+
+ // Ensure all outs and return values are moved back to the current callsite
+ CallsiteInspect::PropagateOutParametersBackToCallsite(gc.Args, gc.RetVal, callsite);
+ }
+ GCPROTECT_END();
+
+ return fpRetSize;
+}
// calls that propagate from CLR to COM
@@ -681,6 +991,12 @@ UINT32 STDCALL CLRToCOMWorker(TransitionBlock * pTransitionBlock, ComPlusCallMet
{
returnValue = CLRToCOMEventCallWorker(pFrame, pMD);
}
+ else if (pItfMT->GetComInterfaceType() == ifDispatch)
+ {
+ // If the interface is a Dispatch only interface then convert the early bound
+ // call to a late bound call.
+ returnValue = CLRToCOMLateBoundWorker(pFrame, pMD);
+ }
else
{
LOG((LF_STUBS, LL_INFO1000, "Calling CLRToCOMWorker %s::%s \n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
diff --git a/src/vm/metasig.h b/src/vm/metasig.h
index b3a4139a7c..e826526976 100644
--- a/src/vm/metasig.h
+++ b/src/vm/metasig.h
@@ -455,6 +455,7 @@ DEFINE_METASIG(IM(IntPtr_UInt_IntPtr_IntPtr_RetVoid, I K I I, v))
DEFINE_METASIG(IM(Obj_Bool_RetVoid, j F, v))
#ifdef FEATURE_COMINTEROP
DEFINE_METASIG(SM(Obj_RetStr, j, s))
+DEFINE_METASIG_T(IM(Str_BindingFlags_Obj_ArrObj_ArrBool_ArrInt_ArrType_Type_RetObj, s g(BINDING_FLAGS) j a(j) a(F) a(i) a(C(TYPE)) C(TYPE), j))
#endif // FEATURE_COMINTEROP
DEFINE_METASIG_T(IM(Obj_Obj_BindingFlags_Binder_CultureInfo_RetVoid, j j g(BINDING_FLAGS) C(BINDER) C(CULTURE_INFO), v))
DEFINE_METASIG_T(IM(Obj_Obj_BindingFlags_Binder_ArrObj_CultureInfo_RetVoid, j j g(BINDING_FLAGS) C(BINDER) a(j) C(CULTURE_INFO), v))
diff --git a/src/vm/mlinfo.h b/src/vm/mlinfo.h
index b27dcc01c3..b31e34f138 100644
--- a/src/vm/mlinfo.h
+++ b/src/vm/mlinfo.h
@@ -31,6 +31,7 @@ enum DispatchWrapperType
{
DispatchWrapperType_Unknown = 0x00000001,
DispatchWrapperType_Dispatch = 0x00000002,
+ //DispatchWrapperType_Record = 0x00000004,
DispatchWrapperType_Error = 0x00000008,
DispatchWrapperType_Currency = 0x00000010,
DispatchWrapperType_BStr = 0x00000020,
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index 2813fc6e04..ab00e94577 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -191,10 +191,6 @@ DEFINE_METHOD(BINDER, CHANGE_TYPE, ChangeType,
DEFINE_CLASS(BINDING_FLAGS, Reflection, BindingFlags)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(BSTR_WRAPPER, Interop, BStrWrapper)
-#endif // FEATURE_COMINTEROP
-
DEFINE_CLASS_U(System, RuntimeType, ReflectClassBaseObject)
DEFINE_FIELD_U(m_cache, ReflectClassBaseObject, m_cache)
DEFINE_FIELD_U(m_handle, ReflectClassBaseObject, m_typeHandle)
@@ -210,6 +206,19 @@ DEFINE_METHOD(CLASS, GET_FIELD_INFO, GetFieldInfo,
DEFINE_METHOD(CLASS, GET_PROPERTY_INFO, GetPropertyInfo, SM_RuntimeType_Int_RetPropertyInfo)
#ifdef FEATURE_COMINTEROP
+DEFINE_METHOD(CLASS, FORWARD_CALL_TO_INVOKE, ForwardCallToInvokeMember, IM_Str_BindingFlags_Obj_ArrObj_ArrBool_ArrInt_ArrType_Type_RetObj)
+#endif // FEATURE_COMINTEROP
+
+#ifdef FEATURE_COMINTEROP
+DEFINE_CLASS(BSTR_WRAPPER, Interop, BStrWrapper)
+DEFINE_CLASS(CURRENCY_WRAPPER, Interop, CurrencyWrapper)
+DEFINE_CLASS(DISPATCH_WRAPPER, Interop, DispatchWrapper)
+DEFINE_CLASS(ERROR_WRAPPER, Interop, ErrorWrapper)
+DEFINE_CLASS(UNKNOWN_WRAPPER, Interop, UnknownWrapper)
+DEFINE_CLASS(VARIANT_WRAPPER, Interop, VariantWrapper)
+#endif // FEATURE_COMINTEROP
+
+#ifdef FEATURE_COMINTEROP
DEFINE_CLASS_U(System, __ComObject, ComObject)
DEFINE_FIELD_U(m_ObjectToDataMap, ComObject, m_ObjectToDataMap)
DEFINE_CLASS(COM_OBJECT, System, __ComObject)
@@ -296,10 +305,6 @@ DEFINE_PROPERTY(CULTURE_INFO, PARENT, Parent,
DEFINE_CLASS(CURRENCY, System, Currency)
DEFINE_METHOD(CURRENCY, DECIMAL_CTOR, .ctor, IM_Dec_RetVoid)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(CURRENCY_WRAPPER, Interop, CurrencyWrapper)
-#endif
-
DEFINE_CLASS(DATE_TIME, System, DateTime)
DEFINE_METHOD(DATE_TIME, LONG_CTOR, .ctor, IM_Long_RetVoid)
@@ -322,10 +327,6 @@ DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux)
DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid)
DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(DISPATCH_WRAPPER, Interop, DispatchWrapper)
-#endif // FEATURE_COMINTEROP
-
DEFINE_CLASS(DYNAMICMETHOD, ReflectionEmit, DynamicMethod)
DEFINE_CLASS(DYNAMICRESOLVER, ReflectionEmit, DynamicResolver)
@@ -344,10 +345,6 @@ DEFINE_CLASS(ENVIRONMENT, System, Environment)
DEFINE_METHOD(ENVIRONMENT, GET_RESOURCE_STRING_LOCAL, GetResourceStringLocal, SM_Str_RetStr)
DEFINE_METHOD(ENVIRONMENT, SET_COMMAND_LINE_ARGS, SetCommandLineArgs, SM_ArrStr_RetVoid)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(ERROR_WRAPPER, Interop, ErrorWrapper)
-#endif
-
DEFINE_CLASS(EVENT, Reflection, RuntimeEventInfo)
DEFINE_CLASS(EVENT_ARGS, System, EventArgs)
@@ -960,18 +957,10 @@ DEFINE_CLASS(LAZY, System, Lazy`1)
DEFINE_CLASS(LAZY_INITIALIZER, Threading, LazyInitializer)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(UNKNOWN_WRAPPER, Interop, UnknownWrapper)
-#endif
-
DEFINE_CLASS(VALUE_TYPE, System, ValueType)
DEFINE_METHOD(VALUE_TYPE, GET_HASH_CODE, GetHashCode, IM_RetInt)
DEFINE_METHOD(VALUE_TYPE, EQUALS, Equals, IM_Obj_RetBool)
-#ifdef FEATURE_COMINTEROP
-DEFINE_CLASS(VARIANT_WRAPPER, Interop, VariantWrapper)
-#endif // FEATURE_COMINTEROP
-
DEFINE_CLASS(GC, System, GC)
DEFINE_METHOD(GC, KEEP_ALIVE, KeepAlive, SM_Obj_RetVoid)
DEFINE_METHOD(GC, COLLECT, Collect, SM_RetVoid)
diff --git a/src/vm/stdinterfaces.cpp b/src/vm/stdinterfaces.cpp
index 5726df9958..005748ce2d 100644
--- a/src/vm/stdinterfaces.cpp
+++ b/src/vm/stdinterfaces.cpp
@@ -583,25 +583,6 @@ ClassInfo_GetClassInfo(IUnknown* pUnk, ITypeInfo** ppTI)
return hr;
}
-//-------------------------------------------------------------------------------------
-// Helper to get the ITypeLib* for a Assembly.
-HRESULT GetITypeLibForAssembly(Assembly *pAssembly, ITypeLib **ppTLB, int bAutoCreate, int flags)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- PRECONDITION(CheckPointer(pAssembly));
- PRECONDITION(CheckPointer(ppTLB));
- }
- CONTRACTL_END;
-
- //@CORESYSTODO: what to do?
- return E_FAIL;
-} // HRESULT GetITypeLibForAssembly()
-
-
//------------------------------------------------------------------------------------------
// Helper to get the ITypeInfo* for a type.
HRESULT GetITypeLibForEEClass(MethodTable *pClass, ITypeLib **ppTLB, int bAutoCreate, int flags)
@@ -614,7 +595,7 @@ HRESULT GetITypeLibForEEClass(MethodTable *pClass, ITypeLib **ppTLB, int bAutoCr
}
CONTRACTL_END;
- return GetITypeLibForAssembly(pClass->GetAssembly(), ppTLB, bAutoCreate, flags);
+ return COR_E_NOTSUPPORTED;
} // HRESULT GetITypeLibForEEClass()
diff --git a/src/vm/stdinterfaces.h b/src/vm/stdinterfaces.h
index 57981fa868..3ef26d1563 100644
--- a/src/vm/stdinterfaces.h
+++ b/src/vm/stdinterfaces.h
@@ -539,18 +539,10 @@ HRESULT TryGetGuid(MethodTable* pClass, GUID* pGUID, BOOL b);
//------------------------------------------------------------------------------------------
// Helpers to get the ITypeInfo* for a type.
-HRESULT ExportTypeLibFromLoadedAssemblyNoThrow(Assembly *pAssembly, LPCWSTR szTlb, ITypeLib **ppTlb, ITypeLibExporterNotifySink *pINotify, int flags);
-void ExportTypeLibFromLoadedAssembly(Assembly *pAssembly, LPCWSTR szTlb, ITypeLib **ppTlb, ITypeLibExporterNotifySink *pINotify, int flags);
-HRESULT GetITypeLibForEEClass(MethodTable *pMT, ITypeLib **ppTLB, int bAutoCreate, int flags);
HRESULT GetITypeInfoForEEClass(MethodTable *pMT, ITypeInfo **ppTI, int bClassInfo=false, int bAutoCreate=true, int flags=0);
-HRESULT GetTypeLibIdForRegisteredEEClass(MethodTable *pMT, GUID *pGuid);
HRESULT GetDefaultInterfaceForCoclass(ITypeInfo *pTI, ITypeInfo **ppTIDef);
//-------------------------------------------------------------------------------------
-// Helper to get the ITypeLib* for a Assembly.
-HRESULT GetITypeLibForAssembly(Assembly *pAssembly, ITypeLib **ppTLB, int bAutoCreate, int flags);
-
-//-------------------------------------------------------------------------------------
// Helper to get the GUID of the typelib that is created from an assembly.
HRESULT GetTypeLibGuidForAssembly(Assembly *pAssembly, GUID *pGuid);