Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
IDispatchMetaObject.cs333 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;5using System.Collections.Generic;6using System.Dynamic;7using System.Linq;8using System.Linq.Expressions;9using System.Management.Automation.Language;10using System.Runtime.InteropServices.ComTypes;11 12namespace System.Management.Automation.ComInterop13{14    internal sealed class IDispatchMetaObject : ComFallbackMetaObject15    {16        private readonly IDispatchComObject _self;17 18        internal IDispatchMetaObject(Expression expression, IDispatchComObject self)19            : base(expression, BindingRestrictions.Empty, self)20        {21            _self = self;22        }23 24        public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)25        {26            Requires.NotNull(binder);27 28            ComMethodDesc method = null;29 30            // See if this is actually a property set31            ComBinder.ComInvokeMemberBinder comInvokeBinder = binder as ComBinder.ComInvokeMemberBinder;32            if ((comInvokeBinder != null) && (comInvokeBinder.IsPropertySet))33            {34                DynamicMetaObject value = args[args.Length - 1];35 36                bool holdsNull = value.Value == null && value.HasValue;37                if (!_self.TryGetPropertySetter(binder.Name, out method, value.LimitType, holdsNull))38                {39                    _self.TryGetPropertySetterExplicit(binder.Name, out method, value.LimitType, holdsNull);40                }41            }42 43            // Otherwise, try property get44            if (method == null)45            {46                if (!_self.TryGetMemberMethod(binder.Name, out method))47                {48                    _self.TryGetMemberMethodExplicit(binder.Name, out method);49                }50            }51 52            if (method != null)53            {54                List<ParameterExpression> temps = new List<ParameterExpression>();55                List<Expression> initTemps = new List<Expression>();56 57                bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(method, ref args, temps, initTemps);58                return BindComInvoke(args, method, binder.CallInfo, isByRef, temps, initTemps);59            }60 61            return base.BindInvokeMember(binder, args);62        }63 64        public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)65        {66            Requires.NotNull(binder);67 68            if (_self.TryGetGetItem(out ComMethodDesc method))69            {70                List<ParameterExpression> temps = new List<ParameterExpression>();71                List<Expression> initTemps = new List<Expression>();72 73                bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(method, ref args, temps, initTemps);74                return BindComInvoke(args, method, binder.CallInfo, isByRef, temps, initTemps);75            }76 77            return base.BindInvoke(binder, args);78        }79 80        private DynamicMetaObject BindComInvoke(DynamicMetaObject[] args, ComMethodDesc method, CallInfo callInfo, bool[] isByRef,81            List<ParameterExpression> temps, List<Expression> initTemps)82        {83            DynamicMetaObject invoke = new ComInvokeBinder(84                callInfo,85                args,86                isByRef,87                IDispatchRestriction(),88                Expression.Constant(method),89                Expression.Property(90                    Helpers.Convert(Expression, typeof(IDispatchComObject)),91                    typeof(IDispatchComObject).GetProperty(nameof(IDispatchComObject.DispatchObject))92                ),93                method94            ).Invoke();95 96            if (temps != null && temps.Count > 0)97            {98                Expression invokeExpression = invoke.Expression;99                Expression call = Expression.Block(invokeExpression.Type, temps, initTemps.Append(invokeExpression));100                invoke = new DynamicMetaObject(call, invoke.Restrictions);101            }102 103            return invoke;104        }105 106        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)107        {108            ComBinder.ComGetMemberBinder comBinder = binder as ComBinder.ComGetMemberBinder;109            bool canReturnCallables = comBinder?._canReturnCallables ?? false;110 111            Requires.NotNull(binder);112 113            // 1. Try methods114            if (_self.TryGetMemberMethod(binder.Name, out ComMethodDesc method))115            {116                if (((method.InvokeKind & INVOKEKIND.INVOKE_PROPERTYGET) ==117                    INVOKEKIND.INVOKE_PROPERTYGET) &&118                    (method.ParamCount == 0))119                {120                    return BindGetMember(method, canReturnCallables);121                }122            }123 124            // 2. Try events125            if (_self.TryGetMemberEvent(binder.Name, out ComEventDesc @event))126            {127                return BindEvent(@event);128            }129 130            // 3. Try methods explicitly by name131            if (_self.TryGetMemberMethodExplicit(binder.Name, out method))132            {133                if (((method.InvokeKind & INVOKEKIND.INVOKE_PROPERTYGET) ==134                    INVOKEKIND.INVOKE_PROPERTYGET) &&135                    (method.ParamCount == 0))136                {137                    return BindGetMember(method, canReturnCallables);138                }139            }140 141            // 4. Fallback142            return base.BindGetMember(binder);143        }144 145        private DynamicMetaObject BindGetMember(ComMethodDesc method, bool canReturnCallables)146        {147            if (method.IsDataMember)148            {149                if (method.ParamCount == 0)150                {151                    return BindComInvoke(DynamicMetaObject.EmptyMetaObjects, method, new CallInfo(0), Array.Empty<bool>(), null, null);152                }153            }154 155            // ComGetMemberBinder does not expect callables. Try to call always.156            if (!canReturnCallables)157            {158                return BindComInvoke(DynamicMetaObject.EmptyMetaObjects, method, new CallInfo(0), Array.Empty<bool>(), null, null);159            }160 161            return new DynamicMetaObject(162                Expression.Call(163                    typeof(ComRuntimeHelpers).GetMethod(nameof(ComRuntimeHelpers.CreateDispCallable)),164                    Helpers.Convert(Expression, typeof(IDispatchComObject)),165                    Expression.Constant(method)166                ),167                IDispatchRestriction()168            );169        }170 171        private DynamicMetaObject BindEvent(ComEventDesc eventDesc)172        {173            // BoundDispEvent CreateComEvent(object rcw, Guid sourceIid, int dispid)174            Expression result =175                Expression.Call(176                    typeof(ComRuntimeHelpers).GetMethod(nameof(ComRuntimeHelpers.CreateComEvent)),177                    ComObject.RcwFromComObject(Expression),178                    Expression.Constant(eventDesc.SourceIID),179                    Expression.Constant(eventDesc.Dispid)180                );181 182            return new DynamicMetaObject(183                result,184                IDispatchRestriction()185            );186        }187 188        public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)189        {190            Requires.NotNull(binder);191 192            if (_self.TryGetGetItem(out ComMethodDesc getItem))193            {194                List<ParameterExpression> temps = new List<ParameterExpression>();195                List<Expression> initTemps = new List<Expression>();196 197                bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(getItem, ref indexes, temps, initTemps);198                return BindComInvoke(indexes, getItem, binder.CallInfo, isByRef, temps, initTemps);199            }200 201            return base.BindGetIndex(binder, indexes);202        }203 204        public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)205        {206            Requires.NotNull(binder);207 208            if (_self.TryGetSetItem(out ComMethodDesc setItem))209            {210                List<ParameterExpression> temps = new List<ParameterExpression>();211                List<Expression> initTemps = new List<Expression>();212 213                bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(setItem, ref indexes, temps, initTemps);214                isByRef = isByRef.AddLast(false);215 216                // Convert the value to the target type217                DynamicMetaObject updatedValue = new DynamicMetaObject(218                    value.CastOrConvertMethodArgument(219                        value.LimitType,220                        setItem.Name,221                        "SetIndex",222                        allowCastingToByRefLikeType: false,223                        temps,224                        initTemps),225                    value.Restrictions);226 227                var result = BindComInvoke(indexes.AddLast(updatedValue), setItem, binder.CallInfo, isByRef, temps, initTemps);228 229                // Make sure to return the value; some languages need it.230                return new DynamicMetaObject(231                    Expression.Block(result.Expression, Expression.Convert(value.Expression, typeof(object))),232                    result.Restrictions233                );234            }235 236            return base.BindSetIndex(binder, indexes, value);237        }238 239        public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)240        {241            Requires.NotNull(binder);242 243            return244                // 1. Check for simple property put245                TryPropertyPut(binder, value) ??246 247                // 2. Check for event handler hookup where the put is dropped248                TryEventHandlerNoop(binder, value) ??249 250                // 3. Fallback251                base.BindSetMember(binder, value);252        }253 254        private DynamicMetaObject TryPropertyPut(SetMemberBinder binder, DynamicMetaObject value)255        {256            bool holdsNull = value.Value == null && value.HasValue;257            if (_self.TryGetPropertySetter(binder.Name, out ComMethodDesc method, value.LimitType, holdsNull) ||258                _self.TryGetPropertySetterExplicit(binder.Name, out method, value.LimitType, holdsNull))259            {260                BindingRestrictions restrictions = IDispatchRestriction();261                Expression dispatch =262                    Expression.Property(263                        Helpers.Convert(Expression, typeof(IDispatchComObject)),264                        typeof(IDispatchComObject).GetProperty(nameof(IDispatchComObject.DispatchObject))265                    );266 267                DynamicMetaObject result = new ComInvokeBinder(268                    new CallInfo(1),269                    new[] { value },270                    new bool[] { false },271                    restrictions,272                    Expression.Constant(method),273                    dispatch,274                    method275                ).Invoke();276 277                // Make sure to return the value; some languages need it.278                return new DynamicMetaObject(279                    Expression.Block(result.Expression, Expression.Convert(value.Expression, typeof(object))),280                    result.Restrictions281                );282            }283 284            return null;285        }286 287        private DynamicMetaObject TryEventHandlerNoop(SetMemberBinder binder, DynamicMetaObject value)288        {289            if (_self.TryGetMemberEvent(binder.Name, out _) && value.LimitType == typeof(BoundDispEvent))290            {291                // Drop the event property set.292                return new DynamicMetaObject(293                    Expression.Constant(null),294                    value.Restrictions.Merge(IDispatchRestriction()).Merge(BindingRestrictions.GetTypeRestriction(value.Expression, typeof(BoundDispEvent)))295                );296            }297 298            return null;299        }300 301        private BindingRestrictions IDispatchRestriction()302        {303            return IDispatchRestriction(Expression, _self.ComTypeDesc);304        }305 306        internal static BindingRestrictions IDispatchRestriction(Expression expr, ComTypeDesc typeDesc)307        {308            return BindingRestrictions.GetTypeRestriction(309                expr, typeof(IDispatchComObject)310            ).Merge(311                BindingRestrictions.GetExpressionRestriction(312                    Expression.Equal(313                        Expression.Property(314                            Helpers.Convert(expr, typeof(IDispatchComObject)),315                            typeof(IDispatchComObject).GetProperty(nameof(IDispatchComObject.ComTypeDesc))316                        ),317                        Expression.Constant(typeDesc)318                    )319                )320            );321        }322 323        protected override ComUnwrappedMetaObject UnwrapSelf()324        {325            return new ComUnwrappedMetaObject(326                ComObject.RcwFromComObject(Expression),327                IDispatchRestriction(),328                _self.RuntimeCallableWrapper329            );330        }331    }332}333