Esempio n. 1
0
            void iMethodPrefab.emitMethod(MethodBuilder mb, FieldBuilder field, CustomConventionsAttribute customConventions)
            {
                ILGenerator il = mb.GetILGenerator();

                var prologue = customConventions?.prologue;

                if (null != prologue)
                {
                    il.EmitCall(OpCodes.Call, prologue, null);
                }

                // Load the delegate from this
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, field);

                // Load arguments
                for (int i = 0; i < method.GetParameters().Length; i++)
                {
                    il.loadArg(i + 1);
                }

                // Call the delegate
                MethodInfo invoke = field.FieldType.GetMethod("Invoke");

                il.Emit(OpCodes.Callvirt, invoke);
                il.Emit(OpCodes.Ret);
            }
Esempio n. 2
0
            void iMethodPrefab.emitMethod(MethodBuilder mb, FieldBuilder field, CustomConventionsAttribute customConventions)
            {
                ParameterInfo[] parameters = method.GetParameters();

                // Method body
                ILGenerator il = mb.GetILGenerator();

                var prologue = customConventions?.prologue;

                if (null != prologue)
                {
                    il.EmitCall(OpCodes.Call, prologue, null);
                }

                // Load the delegate from this
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, field);
                // Load nativePointer from the base class
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, fiNativePointer);
                // Load arguments
                for (int i = 0; i < parameters.Length; i++)
                {
                    il.loadArg(i + 1);
                }
                // Call the delegate
                MethodInfo invoke = field.FieldType.GetMethod("Invoke");

                il.Emit(OpCodes.Callvirt, invoke);

                if (method.ReturnType == typeof(void))
                {
                    MethodInfo mi = customConventions?.throwException ?? miThrow;
                    // Call ErrorCodes.throwForHR
                    il.EmitCall(OpCodes.Call, mi, null);
                }
                else if (method.ReturnType == typeof(bool))
                {
                    MethodInfo mi = customConventions?.throwAndReturnBool ?? miThrowRetBool;
                    il.EmitCall(OpCodes.Call, mi, null);
                }

                il.Emit(OpCodes.Ret);
            }
Esempio n. 3
0
            /// <summary>Build the prefab, it contains 2 expressions that need late binding, `tNativeDelegate nativeDelegate`, and `IntPtr nativeComPointer`, represented by paramNativeObject constant object.</summary>
            public CustomMarshallerMethod(MethodInfo mi, Type tNativeDelegate, int idx, CustomConventionsAttribute customConventions)
            {
                method               = mi;
                methodIndex          = idx;
                this.tNativeDelegate = tNativeDelegate;
                eNativeDelegate      = Expression.Parameter(tNativeDelegate, "nativeDelegate");
                ParameterInfo[] parameters = mi.GetParameters();
                managedParameters = parameters.Select(pi => Expression.Parameter(pi.ParameterType, pi.Name)).ToArray();
                // tDelegate = Expression.GetDelegateType( parameters.Select( pi => pi.ParameterType ).Concat( new Type[ 1 ] { mi.ReturnType } ).ToArray() );
                // Expression.GetDelegateType doesn't work on desktop .NET, crashes later saying "Unable to make a reference to a transient module from a non-transient module."
                // No big deal, creating them manually with emitManagedDelegate so they're in the same assembly.

                List <ParameterExpression> localVars = new List <ParameterExpression>();

                int nativeParamsCount            = parameters.Length + 1;
                int retValIndex                  = -1;
                ParameterExpression nativeRetVal = null;

                if (mi.GetCustomAttribute <RetValIndexAttribute>() is RetValIndexAttribute rvi)
                {
                    nativeParamsCount++;
                    retValIndex = rvi.index;
                    if (mi.ReturnType.IsInterface)
                    {
                        nativeRetVal = Expression.Parameter(typeof(IntPtr), "retValObj");
                    }
                    else
                    {
                        nativeRetVal = Expression.Parameter(mi.ReturnType, "retVal");
                    }
                    localVars.Add(nativeRetVal);
                }

                Expression[] nativeParameters = new Expression[nativeParamsCount];
                nativeParameters[0] = paramNativeObject;
                int iNative             = 1;
                List <Expression> after = new List <Expression>();

                for (int i = 0; i < parameters.Length; i++, iNative++)
                {
                    if (i == retValIndex)
                    {
                        nativeParameters[iNative] = nativeRetVal;
                        retValIndex = -1;
                        i--;
                        continue;
                    }

                    var pi = parameters[i];
                    var cm = pi.customMarshaller();
                    if (null == cm)
                    {
                        nativeParameters[iNative] = managedParameters[i];
                        continue;
                    }
                    var customExpressions = cm.native(managedParameters[i], !pi.IsOut);
                    nativeParameters[iNative] = customExpressions.argument;
                    if (null != customExpressions.variable)
                    {
                        localVars.Add(customExpressions.variable);
                    }
                    if (null != customExpressions.after)
                    {
                        after.Add(customExpressions.after);
                    }
                }

                if (retValIndex >= 0)
                {
                    // User has specified [RetValIndex] value after the rest of the parameters
                    nativeParameters[iNative] = nativeRetVal;
                }

                List <Expression> block          = new List <Expression>();
                MethodInfo        miInvokeNative = eNativeDelegate.Type.GetMethod("Invoke");
                Expression        eCall          = Expression.Call(eNativeDelegate, miInvokeNative, nativeParameters);
                List <Expression> blockEntries   = new List <Expression>();

                if (null != nativeRetVal)
                {
                    // int hr = nativeCall( ... )
                    ParameterExpression hr = Expression.Variable(typeof(int), "hr");
                    localVars.Add(hr);
                    block.Add(Expression.Assign(hr, eCall));

                    // Append after expressions, if any
                    block.AddRange(after);

                    // ErrorCodes.throwForHR( hr )
                    MethodInfo mit = customConventions?.throwException ?? miThrow;
                    block.Add(Expression.Call(mit, hr));

                    LabelTarget returnTarget = Expression.Label(method.ReturnType);

                    if (mi.ReturnType.IsInterface)
                    {
                        // return NativeWrapper.wrap<mi.ReturnType>( nativeRetVal )
                        MethodInfo miWrapNative = typeof(NativeWrapper)
                                                  .GetMethod("wrap", new Type[1] {
                            typeof(IntPtr)
                        })
                                                  .MakeGenericMethod(mi.ReturnType);

                        block.Add(Expression.Return(returnTarget, Expression.Call(miWrapNative, nativeRetVal)));
                    }
                    else
                    {
                        // return nativeRetVal
                        block.Add(Expression.Return(returnTarget, nativeRetVal));
                    }
                    block.Add(Expression.Label(returnTarget, Expression.Default(method.ReturnType)));
                }
                else if (mi.ReturnType == typeof(void))
                {
                    MethodInfo mit = customConventions?.throwException ?? miThrow;
                    block.Add(Expression.Call(mit, eCall));
                    block.AddRange(after);
                }
                else if (mi.ReturnType == typeof(int))
                {
                    if (localVars.Count <= 0 && after.Count <= 0)
                    {
                        methodExpression = eCall;
                        return;
                    }

                    ParameterExpression hr = Expression.Variable(typeof(int), "hr");
                    localVars.Add(hr);
                    block.Add(Expression.Assign(hr, eCall));
                    block.AddRange(after);
                    LabelTarget returnTarget = Expression.Label(typeof(int));
                    block.Add(Expression.Return(returnTarget, hr));
                    block.Add(Expression.Label(returnTarget, Expression.Constant(IUnknown.E_UNEXPECTED)));
                }
                else if (mi.ReturnType == typeof(IntPtr))
                {
                    if (localVars.Count <= 0 && after.Count <= 0)
                    {
                        methodExpression = eCall;
                        return;
                    }

                    ParameterExpression resultVar = Expression.Variable(typeof(IntPtr), "resultPtr");
                    localVars.Add(resultVar);
                    block.Add(Expression.Assign(resultVar, eCall));
                    block.AddRange(after);
                    LabelTarget returnTarget = Expression.Label(typeof(IntPtr));
                    block.Add(Expression.Return(returnTarget, resultVar));
                    block.Add(Expression.Label(returnTarget, Expression.Constant(IntPtr.Zero)));
                }
                else if (mi.ReturnType == typeof(bool))
                {
                    ParameterExpression resultVar = Expression.Variable(typeof(int), "hr");
                    localVars.Add(resultVar);
                    block.Add(Expression.Assign(resultVar, eCall));
                    block.AddRange(after);
                    LabelTarget returnTarget = Expression.Label(typeof(bool));
                    var         mit          = customConventions?.throwAndReturnBool ?? miThrowRetBool;
                    block.Add(Expression.Return(returnTarget, Expression.Call(mit, resultVar)));
                    block.Add(Expression.Label(returnTarget, MiscUtils.eFalse));
                }
                else
                {
                    throw new ArgumentException($"Unsupported return type { mi.ReturnType.FullName }, must be int, void, bool or pointer");
                }

                methodExpression = Expression.Block(localVars, block);
            }