diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 5d43d2b6af7..fa7c24f8727 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1400,43 +1400,26 @@ internal static class Separators internal static readonly char[] PathSearchTrimEnd = { (char)0x9, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20, (char)0x85, (char)0xA0 }; } -#if !UNIX - // This is to reduce the runtime overhead of the feature query - private static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject"); -#endif - - internal static bool IsComObject(PSObject psObject) - { -#if UNIX - return false; -#else - if (psObject == null) { return false; } - - object obj = PSObject.Base(psObject); - return IsComObject(obj); -#endif - } - + /// + /// A COM object could be directly of the type 'System.__ComObject', or it could be a strongly typed RWC, + /// whose specific type derives from 'System.__ComObject'. + /// A strongly typed RWC can be created via the 'new' operation with a Primary Interop Assembly (PIA). + /// For example, with the PIA 'Microsoft.Office.Interop.Excel', you can write the following code: + /// var excelApp = new Microsoft.Office.Interop.Excel.Application(); + /// Type type = excelApp.GetType(); + /// Type comObjectType = typeof(object).Assembly.GetType("System.__ComObject"); + /// Console.WriteLine("excelApp type: {0}", type.FullName); + /// Console.WriteLine("Is __ComObject assignable from? {0}", comObjectType.IsAssignableFrom(type)); + /// and the results are: + /// excelApp type: Microsoft.Office.Interop.Excel.ApplicationClass + /// Is __ComObject assignable from? True + /// internal static bool IsComObject(object obj) { #if UNIX return false; #else - // We can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust. - // - // There could be strongly typed RWCs whose type is not 'System.__ComObject', but the more specific type should - // derive from 'System.__ComObject'. The strongly typed RWCs can be created with 'new' operation via the Primay - // Interop Assembly (PIA). - // For example, with the PIA 'Microsoft.Office.Interop.Excel', you can write the following code: - // var excelApp = new Microsoft.Office.Interop.Excel.Application(); - // Type type = excelApp.GetType(); - // Type comObjectType = typeof(object).Assembly.GetType("System.__ComObject"); - // Console.WriteLine("excelApp type: {0}", type.FullName); - // Console.WriteLine("Is __ComObject assignable from? {0}", comObjectType.IsAssignableFrom(type)); - // and the results are: - // excelApp type: Microsoft.Office.Interop.Excel.ApplicationClass - // Is __ComObject assignable from? True - return obj != null && ComObjectType.IsAssignableFrom(obj.GetType()); + return obj != null && Marshal.IsComObject(obj); #endif } } diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index c6159b1fe85..68ca0f4410b 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -499,7 +499,7 @@ internal static class CachedReflectionInfo typeof(VariableOps).GetMethod(nameof(VariableOps.SetVariableValue), staticFlags); internal static readonly MethodInfo Utils_IsComObject = - typeof(Utils).GetMethod(nameof(Utils.IsComObject), staticFlags, binder: null, types: new Type[] {typeof(object)}, modifiers: null); + typeof(Utils).GetMethod(nameof(Utils.IsComObject), staticFlags); internal static readonly MethodInfo ClassOps_ValidateSetProperty = typeof(ClassOps).GetMethod(nameof(ClassOps.ValidateSetProperty), staticPublicFlags); diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index 39943665f58..b10d2ecac91 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -14,6 +14,7 @@ using System.Management.Automation.Runspaces; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -619,7 +620,7 @@ public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, Dyna GetRestrictions(target))).WriteToDebugLog(this); } - if (Utils.IsComObject(targetValue)) + if (Marshal.IsComObject(targetValue)) { // Pretend that all com objects are enumerable, even if they aren't. We do this because it's technically impossible // to know if a com object is enumerable without just trying to cast it to IEnumerable. We could generate a rule like: @@ -715,7 +716,12 @@ private static IEnumerator AutomationNullRule(CallSite site, object obj) private static IEnumerator NotEnumerableRule(CallSite site, object obj) { - if (!(obj is PSObject) && !(obj is IEnumerable) && !(obj is IEnumerator) && !(obj is DataTable) && !Utils.IsComObject(obj)) + if (obj == null) + { + return null; + } + + if (!(obj is PSObject) && !(obj is IEnumerable) && !(obj is IEnumerator) && !(obj is DataTable) && !Marshal.IsComObject(obj)) { return null; } @@ -4988,7 +4994,7 @@ public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, Dy if (target.Value is PSObject && (PSObject.Base(target.Value) != target.Value)) { Object baseObject = PSObject.Base(target.Value); - if (baseObject != null && Utils.IsComObject(baseObject)) + if (baseObject != null && Marshal.IsComObject(baseObject)) { // We unwrap only if the 'base' is a COM object. It's unnecessary to unwrap in other cases, // especially in the case of strings, we would lose instance members on the PSObject. @@ -5859,7 +5865,7 @@ public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, Dy (value.Value is PSObject && (PSObject.Base(value.Value) != value.Value))) { Object baseObject = PSObject.Base(target.Value); - if (baseObject != null && Utils.IsComObject(baseObject)) + if (baseObject != null && Marshal.IsComObject(baseObject)) { // We unwrap only if the 'base' of 'target' is a COM object. It's unnecessary to unwrap in other cases, // especially in the case that 'target' is a string, we would lose instance members on the PSObject. @@ -6380,7 +6386,7 @@ public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, args.Any(mo => mo.Value is PSObject && (PSObject.Base(mo.Value) != mo.Value))) { Object baseObject = PSObject.Base(target.Value); - if (baseObject != null && Utils.IsComObject(baseObject)) + if (baseObject != null && Marshal.IsComObject(baseObject)) { // We unwrap only if the 'base' of 'target' is a COM object. It's unnecessary to unwrap in other cases, // especially in the case that 'target' is a string, we would lose instance members on the PSObject.