Error out clearly when trying to use COM objects with the DLR. (dotnet/corefx#40075)
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Mon, 23 Sep 2019 23:30:46 +0000 (16:30 -0700)
committerGitHub <noreply@github.com>
Mon, 23 Sep 2019 23:30:46 +0000 (16:30 -0700)
* Throw an exception in the dynamic binder when trying to dynamically resolve a COM object without an enabled COM binder.

* Add test for exception throw on dynamic usage with COM.

* Update test to validate the change in each binder.

* PR Feedback.

* Add missing using.

Commit migrated from https://github.com/dotnet/corefx/commit/5ed05b311925509d3cd4b6938d4935ca31cdaf92

12 files changed:
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs
src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs
src/libraries/Microsoft.CSharp/src/Resources/Strings.resx
src/libraries/Microsoft.CSharp/tests/RuntimeBinderTests.cs

index 67c7a43..57a33b1 100644 (file)
@@ -11,6 +11,7 @@ using System.Linq.Expressions;
 using System.Runtime.InteropServices;
 using System.Reflection;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 
 namespace Microsoft.CSharp.RuntimeBinder
 {
@@ -182,7 +183,6 @@ namespace Microsoft.CSharp.RuntimeBinder
             return obj != null && Marshal.IsComObject(obj);
         }
 
-#if ENABLECOMBINDER
         /////////////////////////////////////////////////////////////////////////////////
 
         // Try to determine if this object represents a WindowsRuntime object - i.e. it either
@@ -210,7 +210,7 @@ namespace Microsoft.CSharp.RuntimeBinder
 
             return false;
         }
-#endif
+
         /////////////////////////////////////////////////////////////////////////////////
 
         private static bool IsTransparentProxy(object obj)
@@ -513,5 +513,15 @@ namespace Microsoft.CSharp.RuntimeBinder
 
             return true;
         }
+
+#if !ENABLECOMBINDER
+        internal static void ThrowIfUsingDynamicCom(DynamicMetaObject target)
+        {
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && target.LimitType.IsCOMObject)
+            {
+                throw ErrorHandling.Error(ErrorCode.ERR_DynamicBindingComUnsupported);
+            }
+        }
+#endif
     }
 }
index 455fee1..fa45efb 100644 (file)
@@ -7,6 +7,7 @@ using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -121,7 +122,10 @@ namespace Microsoft.CSharp.RuntimeBinder
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             return BinderHelper.Bind(this, _binder, new[] { target }, null, errorSuggestion);
         }
index d0d69c7..b36e838 100644 (file)
@@ -5,6 +5,7 @@
 using System;
 using System.Collections.Generic;
 using System.Dynamic;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -89,11 +90,14 @@ namespace Microsoft.CSharp.RuntimeBinder
         {
 #if ENABLECOMBINDER
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindGetIndex(this, target, indexes, out com))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             BinderHelper.ValidateBindArgument(indexes, nameof(indexes));
             return BinderHelper.Bind(this, _binder, BinderHelper.Cons(target, indexes), _argumentInfo, errorSuggestion);
index b300da8..a088414 100644 (file)
@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -104,11 +105,14 @@ namespace Microsoft.CSharp.RuntimeBinder
         {
 #if ENABLECOMBINDER
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindGetMember(this, target, out com, ResultIndexed))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             return BinderHelper.Bind(this, _binder, new[] { target }, _argumentInfo, errorSuggestion);
         }
index 0adc77a..6f1fca3 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Collections.Generic;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -101,13 +102,15 @@ namespace Microsoft.CSharp.RuntimeBinder
         public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
         {
 #if ENABLECOMBINDER
-
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindInvoke(this, target, args, out com))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             BinderHelper.ValidateBindArgument(args, nameof(args));
             return BinderHelper.Bind(this, _binder, BinderHelper.Cons(target, args), _argumentInfo, errorSuggestion);
index 3cb08b3..1da115c 100644 (file)
@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -115,11 +116,14 @@ namespace Microsoft.CSharp.RuntimeBinder
         {
 #if ENABLECOMBINDER
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindInvokeMember(this, target, args, out com))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             BinderHelper.ValidateBindArgument(args, nameof(args));
             return BinderHelper.Bind(this, _binder, BinderHelper.Cons(target, args), _argumentInfo, errorSuggestion);
index 71c3bd5..2779431 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Collections.Generic;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -109,11 +110,14 @@ namespace Microsoft.CSharp.RuntimeBinder
         {
 #if ENABLECOMBINDER
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindSetIndex(this, target, indexes, value, out com))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             BinderHelper.ValidateBindArgument(indexes, nameof(indexes));
             BinderHelper.ValidateBindArgument(value, nameof(value));
index 66315db..1fbd07c 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Collections.Generic;
 using System.Dynamic;
 using System.Numerics.Hashing;
+using Microsoft.CSharp.RuntimeBinder.Errors;
 using Microsoft.CSharp.RuntimeBinder.Semantics;
 
 namespace Microsoft.CSharp.RuntimeBinder
@@ -109,11 +110,14 @@ namespace Microsoft.CSharp.RuntimeBinder
         {
 #if ENABLECOMBINDER
             DynamicMetaObject com;
-            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryBindSetMember(this, target, value, out com))
+            if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
             {
                 return com;
             }
+#else
+            BinderHelper.ThrowIfUsingDynamicCom(target);
 #endif
+
             BinderHelper.ValidateBindArgument(target, nameof(target));
             BinderHelper.ValidateBindArgument(value, nameof(value));
             return BinderHelper.Bind(this, _binder, new[] { target, value }, _argumentInfo, errorSuggestion);
index d0003f4..a386666 100644 (file)
@@ -64,6 +64,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
         ERR_NamedArgumentUsedInPositional = 1744,
         ERR_BadNamedArgumentForDelegateInvoke = 1746,
         ERR_NonInvocableMemberCalled = 1955,
-        ERR_BadNonTrailingNamedArgument = 8323
+        ERR_BadNonTrailingNamedArgument = 8323,
+        ERR_DynamicBindingComUnsupported = 8365
     }
 }
index a339a97..ad0f121 100644 (file)
@@ -191,7 +191,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
                 case ErrorCode.ERR_BadNonTrailingNamedArgument:
                     codeStr = SR.BadNonTrailingNamedArgument;
                     break;
-
+                case ErrorCode.ERR_DynamicBindingComUnsupported:
+                    codeStr = SR.DynamicBindingComUnsupported;
+                    break;
                 default:
                     // means missing resources match the code entry
                     Debug.Fail("Missing resources for the error " + code.ToString());
index ecde81c..ea1e5ad 100644 (file)
   <data name="AnonMethod" xml:space="preserve">
     <value>anonymous method</value>
   </data>
+  <data name="DynamicBindingComUnsupported" xml:space="preserve">
+    <value>The C# runtime binder cannot dynamically resolve members on COM Runtime Callable Wrappers.</value>
+  </data>
   <data name="ERRORSYM" xml:space="preserve">
     <value>&lt;error&gt;</value>
   </data>
index 38bfa96..6d81430 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using Xunit;
 
 // IVT to "Microsoft.CSharp.RuntimeBinder.Binder", just to use IVT in a test (see: InternalsVisibleToTest below)
@@ -49,7 +50,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Tests
         public void GenericNameMatchesPredefined()
         {
             dynamic d = 3;
-            dynamic v = new Value<int> {Quantity = d};
+            dynamic v = new Value<int> { Quantity = d };
             dynamic r = v.Quantity;
             Assert.Equal(3, r);
             dynamic h = new Holder();
@@ -391,5 +392,64 @@ namespace Microsoft.CSharp.RuntimeBinder.Tests
             Func<CallSite, ICounterBoth, object> target2 = getter.Target;
             Assert.Equal(message, Assert.Throws<RuntimeBinderException>(() => target2(getter, null)).Message);
         }
+
+        // This is not the defined COM interface for IKnownFolderManager.
+        // We need a registered COM interface and CoClass to validate the behavior with dynamic and COM.
+        // The real IKnownFolderManager interface is available on Windows Vista+, so it is on all platforms that we're testing.
+        [ComImport]
+        [Guid("8BE2D872-86AA-4d47-B776-32CCA40C7018")]
+        interface Not_IKnownFolderManager
+        {
+            void MethodCall();
+
+            int this[int i] { get; set; }
+
+            int Property { get; set; }
+        }
+
+        [CoClass(typeof(KnownFolderManagerClass))]
+        [ComImport]
+        [Guid("8BE2D872-86AA-4d47-B776-32CCA40C7018")]
+        interface KnownFolderManager : Not_IKnownFolderManager { }
+
+        [Guid("4df0c730-df9d-4ae3-9153-aa6b82e9795a")]
+        class KnownFolderManagerClass { }
+
+        [Fact]
+        [PlatformSpecific(TestPlatforms.Windows)]
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+        public void DynamicComThrowsException()
+        {
+            Assert.Throws<RuntimeBinderException>(() =>
+            {
+                var a = new { Manager = new KnownFolderManagerClass() };
+                dynamic d = a;
+                d.Manager.MethodCall();
+            });
+            Assert.Throws<RuntimeBinderException>(() =>
+            {
+                var a = new { Manager = new KnownFolderManagerClass() };
+                dynamic d = a;
+                return d.Manager[0];
+            });
+            Assert.Throws<RuntimeBinderException>(() =>
+            {
+                var a = new { Manager = new KnownFolderManagerClass() };
+                dynamic d = a;
+                d.Manager[0] = 1;
+            });
+            Assert.Throws<RuntimeBinderException>(() =>
+            {
+                var a = new { Manager = new KnownFolderManagerClass() };
+                dynamic d = a;
+                d.Manager.Property = 1;
+            });
+            Assert.Throws<RuntimeBinderException>(() =>
+            {
+                var a = new { Manager = new KnownFolderManagerClass() };
+                dynamic d = a;
+                d.Manager.Property = 1;
+            });
+        }
     }
 }