Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ComBinder.cs378 linesDownload Raw Back to ComInterop
1// Licensed to the .NET Foundation under one or more agreements.2// The .NET Foundation licenses this file to you under the MIT license.3 4using System.Collections.Generic;5using System.Dynamic;6using System.Linq;7using System.Linq.Expressions;8using System.Management.Automation.Language;9using System.Runtime.InteropServices;10 11namespace System.Management.Automation.ComInterop12{13    /// <summary>14    /// Provides helper methods to bind COM objects dynamically.15    /// </summary>16    internal static class ComBinder17    {18        /// <summary>19        /// Determines if an object is a COM object.20        /// </summary>21        /// <param name="value">The object to test.</param>22        /// <returns>True if the object is a COM object, false otherwise.</returns>23        public static bool IsComObject(object value)24        {25            return value != null && Marshal.IsComObject(value);26        }27 28        /// <summary>29        /// Tries to perform binding of the dynamic get member operation.30        /// </summary>31        /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>32        /// <param name="instance">The target of the dynamic operation. </param>33        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>34        /// <param name="delayInvocation">True if member evaluation may be delayed.</param>35        /// <returns>True if operation was bound successfully; otherwise, false.</returns>36        public static bool TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, out DynamicMetaObject result, bool delayInvocation)37        {38            Requires.NotNull(binder);39            Requires.NotNull(instance);40 41            if (TryGetMetaObject(ref instance))42            {43                var comGetMember = new ComGetMemberBinder(binder, delayInvocation);44                result = instance.BindGetMember(comGetMember);45                if (result.Expression.Type.IsValueType)46                {47                    result = new DynamicMetaObject(48                        Expression.Convert(result.Expression, typeof(object)),49                        result.Restrictions50                    );51                }52                return true;53            }54 55            result = null;56            return false;57        }58 59        /// <summary>60        /// Tries to perform binding of the dynamic set member operation.61        /// </summary>62        /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>63        /// <param name="instance">The target of the dynamic operation.</param>64        /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>65        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>66        /// <returns>True if operation was bound successfully; otherwise, false.</returns>67        public static bool TryBindSetMember(SetMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject value, out DynamicMetaObject result)68        {69            Requires.NotNull(binder);70            Requires.NotNull(instance);71            Requires.NotNull(value);72 73            if (TryGetMetaObject(ref instance))74            {75                result = instance.BindSetMember(binder, value);76                result = new DynamicMetaObject(result.Expression, result.Restrictions.Merge(value.PSGetMethodArgumentRestriction()));77                return true;78            }79 80            result = null;81            return false;82        }83 84        /// <summary>85        /// Tries to perform binding of the dynamic invoke operation.86        /// </summary>87        /// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param>88        /// <param name="instance">The target of the dynamic operation. </param>89        /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>90        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>91        /// <returns>True if operation was bound successfully; otherwise, false.</returns>92        public static bool TryBindInvoke(InvokeBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result)93        {94            Requires.NotNull(binder);95            Requires.NotNull(instance);96            Requires.NotNull(args);97 98            if (TryGetMetaObjectInvoke(ref instance))99            {100                result = instance.BindInvoke(binder, args);101                return true;102            }103 104            result = null;105            return false;106        }107 108        /// <summary>109        /// Tries to perform binding of the dynamic invoke member operation.110        /// </summary>111        /// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param>112        /// <param name="isSetProperty">True if this is for setting a property, false otherwise.</param>113        /// <param name="instance">The target of the dynamic operation. </param>114        /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>115        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>116        /// <returns>True if operation was bound successfully; otherwise, false.</returns>117        public static bool TryBindInvokeMember(InvokeMemberBinder binder, bool isSetProperty, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result)118        {119            Requires.NotNull(binder);120            Requires.NotNull(instance);121            Requires.NotNull(args);122 123            if (TryGetMetaObject(ref instance))124            {125                var comInvokeMember = new ComInvokeMemberBinder(binder, isSetProperty);126                result = instance.BindInvokeMember(comInvokeMember, args);127 128                BindingRestrictions argRestrictions = args.Aggregate(129                    BindingRestrictions.Empty, (current, arg) => current.Merge(arg.PSGetMethodArgumentRestriction()));130                var newRestrictions = result.Restrictions.Merge(argRestrictions);131 132                if (result.Expression.Type.IsValueType)133                {134                    result = new DynamicMetaObject(135                        Expression.Convert(result.Expression, typeof(object)),136                        newRestrictions137                    );138                }139                else140                {141                    result = new DynamicMetaObject(result.Expression, newRestrictions);142                }143 144                return true;145            }146 147            result = null;148            return false;149        }150 151        /// <summary>152        /// Tries to perform binding of the dynamic get index operation.153        /// </summary>154        /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>155        /// <param name="instance">The target of the dynamic operation. </param>156        /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>157        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>158        /// <returns>True if operation was bound successfully; otherwise, false.</returns>159        public static bool TryBindGetIndex(GetIndexBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result)160        {161            Requires.NotNull(binder);162            Requires.NotNull(instance);163            Requires.NotNull(args);164 165            if (TryGetMetaObjectInvoke(ref instance))166            {167                result = instance.BindGetIndex(binder, args);168                return true;169            }170 171            result = null;172            return false;173        }174 175        /// <summary>176        /// Tries to perform binding of the dynamic set index operation.177        /// </summary>178        /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>179        /// <param name="instance">The target of the dynamic operation. </param>180        /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>181        /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>182        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>183        /// <returns>True if operation was bound successfully; otherwise, false.</returns>184        public static bool TryBindSetIndex(SetIndexBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, DynamicMetaObject value, out DynamicMetaObject result)185        {186            Requires.NotNull(binder);187            Requires.NotNull(instance);188            Requires.NotNull(args);189            Requires.NotNull(value);190 191            if (TryGetMetaObjectInvoke(ref instance))192            {193                result = instance.BindSetIndex(binder, args, value);194                result = new DynamicMetaObject(result.Expression, result.Restrictions.Merge(value.PSGetMethodArgumentRestriction()));195                return true;196            }197 198            result = null;199            return false;200        }201 202        /// <summary>203        /// Tries to perform binding of the dynamic Convert operation.204        /// </summary>205        /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>206        /// <param name="instance">The target of the dynamic operation.</param>207        /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>208        /// <returns>True if operation was bound successfully; otherwise, false.</returns>209        public static bool TryConvert(ConvertBinder binder, DynamicMetaObject instance, out DynamicMetaObject result)210        {211            Requires.NotNull(binder);212            Requires.NotNull(instance);213 214            if (IsComObject(instance.Value))215            {216                // Converting a COM object to any interface is always considered possible - it will result in217                // a QueryInterface at runtime218                if (binder.Type.IsInterface)219                {220                    result = new DynamicMetaObject(221                        Expression.Convert(222                            instance.Expression,223                            binder.Type224                        ),225                        BindingRestrictions.GetExpressionRestriction(226                            Expression.Call(227                                typeof(ComBinder).GetMethod(nameof(ComBinder.IsComObject), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public),228                                Helpers.Convert(instance.Expression, typeof(object))229                            )230                        )231                    );232                    return true;233                }234            }235 236            result = null;237            return false;238        }239 240        /// <summary>241        /// Gets the member names of the data-like members associated with the object.242        /// This function can operate only with objects for which <see cref="IsComObject"/> returns true.243        /// </summary>244        /// <param name="value">The object for which member names are requested.</param>245        /// <returns>The collection of member names.</returns>246        internal static IList<string> GetDynamicDataMemberNames(object value)247        {248            Requires.NotNull(value);249            Requires.Condition(IsComObject(value), nameof(value));250 251            return ComObject.ObjectToComObject(value).GetMemberNames(true);252        }253 254        /// <summary>255        /// Gets the data-like members and associated data for an object.256        /// This function can operate only with objects for which <see cref="IsComObject"/> returns true.257        /// </summary>258        /// <param name="value">The object for which data members are requested.</param>259        /// <param name="names">The enumeration of names of data members for which to retrieve values.</param>260        /// <returns>The collection of pairs that represent data member's names and their data.</returns>261        internal static IList<KeyValuePair<string, object>> GetDynamicDataMembers(object value, IEnumerable<string> names)262        {263            Requires.NotNull(value);264            Requires.Condition(IsComObject(value), nameof(value));265 266            return ComObject.ObjectToComObject(value).GetMembers(names);267        }268 269        private static bool TryGetMetaObject(ref DynamicMetaObject instance)270        {271            // If we're already a COM MO don't make a new one272            // (we do this to prevent recursion if we call Fallback from COM)273            if (instance is ComUnwrappedMetaObject)274            {275                return false;276            }277 278            if (IsComObject(instance.Value))279            {280                instance = new ComMetaObject(instance.Expression, instance.Restrictions, instance.Value);281                return true;282            }283 284            return false;285        }286 287        private static bool TryGetMetaObjectInvoke(ref DynamicMetaObject instance)288        {289            // If we're already a COM MO don't make a new one290            // (we do this to prevent recursion if we call Fallback from COM)291            if (TryGetMetaObject(ref instance))292            {293                return true;294            }295 296            if (instance.Value is IPseudoComObject o)297            {298                instance = o.GetMetaObject(instance.Expression);299                return true;300            }301 302            return false;303        }304 305        /// <summary>306        /// Special binder that indicates special semantics for COM GetMember operation.307        /// </summary>308        internal class ComGetMemberBinder : GetMemberBinder309        {310            private readonly GetMemberBinder _originalBinder;311            internal bool _canReturnCallables;312 313            internal ComGetMemberBinder(GetMemberBinder originalBinder, bool canReturnCallables)314             : base(originalBinder.Name, originalBinder.IgnoreCase)315            {316                _originalBinder = originalBinder;317                _canReturnCallables = canReturnCallables;318            }319 320            public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)321            {322                return _originalBinder.FallbackGetMember(target, errorSuggestion);323            }324 325            public override int GetHashCode()326            {327                return _originalBinder.GetHashCode() ^ (_canReturnCallables ? 1 : 0);328            }329 330            public override bool Equals(object obj)331            {332                return obj is ComGetMemberBinder other333                    && _canReturnCallables == other._canReturnCallables334                    && _originalBinder.Equals(other._originalBinder);335            }336        }337 338        /// <summary>339        /// Special binder that indicates special semantics for COM InvokeMember operation.340        /// </summary>341        internal class ComInvokeMemberBinder : InvokeMemberBinder342        {343            private readonly InvokeMemberBinder _originalBinder;344            internal bool IsPropertySet;345 346            internal ComInvokeMemberBinder(InvokeMemberBinder originalBinder, bool isPropertySet)347                : base(originalBinder.Name, originalBinder.IgnoreCase, originalBinder.CallInfo)348            {349                _originalBinder = originalBinder;350                this.IsPropertySet = isPropertySet;351            }352 353            public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)354            {355                return _originalBinder.FallbackInvoke(target, args, errorSuggestion);356            }357 358            public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)359            {360                return _originalBinder.FallbackInvokeMember(target, args, errorSuggestion);361            }362 363            public override int GetHashCode()364            {365                return _originalBinder.GetHashCode() ^ (IsPropertySet ? 1 : 0);366            }367 368            public override bool Equals(object obj)369            {370                ComInvokeMemberBinder other = obj as ComInvokeMemberBinder;371                return other != null &&372                    IsPropertySet == other.IsPropertySet &&373                    _originalBinder.Equals(other._originalBinder);374            }375        }376    }377}378