internal VarEnumSelector(Type[] explicitArgTypes) { VariantBuilders = new VariantBuilder[explicitArgTypes.Length]; for (int i = 0; i < explicitArgTypes.Length; i++) { VariantBuilders[i] = GetVariantBuilder(explicitArgTypes[i]); } }
private Expression GenerateTryBlock() { // // Declare variables // ParameterExpression excepInfo = Expression.Variable(typeof(ExcepInfo), "excepInfo"); ParameterExpression argErr = Expression.Variable(typeof(uint), "argErr"); ParameterExpression hresult = Expression.Variable(typeof(int), "hresult"); List <Expression> tryStatements = new List <Expression>(); if (_keywordArgNames.Length > 0) { string[] names = _keywordArgNames.AddFirst(_methodDesc.Name); tryStatements.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.rgdispidNamedArgs)) ), Expression.Call(typeof(UnsafeMethods).GetMethod(nameof(UnsafeMethods.GetIdsOfNamedParameters)), DispatchObjectVariable, Expression.Constant(names), DispIdVariable, DispIdsOfKeywordArgsPinnedVariable ) ) ); } // // Marshal the arguments to Variants // // For a call like this: // comObj.Foo(100, 101, 102, x=123, z=125) // DISPPARAMS needs to be setup like this: // cArgs: 5 // cNamedArgs: 2 // rgArgs: 123, 125, 102, 101, 100 // rgdispidNamedArgs: dispid x, dispid z (the dispids of x and z respectively) Expression[] parameters = MakeArgumentExpressions(); int reverseIndex = _varEnumSelector.VariantBuilders.Length - 1; int positionalArgs = _varEnumSelector.VariantBuilders.Length - _keywordArgNames.Length; // args passed by position order and not by name for (int i = 0; i < _varEnumSelector.VariantBuilders.Length; i++, reverseIndex--) { int variantIndex; if (i >= positionalArgs) { // Named arguments are in order at the start of rgArgs variantIndex = i - positionalArgs; } else { // Positional arguments are in reverse order at the tail of rgArgs variantIndex = reverseIndex; } VariantBuilder variantBuilder = _varEnumSelector.VariantBuilders[i]; Expression marshal = variantBuilder.InitializeArgumentVariant( VariantArray.GetStructField(ParamVariantsVariable, variantIndex), parameters[i + 1] ); if (marshal != null) { tryStatements.Add(marshal); } } // // Call Invoke // ComTypes.INVOKEKIND invokeKind; if (_methodDesc.IsPropertyPut) { if (_methodDesc.IsPropertyPutRef) { invokeKind = ComTypes.INVOKEKIND.INVOKE_PROPERTYPUTREF; } else { invokeKind = ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT; } } else { // INVOKE_PROPERTYGET should only be needed for COM objects without typeinfo, where we might have to treat properties as methods invokeKind = ComTypes.INVOKEKIND.INVOKE_FUNC | ComTypes.INVOKEKIND.INVOKE_PROPERTYGET; } MethodCallExpression invoke = Expression.Call( typeof(UnsafeMethods).GetMethod(nameof(UnsafeMethods.IDispatchInvoke)), DispatchPointerVariable, DispIdVariable, Expression.Constant(invokeKind), DispParamsVariable, InvokeResultVariable, excepInfo, argErr ); Expression expr = Expression.Assign(hresult, invoke); tryStatements.Add(expr); // // ComRuntimeHelpers.CheckThrowException(int hresult, ref ExcepInfo excepInfo, ComMethodDesc method, object[] args, uint argErr) List <Expression> args = new List <Expression>(); foreach (Expression parameter in parameters) { args.Add(Expression.TypeAs(parameter, typeof(object))); } expr = Expression.Call( typeof(ComRuntimeHelpers).GetMethod(nameof(ComRuntimeHelpers.CheckThrowException)), hresult, excepInfo, Expression.Constant(_methodDesc, typeof(ComMethodDesc)), Expression.NewArrayInit(typeof(object), args), argErr ); tryStatements.Add(expr); // // _returnValue = (ReturnType)_invokeResult.ToObject(); // Expression invokeResultObject = Expression.Call( InvokeResultVariable, typeof(Variant).GetMethod(nameof(Variant.ToObject))); VariantBuilder[] variants = _varEnumSelector.VariantBuilders; Expression[] parametersForUpdates = MakeArgumentExpressions(); tryStatements.Add(Expression.Assign(ReturnValueVariable, invokeResultObject)); for (int i = 0, n = variants.Length; i < n; i++) { Expression updateFromReturn = variants[i].UpdateFromReturn(parametersForUpdates[i + 1]); if (updateFromReturn != null) { tryStatements.Add(updateFromReturn); } } tryStatements.Add(Expression.Empty()); return(Expression.Block(new[] { excepInfo, argErr, hresult }, tryStatements)); }