示例#1
0
        static Type createDelegate(TypeBuilder tbDelegates, MethodInfo method)
        {
            // Initially based on this: https://blogs.msdn.microsoft.com/joelpob/2004/02/15/creating-delegate-types-via-reflection-emit/

            // Create the delegate type
            TypeAttributes ta = TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.NestedPublic;
            TypeBuilder    tb = tbDelegates.DefineNestedType(method.Name, ta, typeof(MulticastDelegate));
            // Apply [UnmanagedFunctionPointer] using the value from RuntimeClass.defaultCallingConvention
            CustomAttributeBuilder cab = new CustomAttributeBuilder(ciFPAttribute, new object[1] {
                RuntimeClass.defaultCallingConvention
            });

            tb.SetCustomAttribute(cab);

            // Create constructor for the delegate
            MethodAttributes   ma = MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
            ConstructorBuilder cb = tb.DefineConstructor(ma, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) });

            cb.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
            cb.DefineParameter(1, ParameterAttributes.In, "object");
            cb.DefineParameter(2, ParameterAttributes.In, "method");

            // Create Invoke method for the delegate. Appending one more parameter to the start, `[in] IntPtr pThis`
            ParameterInfo[] methodParams = method.GetParameters();
            Type[]          paramTypes   = new Type[methodParams.Length + 1];
            paramTypes[0] = typeof(IntPtr);
            for (int i = 0; i < methodParams.Length; i++)
            {
                ParameterInfo  pi = methodParams[i];
                Type           tp = pi.ParameterType;
                iCustomMarshal cm = pi.customMarshaller();
                if (null != cm)
                {
                    tp = cm.getNativeType(pi);
                }
                paramTypes[i + 1] = tp;
            }

            var mb = tb.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(int), paramTypes);

            mb.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
            defineDelegateParameters(mb, methodParams);
            // The method has no code, it's pure virtual.

            return(tb.CreateType());
        }
        static Type createDelegate(DelegatesBuilder builder, MethodInfo method)
        {
            // Initially based on this: https://blogs.msdn.microsoft.com/joelpob/2004/02/15/creating-delegate-types-via-reflection-emit/

            // Create the delegate type
            TypeBuilder tb = builder.defineMulticastDelegate(method);

            // Apply [UnmanagedFunctionPointer] using the value from RuntimeClass.defaultCallingConvention
            CustomAttributeBuilder cab = new CustomAttributeBuilder(ciFPAttribute, new object[1] {
                RuntimeClass.defaultCallingConvention
            });

            tb.SetCustomAttribute(cab);

            // Create constructor for the delegate
            MethodAttributes   ma = MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
            ConstructorBuilder cb = tb.DefineConstructor(ma, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) });

            cb.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
            cb.DefineParameter(1, ParameterAttributes.In, "object");
            cb.DefineParameter(2, ParameterAttributes.In, "method");

            // Create Invoke method for the delegate. Appending one more parameter to the start, `[in] IntPtr pThis`
            ParameterInfo[]      methodParams      = method.GetParameters();
            int                  nativeParamsCount = methodParams.Length + 1;
            int                  retValIndex       = -1;
            RetValIndexAttribute rvi = method.GetCustomAttribute <RetValIndexAttribute>();

            if (rvi != null)
            {
                retValIndex = rvi.index;
                nativeParamsCount++;
            }

            Type[] paramTypes = new Type[nativeParamsCount];
            paramTypes[0] = typeof(IntPtr);
            int iNativeParam = 1;

            for (int i = 0; i < methodParams.Length; i++, iNativeParam++)
            {
                if (i == retValIndex)
                {
                    retValIndex = -1;
                    i--;
                    paramTypes[iNativeParam] = nativeRetValArgType(method);
                    continue;
                }

                ParameterInfo  pi = methodParams[i];
                Type           tp = pi.ParameterType;
                iCustomMarshal cm = pi.customMarshaller();
                if (null != cm)
                {
                    tp = cm.getNativeType(pi);
                }
                paramTypes[iNativeParam] = tp;
            }
            if (retValIndex >= 0)
            {
                // User has specified [RetValIndex] value after the rest of the parameters
                paramTypes[iNativeParam] = nativeRetValArgType(method);
            }

            Type returnType;

            if (method.ReturnType != typeof(IntPtr) || null != rvi)
            {
                returnType = typeof(int);
            }
            else
            {
                returnType = typeof(IntPtr);
            }

            var mb = tb.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, returnType, paramTypes);

            mb.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);

            mb.DefineParameter(1, ParameterAttributes.In, "pThis");

            iNativeParam = 2;               // 2 because the first one is native this pointer, and MethodBuilder.DefineParameter API uses 1-based indices, the number 0 represents the return value of the method.
            retValIndex  = rvi?.index ?? -1;
            for (int i = 0; i < methodParams.Length; i++, iNativeParam++)
            {
                if (i == retValIndex)
                {
                    retValIndex = -1;
                    i--;
                    mb.DefineParameter(iNativeParam, ParameterAttributes.Out, "retVal");
                    continue;
                }
                ParameterInfo    pi = methodParams[i];
                ParameterBuilder pb = mb.DefineParameter(iNativeParam, pi.Attributes, pi.Name);
                ParamsMarshalling.buildDelegateParam(pi, pb, rvi?.index);
            }
            if (retValIndex >= 0)
            {
                // User has specified [RetValIndex] value after the rest of the parameters
                mb.DefineParameter(iNativeParam, ParameterAttributes.Out, "retVal");
            }

            // The method has no code, it's pure virtual.
            return(tb.CreateType());
        }