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)); } }
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); }
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; }
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)); }
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)); }
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)); } }
public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMethodDesc method) { return new DispCallable(dispatch, method.Name, method.DispId); }
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); }
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); } }
internal bool TryGetMemberMethod(string name, out ComMethodDesc method) { EnsureScanDefinedMethods(); return(_comTypeDesc.TryGetFunc(name, out method)); }
internal void AddFunc(string name, ComMethodDesc method) { name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture); lock (Funcs) { Funcs[name] = method; } }
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); }
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); }
public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMethodDesc method) { return(new DispCallable(dispatch, method.Name, method.DispId)); }
internal void AddPutRef(string name, ComMethodDesc method) { name = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture); lock (_putRefs) { _putRefs[name] = method; } }