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()); }