Add support for IDispatch in CoreCLR
authorAaron Robinson <arobins@microsoft.com>
Fri, 19 Oct 2018 20:03:37 +0000 (13:03 -0700)
committerAaron Robinson <arobins@microsoft.com>
Tue, 23 Oct 2018 18:28:59 +0000 (11:28 -0700)
Reduce some TypeInfo API cruft

Throw exception on non-Windows ABIs for value types

Commit migrated from https://github.com/dotnet/coreclr/commit/b5dc2a822331595f79b6ada42c8feff63ae0cc96

src/coreclr/src/System.Private.CoreLib/src/System/RtType.cs
src/coreclr/src/vm/CMakeLists.txt
src/coreclr/src/vm/callsiteinspect.cpp [new file with mode: 0644]
src/coreclr/src/vm/callsiteinspect.h [new file with mode: 0644]
src/coreclr/src/vm/clrtocomcall.cpp
src/coreclr/src/vm/metasig.h
src/coreclr/src/vm/mlinfo.h
src/coreclr/src/vm/mscorlib.h
src/coreclr/src/vm/stdinterfaces.cpp
src/coreclr/src/vm/stdinterfaces.h

index 0e5cf81..1612be8 100644 (file)
@@ -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
index 54c73cc..842fe31 100644 (file)
@@ -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/coreclr/src/vm/callsiteinspect.cpp b/src/coreclr/src/vm/callsiteinspect.cpp
new file mode 100644 (file)
index 0000000..953714d
--- /dev/null
@@ -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/coreclr/src/vm/callsiteinspect.h b/src/coreclr/src/vm/callsiteinspect.h
new file mode 100644 (file)
index 0000000..8a2d7cc
--- /dev/null
@@ -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);
+}
index 372cf6f..e56c4b4 100644 (file)
@@ -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));
index b3a4139..e826526 100644 (file)
@@ -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))
index b27dcc0..b31e34f 100644 (file)
@@ -31,6 +31,7 @@ enum DispatchWrapperType
 {
     DispatchWrapperType_Unknown         = 0x00000001,
     DispatchWrapperType_Dispatch        = 0x00000002,
+    //DispatchWrapperType_Record          = 0x00000004,
     DispatchWrapperType_Error           = 0x00000008,
     DispatchWrapperType_Currency        = 0x00000010,
     DispatchWrapperType_BStr            = 0x00000020,
index 2813fc6..ab00e94 100644 (file)
@@ -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)
index 5726df9..005748c 100644 (file)
@@ -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()
 
 
index 57981fa..3ef26d1 100644 (file)
@@ -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);