/// <summary> /// Create a stub for the target of the optimized lopop. /// </summary> /// <returns></returns> private Expression MakeIDispatchInvokeTarget() { Debug.Assert(_varEnumSelector.VariantBuilders.Length == _totalExplicitArgs); List <Expression> exprs = new List <Expression> { // // _dispId = ((DispCallable)this).ComMethodDesc.DispId; // Expression.Assign( DispIdVariable, Expression.Property(_method, typeof(ComMethodDesc).GetProperty(nameof(ComMethodDesc.DispId))) ) }; // // _dispParams.rgvararg = RuntimeHelpers.UnsafeMethods.ConvertVariantByrefToPtr(ref _paramVariants._element0) // if (_totalExplicitArgs != 0) { exprs.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.rgvarg)) ), Expression.Call( typeof(UnsafeMethods).GetMethod(nameof(UnsafeMethods.ConvertVariantByrefToPtr)), VariantArray.GetStructField(ParamVariantsVariable, 0) ) ) ); } // // _dispParams.cArgs = <number_of_params>; // exprs.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.cArgs)) ), Expression.Constant(_totalExplicitArgs) ) ); if (_methodDesc.IsPropertyPut) { // // dispParams.cNamedArgs = 1; // dispParams.rgdispidNamedArgs = RuntimeHelpers.UnsafeMethods.GetNamedArgsForPropertyPut() // exprs.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.cNamedArgs)) ), Expression.Constant(1) ) ); exprs.Add( Expression.Assign( PropertyPutDispIdVariable, Expression.Constant(ComDispIds.DISPID_PROPERTYPUT) ) ); exprs.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.rgdispidNamedArgs)) ), Expression.Call( typeof(UnsafeMethods).GetMethod(nameof(UnsafeMethods.ConvertInt32ByrefToPtr)), PropertyPutDispIdVariable ) ) ); } else { // // _dispParams.cNamedArgs = N; // exprs.Add( Expression.Assign( Expression.Field( DispParamsVariable, typeof(ComTypes.DISPPARAMS).GetField(nameof(ComTypes.DISPPARAMS.cNamedArgs)) ), Expression.Constant(_keywordArgNames.Length) ) ); } // // _dispatchObject = _dispatch // _dispatchPointer = Marshal.GetIDispatchForObject(_dispatchObject); // exprs.Add(Expression.Assign(DispatchObjectVariable, _dispatch)); exprs.Add( Expression.Assign( DispatchPointerVariable, Expression.Call( typeof(Marshal).GetMethod(nameof(Marshal.GetIDispatchForObject)), DispatchObjectVariable ) ) ); Expression tryStatements = GenerateTryBlock(); Expression finallyStatements = GenerateFinallyBlock(); exprs.Add(Expression.TryFinally(tryStatements, finallyStatements)); exprs.Add(ReturnValueVariable); var vars = new List <ParameterExpression>(); foreach (VariantBuilder variant in _varEnumSelector.VariantBuilders) { if (variant.TempVariable != null) { vars.Add(variant.TempVariable); } } // If the method returns void, return AutomationNull if (_methodDesc.ReturnType == typeof(void)) { exprs.Add(System.Management.Automation.Language.ExpressionCache.AutomationNullConstant); } return(Expression.Block(vars, exprs)); }
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)); }