Beispiel #1
0
 internal bool TryGetFunc(string name, out ComMethodDesc method)
 {
     name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
     if (Funcs.ContainsKey(name))
     {
         method = Funcs[name] as ComMethodDesc;
         return true;
     }
     method = null;
     return false;
 }
        internal bool TryGetPropertySetter(string name, out ComMethodDesc method, Type limitType, bool holdsNull)
        {
            EnsureScanDefinedMethods();

            if (ComBinderHelpers.PreferPut(limitType, holdsNull))
            {
                return(_comTypeDesc.TryGetPut(name, out method) ||
                       _comTypeDesc.TryGetPutRef(name, out method));
            }
            else
            {
                return(_comTypeDesc.TryGetPutRef(name, out method) ||
                       _comTypeDesc.TryGetPut(name, out method));
            }
        }
Beispiel #3
0
        private bool SlowTryGetSetItem(out ComMethodDesc value)
        {
            EnsureScanDefinedMethods();

            ComMethodDesc methodDesc = _comTypeDesc.SetItem;

            // Without type information, we really don't know whether or not we have a property setter.
            if (methodDesc == null)
            {
                string name = "[PROPERTYPUT, DISPID(0)]";

                _comTypeDesc.EnsureSetItem(new ComMethodDesc(name, ComDispIds.DISPID_VALUE, ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT));
                methodDesc = _comTypeDesc.SetItem;
            }

            value = methodDesc;
            return(true);
        }
Beispiel #4
0
        private static void ThrowWrappedInvocationException(ComMethodDesc method, Exception parameterException)
        {
            if ((method.InvokeKind & ComTypes.INVOKEKIND.INVOKE_FUNC) ==
                ComTypes.INVOKEKIND.INVOKE_FUNC)
            {
                throw new MethodException(parameterException.Message, parameterException);
            }

            if (method.IsPropertyGet)
            {
                throw new GetValueInvocationException(parameterException.Message, parameterException);
            }

            if (method.IsPropertyPut || method.IsPropertyPutRef)
            {
                throw new SetValueInvocationException(parameterException.Message, parameterException);
            }

            throw parameterException;
        }
Beispiel #5
0
        public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
        {
            Requires.NotNull(binder, nameof(binder));

            ComMethodDesc method = null;

            // See if this is actually a property set
            ComBinder.ComInvokeMemberBinder comInvokeBinder = binder as ComBinder.ComInvokeMemberBinder;
            if ((comInvokeBinder != null) && (comInvokeBinder.IsPropertySet))
            {
                DynamicMetaObject value = args[args.Length - 1];

                bool holdsNull = value.Value == null && value.HasValue;
                if (!_self.TryGetPropertySetter(binder.Name, out method, value.LimitType, holdsNull))
                {
                    _self.TryGetPropertySetterExplicit(binder.Name, out method, value.LimitType, holdsNull);
                }
            }

            // Otherwise, try property get
            if (method == null)
            {
                if (!_self.TryGetMemberMethod(binder.Name, out method))
                {
                    _self.TryGetMemberMethodExplicit(binder.Name, out method);
                }
            }

            if (method != null)
            {
                List <ParameterExpression> temps     = new List <ParameterExpression>();
                List <Expression>          initTemps = new List <Expression>();

                bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(method, ref args, temps, initTemps);
                return(BindComInvoke(args, method, binder.CallInfo, isByRef, temps, initTemps));
            }

            return(base.BindInvokeMember(binder, args));
        }
Beispiel #6
0
        internal bool TryGetMemberMethodExplicit(string name, out ComMethodDesc method)
        {
            EnsureScanDefinedMethods();

            int hresult = GetIDsOfNames(DispatchObject, name, out int dispId);

            if (hresult == ComHresults.S_OK)
            {
                ComMethodDesc cmd = new ComMethodDesc(name, dispId, ComTypes.INVOKEKIND.INVOKE_FUNC);
                _comTypeDesc.AddFunc(name, cmd);
                method = cmd;
                return(true);
            }

            if (hresult == ComHresults.DISP_E_UNKNOWNNAME)
            {
                method = null;
                return(false);
            }

            throw Error.CouldNotGetDispId(name, string.Format(CultureInfo.InvariantCulture, "0x{0:X})", hresult));
        }
Beispiel #7
0
        internal bool TryGetPropertySetterExplicit(string name, out ComMethodDesc method, Type limitType, bool holdsNull)
        {
            EnsureScanDefinedMethods();

            int dispId;
            int hresult = GetIDsOfNames(DispatchObject, name, out dispId);

            if (hresult == ComHresults.S_OK)
            {
                // we do not know whether we have put or putref here
                // and we will not guess and pretend we found both.
                ComMethodDesc put = new ComMethodDesc(name, dispId, ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT);
                _comTypeDesc.AddPut(name, put);

                ComMethodDesc putref = new ComMethodDesc(name, dispId, ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF);
                _comTypeDesc.AddPutRef(name, putref);

                if (ComBinderHelpers.PreferPut(limitType, holdsNull))
                {
                    method = put;
                }
                else
                {
                    method = putref;
                }

                return(true);
            }
            else if (hresult == ComHresults.DISP_E_UNKNOWNNAME)
            {
                method = null;
                return(false);
            }
            else
            {
                throw Error.CouldNotGetDispId(name, string.Format(CultureInfo.InvariantCulture, "0x{0:X})", hresult));
            }
        }
Beispiel #8
0
 public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMethodDesc method)
 {
     return new DispCallable(dispatch, method.Name, method.DispId);
 }
Beispiel #9
0
 internal void EnsureSetItem(ComMethodDesc candidate)
 {
     Interlocked.CompareExchange(ref _setItem, candidate, null);
 }
        // this helper prepares arguments for COM binding by transforming ByVal StongBox arguments
        // into ByRef expressions that represent the argument's Value fields.
        internal static bool[] ProcessArgumentsForCom(ComMethodDesc method, ref DynamicMetaObject[] args,
                                                      List <ParameterExpression> temps, List <Expression> initTemps)
        {
            Debug.Assert(args != null);

            DynamicMetaObject[] newArgs = new DynamicMetaObject[args.Length];
            bool[] isByRefArg           = new bool[args.Length];

            for (int i = 0; i < args.Length; i++)
            {
                DynamicMetaObject curArgument = args[i];

                // set new arg infos to their original values or set default ones
                // we will do this fixup early so that we can assume we always have
                // arginfos in COM binder.

                if (IsByRef(curArgument))
                {
                    newArgs[i]    = curArgument;
                    isByRefArg[i] = true;
                }
                else
                {
                    if (IsPSReferenceArg(curArgument))
                    {
                        var restrictions = curArgument.Restrictions.Merge(
                            GetTypeRestrictionForDynamicMetaObject(curArgument)
                            );

                        // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast.
                        Expression boxedValueAccessor = Expression.Property(
                            Helpers.Convert(
                                curArgument.Expression,
                                curArgument.LimitType
                                ),
                            curArgument.LimitType.GetProperty("Value")
                            );

                        PSReference value      = curArgument.Value as PSReference;
                        object      boxedValue = value != null ? value.Value : null;

                        newArgs[i] = new DynamicMetaObject(
                            boxedValueAccessor,
                            restrictions,
                            boxedValue
                            );

                        isByRefArg[i] = true;
                    }
                    else
                    {
                        if ((method.ParameterInformation != null) && (i < method.ParameterInformation.Length))
                        {
                            newArgs[i] = new DynamicMetaObject(curArgument.CastOrConvertMethodArgument(
                                                                   method.ParameterInformation[i].parameterType,
                                                                   i.ToString(CultureInfo.InvariantCulture),
                                                                   method.Name,
                                                                   temps,
                                                                   initTemps), curArgument.Restrictions);
                        }
                        else
                        {
                            newArgs[i] = curArgument;
                        }

                        isByRefArg[i] = false;
                    }
                }
            }

            args = newArgs;
            return(isByRefArg);
        }
Beispiel #11
0
        private void EnsureScanDefinedMethods()
        {
            if (_comTypeDesc != null && _comTypeDesc.Funcs != null)
            {
                return;
            }

            ComTypes.ITypeInfo typeInfo = ComRuntimeHelpers.GetITypeInfoFromIDispatch(DispatchObject, true);
            if (typeInfo == null)
            {
                _comTypeDesc = ComTypeDesc.CreateEmptyTypeDesc();
                return;
            }

            ComTypes.TYPEATTR typeAttr = ComRuntimeHelpers.GetTypeAttrForTypeInfo(typeInfo);

            if (_comTypeDesc == null)
            {
                lock (s_cacheComTypeDesc)
                {
                    if (s_cacheComTypeDesc.TryGetValue(typeAttr.guid, out _comTypeDesc) == true &&
                        _comTypeDesc.Funcs != null)
                    {
                        return;
                    }
                }
            }

            if (typeAttr.typekind == ComTypes.TYPEKIND.TKIND_INTERFACE)
            {
                // We have typeinfo for custom interface. Get typeinfo for Dispatch interface.
                typeInfo = ComTypeInfo.GetDispatchTypeInfoFromCustomInterfaceTypeInfo(typeInfo);
                typeAttr = ComRuntimeHelpers.GetTypeAttrForTypeInfo(typeInfo);
            }

            if (typeAttr.typekind == ComTypes.TYPEKIND.TKIND_COCLASS)
            {
                // We have typeinfo for the COClass.  Find the default interface and get typeinfo for default interface.
                typeInfo = ComTypeInfo.GetDispatchTypeInfoFromCoClassTypeInfo(typeInfo);
                typeAttr = ComRuntimeHelpers.GetTypeAttrForTypeInfo(typeInfo);
            }

            ComTypeDesc typeDesc = ComTypeDesc.FromITypeInfo(typeInfo, typeAttr);

            ComMethodDesc getItem = null;
            ComMethodDesc setItem = null;
            Hashtable     funcs   = new Hashtable(typeAttr.cFuncs);
            Hashtable     puts    = new Hashtable();
            Hashtable     putrefs = new Hashtable();

            for (int definedFuncIndex = 0; definedFuncIndex < typeAttr.cFuncs; definedFuncIndex++)
            {
                IntPtr funcDescHandleToRelease = IntPtr.Zero;

                try
                {
                    ComTypes.FUNCDESC funcDesc;
                    GetFuncDescForDescIndex(typeInfo, definedFuncIndex, out funcDesc, out funcDescHandleToRelease);

                    if ((funcDesc.wFuncFlags & (int)ComTypes.FUNCFLAGS.FUNCFLAG_FRESTRICTED) != 0)
                    {
                        // This function is not meant for the script user to use.
                        continue;
                    }

                    ComMethodDesc method = new ComMethodDesc(typeInfo, funcDesc);
                    string        name   = method.Name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);

                    if ((funcDesc.invkind & ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT) != 0)
                    {
                        // If there is a getter for this put, use that ReturnType as the
                        // PropertyType.
                        if (funcs.ContainsKey(name))
                        {
                            method.InputType = ((ComMethodDesc)funcs[name]).ReturnType;
                        }

                        puts.Add(name, method);

                        // for the special dispId == 0, we need to store
                        // the method descriptor for the Do(SetItem) binder.
                        if (method.DispId == ComDispIds.DISPID_VALUE && setItem == null)
                        {
                            setItem = method;
                        }

                        continue;
                    }

                    if ((funcDesc.invkind & ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF) != 0)
                    {
                        // If there is a getter for this put, use that ReturnType as the
                        // PropertyType.
                        if (funcs.ContainsKey(name))
                        {
                            method.InputType = ((ComMethodDesc)funcs[name]).ReturnType;
                        }

                        putrefs.Add(name, method);
                        // for the special dispId == 0, we need to store
                        // the method descriptor for the Do(SetItem) binder.
                        if (method.DispId == ComDispIds.DISPID_VALUE && setItem == null)
                        {
                            setItem = method;
                        }

                        continue;
                    }

                    if (funcDesc.memid == ComDispIds.DISPID_NEWENUM)
                    {
                        funcs.Add("GETENUMERATOR", method);
                        continue;
                    }

                    // If there is a setter for this put, update the InputType from our
                    // ReturnType.
                    if (puts.ContainsKey(name))
                    {
                        ((ComMethodDesc)puts[name]).InputType = method.ReturnType;
                    }

                    if (putrefs.ContainsKey(name))
                    {
                        ((ComMethodDesc)putrefs[name]).InputType = method.ReturnType;
                    }

                    funcs.Add(name, method);

                    // for the special dispId == 0, we need to store the method descriptor
                    // for the Do(GetItem) binder.
                    if (funcDesc.memid == ComDispIds.DISPID_VALUE)
                    {
                        getItem = method;
                    }
                }
                finally
                {
                    if (funcDescHandleToRelease != IntPtr.Zero)
                    {
                        typeInfo.ReleaseFuncDesc(funcDescHandleToRelease);
                    }
                }
            }

            lock (s_cacheComTypeDesc)
            {
                ComTypeDesc cachedTypeDesc;
                if (s_cacheComTypeDesc.TryGetValue(typeAttr.guid, out cachedTypeDesc))
                {
                    _comTypeDesc = cachedTypeDesc;
                }
                else
                {
                    _comTypeDesc = typeDesc;
                    s_cacheComTypeDesc.Add(typeAttr.guid, _comTypeDesc);
                }

                _comTypeDesc.Funcs   = funcs;
                _comTypeDesc.Puts    = puts;
                _comTypeDesc.PutRefs = putrefs;
                _comTypeDesc.EnsureGetItem(getItem);
                _comTypeDesc.EnsureSetItem(setItem);
            }
        }
Beispiel #12
0
 internal bool TryGetMemberMethod(string name, out ComMethodDesc method)
 {
     EnsureScanDefinedMethods();
     return(_comTypeDesc.TryGetFunc(name, out method));
 }
Beispiel #13
0
 internal void AddFunc(string name, ComMethodDesc method)
 {
     name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
     lock (Funcs)
     {
         Funcs[name] = method;
     }
 }
Beispiel #14
0
 internal void EnsureSetItem(ComMethodDesc candidate)
 {
     Interlocked.CompareExchange(ref _setItem, candidate, null);
 }
Beispiel #15
0
        public static void CheckThrowException(int hresult, ref ExcepInfo excepInfo, ComMethodDesc method, object[] args, uint argErr)
        {
            if (ComHresults.IsSuccess(hresult))
            {
                return;
            }
            Exception parameterException = null;

            switch (hresult)
            {
            case ComHresults.DISP_E_BADPARAMCOUNT:
                // The number of elements provided to DISPPARAMS is different from the number of arguments
                // accepted by the method or property.
                parameterException = Error.DispBadParamCount(method.Name, args.Length - 1);
                ThrowWrappedInvocationException(method, parameterException);
                break;

            case ComHresults.DISP_E_BADVARTYPE:
                //One of the arguments in rgvarg is not a valid variant type.
                break;

            case ComHresults.DISP_E_EXCEPTION:
                // The application needs to raise an exception. In this case, the structure passed in pExcepInfo
                // should be filled in.
                throw excepInfo.GetException();

            case ComHresults.DISP_E_MEMBERNOTFOUND:
                // The requested member does not exist, or the call to Invoke tried to set the value of a
                // read-only property.
                throw Error.DispMemberNotFound(method.Name);

            case ComHresults.DISP_E_NONAMEDARGS:
                // This implementation of IDispatch does not support named arguments.
                throw Error.DispNoNamedArgs(method.Name);

            case ComHresults.DISP_E_OVERFLOW:
                // One of the arguments in rgvarg could not be coerced to the specified type.
                throw Error.DispOverflow(method.Name);

            case ComHresults.DISP_E_PARAMNOTFOUND:
                // One of the parameter DISPIDs does not correspond to a parameter on the method. In this case,
                // puArgErr should be set to the first argument that contains the error.
                break;

            case ComHresults.DISP_E_TYPEMISMATCH:
                // The index within rgvarg of the first parameter with the incorrect
                // type is returned in the puArgErr parameter.
                //
                // But: Arguments are stored in pDispParams->rgvarg in reverse order, so the first
                // parameter is the one with the highest index in the array
                // https://msdn.microsoft.com/library/aa912367.aspx
                argErr = ((uint)args.Length) - argErr - 2;

                // One or more of the arguments could not be coerced.

                Type destinationType = null;
                if (argErr >= method.ParameterInformation.Length)
                {
                    destinationType = method.InputType;
                }
                else
                {
                    destinationType = method.ParameterInformation[argErr].parameterType;
                }

                object originalValue = args[argErr + 1];

                // If this is a put, use the InputType and the last argument
                if (method.IsPropertyPut || method.IsPropertyPutRef)
                {
                    destinationType = method.InputType;
                    originalValue   = args[args.Length - 1];
                }

                string originalValueString = originalValue.ToString();
                string originalTypeName    = Microsoft.PowerShell.ToStringCodeMethods.Type(originalValue.GetType(), true);

                // ByRef arguments should be displayed in the error message as a PSReference
                if (destinationType == typeof(object) && method.ParameterInformation[argErr].isByRef)
                {
                    destinationType = typeof(PSReference);
                }

                string destinationTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(destinationType, true);

                parameterException = Error.DispTypeMismatch(method.Name, originalValueString, originalTypeName, destinationTypeName);
                ThrowWrappedInvocationException(method, parameterException);
                break;

            case ComHresults.DISP_E_UNKNOWNINTERFACE:
                // The interface identifier passed in riid is not IID_NULL.
                break;

            case ComHresults.DISP_E_UNKNOWNLCID:
                // The member being invoked interprets string arguments according to the LCID, and the
                // LCID is not recognized.
                break;

            case ComHresults.DISP_E_PARAMNOTOPTIONAL:
                // A required parameter was omitted.
                throw Error.DispParamNotOptional(method.Name);
            }

            Marshal.ThrowExceptionForHR(hresult);
        }
Beispiel #16
0
        public static void CheckThrowException(int hresult, ref ExcepInfo excepInfo, ComMethodDesc method, object[] args, uint argErr)
        {
            if (Utils.Succeeded(hresult))
            {
                return;
            }

            Exception parameterException = null;

            switch (hresult)
            {
                case ComHresults.DISP_E_BADPARAMCOUNT:
                    // The number of elements provided to DISPPARAMS is different from the number of arguments 
                    // accepted by the method or property.

                    parameterException = Error.DispBadParamCount(method.Name, args.Length - 1);
                    ThrowWrappedInvocationException(method, parameterException);
                    break;

                case ComHresults.DISP_E_BADVARTYPE:
                    //One of the arguments in rgvarg is not a valid variant type.
                    break;

                case ComHresults.DISP_E_EXCEPTION:
                    // The application needs to raise an exception. In this case, the structure passed in pExcepInfo 
                    // should be filled in.
                    throw excepInfo.GetException();

                case ComHresults.DISP_E_MEMBERNOTFOUND:
                    // The requested member does not exist, or the call to Invoke tried to set the value of a 
                    // read-only property.
                    throw Error.DispMemberNotFound(method.Name);

                case ComHresults.DISP_E_NONAMEDARGS:
                    // This implementation of IDispatch does not support named arguments.
                    throw Error.DispNoNamedArgs(method.Name);

                case ComHresults.DISP_E_OVERFLOW:
                    // One of the arguments in rgvarg could not be coerced to the specified type.
                    throw Error.DispOverflow(method.Name);

                case ComHresults.DISP_E_PARAMNOTFOUND:
                    break;

                case ComHresults.DISP_E_TYPEMISMATCH:
                    // The index within rgvarg of the first parameter with the incorrect
                    // type is returned in the puArgErr parameter.
                    //
                    // But: Arguments are stored in pDispParams->rgvarg in reverse order, so the first
                    // parameter is the one with the highest index in the array
                    // http://msdn.microsoft.com/en-us/library/aa912367.aspx
                    argErr = ((uint)args.Length) - argErr - 2;


                    // One or more of the arguments could not be coerced.

                    Type destinationType = null;
                    if (argErr >= method.ParameterInformation.Length)
                    {
                        destinationType = method.InputType;
                    }
                    else
                    {
                        destinationType = method.ParameterInformation[argErr].parameterType;
                    }
                    object originalValue = args[argErr + 1];

                    // If this is a put, use the InputType and the last argument
                    if (method.IsPropertyPut || method.IsPropertyPutRef)
                    {
                        destinationType = method.InputType;
                        originalValue = args[args.Length - 1];
                    }

                    string originalValueString = originalValue.ToString();
                    string originalTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(originalValue.GetType(), true);

                    // ByRef arguments should be displayed in the error message as a PSReference
                    if (destinationType == typeof(Object) && method.ParameterInformation[argErr].isByRef)
                    {
                        destinationType = typeof(PSReference);
                    }

                    string destinationTypeName = Microsoft.PowerShell.ToStringCodeMethods.Type(destinationType, true);

                    parameterException = Error.DispTypeMismatch(method.Name, originalValueString, originalTypeName, destinationTypeName);
                    ThrowWrappedInvocationException(method, parameterException);
                    break;

                case ComHresults.DISP_E_UNKNOWNINTERFACE:
                    // The interface identifier passed in riid is not IID_NULL.
                    break;

                case ComHresults.DISP_E_UNKNOWNLCID:
                    // The member being invoked interprets string arguments according to the LCID, and the 
                    // LCID is not recognized.
                    break;

                case ComHresults.DISP_E_PARAMNOTOPTIONAL:
                    // A required parameter was omitted.
                    throw Error.DispParamNotOptional(method.Name);
            }

            Marshal.ThrowExceptionForHR(hresult);
        }
Beispiel #17
0
        private static void ThrowWrappedInvocationException(ComMethodDesc method, Exception parameterException)
        {
            if ((method.InvokeKind & ComTypes.INVOKEKIND.INVOKE_FUNC) ==
                ComTypes.INVOKEKIND.INVOKE_FUNC)
            {
                throw new MethodException(parameterException.Message, parameterException);
            }

            if (method.IsPropertyGet)
            {
                throw new GetValueInvocationException(parameterException.Message, parameterException);
            }

            if (method.IsPropertyPut || method.IsPropertyPutRef)
            {
                throw new SetValueInvocationException(parameterException.Message, parameterException);
            }

            throw parameterException;
        }
Beispiel #18
0
 public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMethodDesc method)
 {
     return(new DispCallable(dispatch, method.Name, method.DispId));
 }
Beispiel #19
0
 internal void AddPutRef(string name, ComMethodDesc method)
 {
     name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
     lock (_putRefs)
     {
         _putRefs[name] = method;
     }
 }