Disable marshalling delegates as _Delegate and enable marshalling delegates as IDispa...
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Fri, 5 Apr 2019 05:56:56 +0000 (22:56 -0700)
committerGitHub <noreply@github.com>
Fri, 5 Apr 2019 05:56:56 +0000 (22:56 -0700)
* Disable marshalling delegates as _Delegate and enable marshalling delegates as IDispatch.

* ifdef out the new IDispatch marshalling on non-COM-supporting platforms.

* PR feedback.

src/dlls/mscorrc/mscorrc.rc
src/dlls/mscorrc/resource.h
src/vm/fieldmarshaler.cpp
src/vm/mlinfo.cpp
tests/src/Interop/PInvoke/Delegate/MarshalDelegateAsField/AsFieldNative.cpp
tests/src/Interop/PInvoke/Delegate/MarshalDelegateAsField/RefLib/RefLib.cs
tests/src/Interop/PInvoke/Delegate/MarshalDelegateAsParam/AsInterface/AsInterfaceTest.cs
tests/src/Interop/PInvoke/Delegate/MarshalDelegateAsParam/AsParamNative.cpp

index 4853f00..7acfb09 100644 (file)
@@ -586,7 +586,8 @@ BEGIN
     IDS_EE_BADMARSHAL_R8                    "Invalid managed/unmanaged type combination (Double must be paired with R8)."
     IDS_EE_BADMARSHAL_PTR                   "Invalid managed/unmanaged type combination (pointers must not have a MarshalAs attribute set)."
     IDS_EE_BADMARSHAL_NOLAYOUT              "The type definition of this type has no layout information."
-    IDS_EE_BADMARSHAL_DELEGATE              "Invalid managed/unmanaged type combination (Delegates must be paired with FunctionPtr or Interface)."
+    IDS_EE_BADMARSHAL_DELEGATE              "Invalid managed/unmanaged type combination (Delegates must be paired with FunctionPtr or IDispatch)."
+    IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE ".NET Core does not support marshalling delegates to the _Delegate interface provided by the .NET Framework COM Type Library. To marshal a delegate as an interface, marshal it as an IDispatch pointer."
     IDS_EE_BADMARSHAL_FNPTR                 "Invalid managed/unmanaged type combination (function pointers must be paired with FunctionPtr)."
     IDS_EE_BADMARSHAL_INTERFACE             "Invalid managed/unmanaged type combination (Interfaces must be paired with Interface)."
     IDS_EE_BADMARSHAL_CLASS                 "Invalid managed/unmanaged type combination (this type must be paired with LPStruct or Interface)."
index 609a31d..cc9e0e8 100644 (file)
 #define IDS_EE_BADMARSHAL_STRING_OUT               0x2646
 #define IDS_EE_BADMARSHAL_COPYCTORRESTRICTION      0x2647
 #define IDS_EE_BADMARSHAL_WINRT_COPYCTOR           0x2648
+#define IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE   0x2649
index 51d9b8b..a8676d6 100644 (file)
@@ -588,12 +588,16 @@ do                                                      \
                 {
                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
                 }
+                else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable()))
+                {
+                    INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE));
+                }
                 else
                 {
                     ItfMarshalInfo itfInfo;
                     if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
                         break;
-
+                        
                     INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
                 }
             }
@@ -792,6 +796,16 @@ do                                                      \
                 {
                     INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable()));
                 }
+#ifdef FEATURE_COMINTEROP
+                else if (ntype == NATIVE_TYPE_IDISPATCH)
+                {
+                    ItfMarshalInfo itfInfo;
+                    if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
+                        break;
+
+                    INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
+                }
+#endif // FEATURE_COMINTEROP
                 else
                 {
                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE));
index f861c43..cb512bb 100644 (file)
@@ -2003,16 +2003,27 @@ MarshalInfo::MarshalInfo(Module* pModule,
                     IfFailGoto(E_FAIL, lFail);
                 }
 
-                if (m_ms == MARSHAL_SCENARIO_WINRT && COMDelegate::IsDelegate(m_pMT))
+                if (COMDelegate::IsDelegate(m_pMT))
                 {
-                    // In WinRT scenarios delegates must be WinRT delegates
-                    if (!m_pMT->IsProjectedFromWinRT() && !WinRTTypeNameConverter::IsRedirectedType(m_pMT))
+                    if (m_ms == MARSHAL_SCENARIO_WINRT)
                     {
-                        m_resID = IDS_EE_BADMARSHAL_WINRT_DELEGATE;
+                        // In WinRT scenarios delegates must be WinRT delegates
+                        if (!m_pMT->IsProjectedFromWinRT() && !WinRTTypeNameConverter::IsRedirectedType(m_pMT))
+                        {
+                            m_resID = IDS_EE_BADMARSHAL_WINRT_DELEGATE;
+                            IfFailGoto(E_FAIL, lFail);
+                        }
+                    }
+                    else
+                    {
+                        // UnmanagedType.Interface for delegates used to mean the .NET Framework _Delegate interface.
+                        // We don't support that interface in .NET Core, so we disallow marshalling as it here.
+                        // The user can specify UnmanagedType.IDispatch and use the delegate through the IDispatch interface
+                        // if they need an interface pointer.
+                        m_resID = IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE;
                         IfFailGoto(E_FAIL, lFail);
                     }
                 }
-
                 m_type = MARSHAL_TYPE_INTERFACE;
             }
             else if (pDefaultMT != NULL && nativeType == NATIVE_TYPE_DEFAULT)
@@ -2291,17 +2302,29 @@ MarshalInfo::MarshalInfo(Module* pModule,
 
                         case NATIVE_TYPE_DEFAULT:
 #ifdef FEATURE_COMINTEROP
-                            if (m_ms != MARSHAL_SCENARIO_NDIRECT)
+                            if (m_ms == MARSHAL_SCENARIO_WINRT)
                             {
-                                _ASSERTE(m_ms == MARSHAL_SCENARIO_COMINTEROP || m_ms == MARSHAL_SCENARIO_WINRT);
                                 m_type = MARSHAL_TYPE_INTERFACE;
                             }
+                            else if (m_ms == MARSHAL_SCENARIO_COMINTEROP)
+                            {
+                                // Default for COM marshalling for delegates used to mean the .NET Framework _Delegate interface.
+                                // We don't support that interface in .NET Core, so we disallow marshalling as it here.
+                                // The user can specify UnmanagedType.IDispatch and use the delegate through the IDispatch interface
+                                // if they need an interface pointer.
+                                m_resID = IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE;
+                                IfFailGoto(E_FAIL, lFail);
+                            }
                             else
 #endif // FEATURE_COMINTEROP
                                 m_type = MARSHAL_TYPE_DELEGATE;
 
                             break;
-
+#ifdef FEATURE_COMINTEROP
+                        case NATIVE_TYPE_IDISPATCH:
+                            m_type = MARSHAL_TYPE_INTERFACE;
+                            break;
+#endif
                         default:
                         m_resID = IDS_EE_BADMARSHAL_DELEGATE;
                         IfFailGoto(E_FAIL, lFail);
index d5fdf86..9f43d63 100644 (file)
@@ -113,9 +113,6 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeDelegateAsFieldInClass_Exp(Clas
 *                                      For MarshalDelegateAsField_AsInterface.cs                  *
 *                                                                                                                                                         *
 *-----------------------------------------------------------------------------*/
-
-#import "mscorlib.tlb" no_namespace named_guids raw_interfaces_only rename("ReportEvent","ReportEventNew")
-
 typedef struct{
     int result1;
     int result2;
@@ -167,7 +164,7 @@ bool STDMETHODCALLTYPE Verify(Result expectedR, Result resultR)
 
 typedef struct _Struct3_InterfacePtrAsField1_Seq{
     BOOL  verification;
-    _Delegate * p_dele;
+    IDispatch * p_dele;
 }Struct3_InterfacePtrAsField1_Seq;
 
 extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Seq(Struct3_InterfacePtrAsField1_Seq sis)
@@ -183,14 +180,6 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Seq
     }
     else 
     {
-        hr = sis.p_dele->DynamicInvoke( NULL, NULL);
-        if(FAILED(hr))
-        {
-            return FALSE;
-        }
-        bool tempBool = sis.verification && Verify( expected, result);
-
-
         //IDispatch::Invoke
         ResetToZero();
 
@@ -234,14 +223,14 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Seq
             return FALSE;
         }
 
-        return tempBool && Verify(expected, result);
+        return Verify(expected, result);
     }
 }
 
 typedef struct _Struct3_InterfacePtrAsField2_Exp{
     bool verification;
     int  Padding;
-    _Delegate * p_dele;
+    IDispatch * p_dele;
 }Struct3_InterfacePtrAsField2_Exp;
 
 extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Exp(Struct3_InterfacePtrAsField2_Exp sie)
@@ -255,18 +244,9 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Exp
         printf("NULL field member.\n");
         return FALSE;
     }
-    else 
+    else
     {
-        hr = sie.p_dele->DynamicInvoke(NULL, NULL);
-        if(FAILED(hr))
-        {
-            return FALSE;
-        }
-        bool tempBool = sie.verification && Verify( expected, result);
-
-
         //IDispatch::Invoke
-        ResetToZero();
 
         BSTR bstrNames[1];
         bstrNames[0] = SysAllocString(L"DynamicInvoke");
@@ -307,7 +287,7 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInStruct_Exp
             return FALSE;
         }
 
-        return tempBool && Verify(expected, result);
+        return Verify(expected, result);
     }
 }
 
@@ -315,7 +295,7 @@ class Class3_InterfacePtrAsField3_Seq
 {
 public:
     bool verification;
-    _Delegate * p_dele;
+    IDispatch * p_dele;
 };
 
 extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Seq(Class3_InterfacePtrAsField3_Seq *cis)
@@ -331,14 +311,6 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Seq(
     }
     else 
     {
-        hr = (cis->p_dele)->DynamicInvoke(NULL, NULL);
-        if(FAILED(hr))
-        {
-            return FALSE;
-        }
-        bool tempBool = cis->verification && Verify( expected, result);
-
-
         //IDispatch::Invoke
         BSTR bstrNames[1];
         bstrNames[0] = SysAllocString(L"DynamicInvoke");
@@ -380,7 +352,7 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Seq(
             return FALSE;
         }
 
-        return tempBool && Verify(expected, result);
+        return Verify(expected, result);
     }
 
 }
@@ -389,7 +361,7 @@ class Class3_InterfacePtrAsField4_Exp{
 public:
     bool verification;
     int  Padding;
-    _Delegate * p_dele;
+    IDispatch * p_dele;
 };
 
 extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Exp(Class3_InterfacePtrAsField4_Exp *cie)
@@ -405,14 +377,6 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Exp(
     }
     else 
     {
-        hr = (cie->p_dele)->DynamicInvoke(NULL, NULL);
-        if(FAILED(hr))
-        {
-            return FALSE;
-        }
-        bool tempBool = cie->verification && Verify( expected, result);
-
-
         //IDispatch::Invoke
         BSTR bstrNames[1];
         bstrNames[0] = SysAllocString(L"DynamicInvoke");
@@ -453,7 +417,11 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrAsFieldInClass_Exp(
             return FALSE;
         }
 
-        return tempBool && Verify(expected, result);
+        return Verify(expected, result);
     }
 }
+
+extern "C" DLL_EXPORT void STDMETHODCALLTYPE TakeDelegateAsInterface(void* illegal)
+{
+}
 #endif
index a89be58..37f74c9 100644 (file)
@@ -107,7 +107,7 @@ public struct Struct3_InterfacePtrAsField1_Seq
 {
     public bool verification;
 
-    [MarshalAs(UnmanagedType.Interface)]
+    [MarshalAs(UnmanagedType.IDispatch)]
     public Dele2 dele;
 }
 
@@ -121,7 +121,7 @@ public struct Struct3_InterfacePtrAsField2_Exp
     public Int32 Padding;
 
     [FieldOffset(8)]
-    [MarshalAs(UnmanagedType.Interface)]
+    [MarshalAs(UnmanagedType.IDispatch)]
     public Dele2 dele;
 }
 
@@ -130,7 +130,7 @@ public class Class3_InterfacePtrAsField3_Seq
 {
     public bool verification;
 
-    [MarshalAs(UnmanagedType.Interface)]
+    [MarshalAs(UnmanagedType.IDispatch)]
     public Dele2 dele;
 }
 
@@ -144,7 +144,7 @@ public class Class3_InterfacePtrAsField4_Exp
     public Int32 Padding;
 
     [FieldOffset(8)]
-    [MarshalAs(UnmanagedType.Interface)]
+    [MarshalAs(UnmanagedType.IDispatch)]
     public Dele2 dele;
 }
-#endregion
\ No newline at end of file
+#endregion
index b06260b..7e43687 100644 (file)
@@ -11,32 +11,35 @@ class AsInterfaceTest
     public delegate void Dele();
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByValParam([MarshalAs(UnmanagedType.Interface)] Dele dele);
+    extern static bool Take_DelegatePtrByValParam([MarshalAs(UnmanagedType.IDispatch)] Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByRefParam([MarshalAs(UnmanagedType.Interface)] ref Dele dele);
+    extern static bool Take_DelegatePtrByRefParam([MarshalAs(UnmanagedType.IDispatch)] ref Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByInValParam([In, MarshalAs(UnmanagedType.Interface)] Dele dele);
+    extern static bool Take_DelegatePtrByInValParam([In, MarshalAs(UnmanagedType.IDispatch)] Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByInRefParam([In, MarshalAs(UnmanagedType.Interface)] ref Dele dele);
+    extern static bool Take_DelegatePtrByInRefParam([In, MarshalAs(UnmanagedType.IDispatch)] ref Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByOutValParam([Out, MarshalAs(UnmanagedType.Interface)] Dele dele);
+    extern static bool Take_DelegatePtrByOutValParam([Out, MarshalAs(UnmanagedType.IDispatch)] Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByOutRefParam([Out, MarshalAs(UnmanagedType.Interface)]out Dele dele, [MarshalAs(UnmanagedType.Interface)] Dele deleHelper);
+    extern static bool Take_DelegatePtrByOutRefParam([Out, MarshalAs(UnmanagedType.IDispatch)]out Dele dele, [MarshalAs(UnmanagedType.IDispatch)] Dele deleHelper);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByInOutValParam([In, Out, MarshalAs(UnmanagedType.Interface)] Dele dele);
+    extern static bool Take_DelegatePtrByInOutValParam([In, Out, MarshalAs(UnmanagedType.IDispatch)] Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    extern static bool Take_DelegatePtrByInOutRefParam([In, Out, MarshalAs(UnmanagedType.Interface)] ref Dele dele);
+    extern static bool Take_DelegatePtrByInOutRefParam([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
-    [return: MarshalAs(UnmanagedType.Interface)]
-    extern static Dele ReturnDelegatePtrByVal([MarshalAs(UnmanagedType.Interface)] Dele dele);
+    [return: MarshalAs(UnmanagedType.IDispatch)]
+    extern static Dele ReturnDelegatePtrByVal([MarshalAs(UnmanagedType.IDispatch)] Dele dele);
+
+    [DllImport("PInvoke_Delegate_AsParam")]
+    extern static void TakeDelegateAsInterface([MarshalAs(UnmanagedType.Interface)] Dele dele);
 
     [DllImport("PInvoke_Delegate_AsParam")]
     extern static int RetFieldResult1();
@@ -63,40 +66,40 @@ class AsInterfaceTest
     static int Main()
     {
         try{
-            Console.WriteLine("Scenario 1 : Delegate marshaled by val with attribute [MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("Scenario 1 : Delegate marshaled by val with attribute [MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele1 = new Dele(CommonMethod1);
             dele1 += CommonMethod2;
             dele1 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByValParam(dele1), "Take_DelegatePtrByValParam");
 
-            Console.WriteLine("\n\nScenario 2 : Delegate marshaled by ref with attribute [MarshalAs(MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 2 : Delegate marshaled by ref with attribute [MarshalAs(MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele2 = new Dele(CommonMethod1);
             dele2 += CommonMethod2;
             dele2 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByRefParam(ref dele2), "Take_DelegatePtrByRefParam");
             Assert.IsNull( dele2, "dele2 should equal to null");
 
-            Console.WriteLine("\n\nScenario 3 : Delegate marshaled by val with attribute [In,MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 3 : Delegate marshaled by val with attribute [In,MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele3 = new Dele(CommonMethod1);
             dele3 += CommonMethod2;
             dele3 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByInValParam(dele3), "Take_DelegatePtrByInValParam");
 
-            Console.WriteLine("\n\nScenario 4 : Delegate marshaled by ref with attribute [In,MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 4 : Delegate marshaled by ref with attribute [In,MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele4 = new Dele(CommonMethod1);
             dele4 += CommonMethod2;
             dele4 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByInRefParam(ref dele4), "Take_DelegatePtrByInRefParam");
             Assert.IsNotNull(dele4, "dele4 does't set to null correctly.");
 
-            Console.WriteLine("\n\nScenario 5 : Delegate marshaled by val with attribute [Out,MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 5 : Delegate marshaled by val with attribute [Out,MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele5 = new Dele(CommonMethod1);
             dele5 += CommonMethod2;
             dele5 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByOutValParam(dele5), "Take_DelegatePtrByOutValParam");
             Assert.IsNotNull(dele5, "dele5 does't set to null correctly");
 
-            Console.WriteLine("\n\nScenario 6 : Delegate marshaled by ref with attribute [Out,MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 6 : Delegate marshaled by ref with attribute [Out,MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele6 = null;
             Dele deleHelper = new Dele(CommonMethod1);
             deleHelper += CommonMethod2;
@@ -105,20 +108,20 @@ class AsInterfaceTest
             Assert.AreEqual(COMMONMETHOD1_RESULT, RetFieldResult1(), "RetFieldResult1 return value is wrong");
             Assert.AreEqual(COMMONMETHOD2_RESULT, RetFieldResult2(), "RetFieldResult2 return value is wrong ");
 
-            Console.WriteLine("\n\nScenario 7 : Delegate marshaled by val with attribute [In,OutMarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 7 : Delegate marshaled by val with attribute [In,OutMarshalAs(UnmanagedType.IDispatch)].");
             Dele dele7 = new Dele(CommonMethod1);
             dele7 += CommonMethod2;
             dele7 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByInOutValParam(dele7), "Take_DelegatePtrByInOutValParam");
 
-            Console.WriteLine("\n\nScenario 8 : Delegate marshaled by ref with attribute [In,OutMarshalAs(MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 8 : Delegate marshaled by ref with attribute [In,OutMarshalAs(MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele8 = new Dele(CommonMethod1);
             dele8 += CommonMethod2;
             dele8 += CommonMethod3;
             Assert.IsTrue(Take_DelegatePtrByInOutRefParam(ref dele8), "Take_DelegatePtrByInOutRefParam");
             Assert.IsTrue(dele8 == null, "dele8 does't set to null correctly.");
 
-            Console.WriteLine("\n\nScenario 9 : return Delegate marshaled by val with attribute [return:MarshalAs(UnmanagedType.Interface)].");
+            Console.WriteLine("\n\nScenario 9 : return Delegate marshaled by val with attribute [return:MarshalAs(UnmanagedType.IDispatch)].");
             Dele dele9 = new Dele(CommonMethod1);
             dele9 += CommonMethod2;
             dele9 += CommonMethod3;
@@ -128,6 +131,8 @@ class AsInterfaceTest
             Assert.AreEqual(COMMONMETHOD2_RESULT, RetFieldResult2(), "RetFieldResult2() return value is wrong");
             Assert.AreEqual(COMMONMETHOD3_RESULT, RetFieldResult3(), "RetFieldResult3() return value is wrong");
 
+            Assert.Throws<MarshalDirectiveException>(() => TakeDelegateAsInterface(new Dele(CommonMethod1)));
+
             return 100;
         } catch (Exception e){
             Console.WriteLine($"Test Failure: {e}"); 
index d85babb..c3f2084 100644 (file)
@@ -240,8 +240,6 @@ extern "C" DLL_EXPORT DelegateParam STDMETHODCALLTYPE ReturnDelegateByVal()
 *                                                                                              *
 * -----------------------------------------------------------------------------*/
 
-#import "mscorlib.tlb" no_namespace named_guids raw_interfaces_only rename("ReportEvent","ReportEventNew")
-
 typedef struct{
     int result1;
     int result2;
@@ -290,24 +288,60 @@ BOOL STDMETHODCALLTYPE Verify(Result expectedR, Result resultR)
         && expectedR.result3 == resultR.result3;
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByValParam(_Delegate * p_dele)
+HRESULT InvokeDelegate(IDispatch* dele)
+{
+    HRESULT hr;
+    BSTR bstrNames[1];
+    bstrNames[0] = SysAllocString(L"DynamicInvoke");
+    DISPID dispid = 0;
+    hr = dele->GetIDsOfNames(
+        IID_NULL,
+        bstrNames,
+        sizeof(bstrNames) / sizeof(bstrNames[0]),
+        GetUserDefaultLCID(),
+        &dispid);
+
+    SysFreeString(bstrNames[0]);
+
+    if (FAILED(hr))
+    {
+        printf("\nERROR: Invoke failed: 0x%x\n", (unsigned int)hr);
+        return hr;
+    }
+
+    DISPPARAMS params = { NULL, NULL, 0, 0 };
+
+    hr = dele->Invoke(
+        dispid,
+        IID_NULL,
+        GetUserDefaultLCID(),
+        DISPATCH_METHOD,
+        &params,
+        NULL,
+        NULL,
+        NULL);
+
+    return hr;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByValParam(IDispatch * p_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = p_dele->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(p_dele);
     if(FAILED(hr))
         return FALSE;
     else
         return Verify(expected, result);
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByRefParam(_Delegate **pp_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByRefParam(IDispatch **pp_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = (*pp_dele)->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(*pp_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -319,12 +353,12 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByRefParam(_Delegat
     }
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInValParam(_Delegate * p_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInValParam(IDispatch * p_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = p_dele->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(p_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -335,12 +369,12 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInValParam(_Deleg
     }
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInRefParam(_Delegate **pp_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInRefParam(IDispatch **pp_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = (*pp_dele)->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(*pp_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -352,12 +386,12 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInRefParam(_Deleg
     }
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByOutValParam(_Delegate * p_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByOutValParam(IDispatch * p_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = p_dele->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(p_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -385,7 +419,7 @@ extern "C" DLL_EXPORT int STDMETHODCALLTYPE RetFieldResult3()
     return result.result3;
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByOutRefParam(_Delegate ** pp_dele, _Delegate * pdeleHelper)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByOutRefParam(IDispatch ** pp_dele, IDispatch * pdeleHelper)
 {
     printf("In Take_DelegatePtrByOutRefParam native side \n");
     ResetToZero();
@@ -402,12 +436,12 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByOutRefParam(_Dele
     }
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutValParam(_Delegate * p_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutValParam(IDispatch * p_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = p_dele->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(p_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -418,12 +452,12 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutValParam(_De
     }
 }
 
-extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutRefParam(_Delegate **pp_dele)
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutRefParam(IDispatch **pp_dele)
 {
     ResetToZero();
 
     HRESULT hr;
-    hr = (*pp_dele)->DynamicInvoke(NULL, NULL);
+    hr = InvokeDelegate(*pp_dele);
     if(FAILED(hr))
     {
         return FALSE;
@@ -435,7 +469,7 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Take_DelegatePtrByInOutRefParam(_De
     }
 }
 
-extern "C" DLL_EXPORT _Delegate* ReturnDelegatePtrByVal(_Delegate * pdeleHelper)
+extern "C" DLL_EXPORT IDispatch* ReturnDelegatePtrByVal(IDispatch * pdeleHelper)
 {
     pdeleHelper->AddRef();
     return pdeleHelper;