static Type EmitWrapper(Type delegateType)
{
//
// define class
//
// public class NativeDelegateWrapperXXX : NativeDelegateWrapper
//
TypeBuilder tb = moduleBuilder.DefineType(
String.Format("NativeDelegateWrapper{0}", sequence++),
TypeAttributes.Public,
typeof (NativeDelegateWrapper)
);
MethodInfo method = delegateType.GetMethod("Invoke");
ParameterInfo[] pi = method.GetParameters();
var parameterTypes = new Type[pi.Length];
// The icall's parameters are prefixed with an IntPtr "context" parameter.
var icallParameterTypes = new Type[pi.Length + 1];
icallParameterTypes[0] = typeof (IntPtr);
for (int i = 0; i < pi.Length; i++)
{
parameterTypes[i] = pi[i].ParameterType;
if (parameterTypes[i].IsByRef)
throw new NotSupportedException("ByRef parameters are not supported");
icallParameterTypes[i + 1] = parameterTypes[i];
}
//
// define ctor
//
// public .ctor(IntPtr context)
//
ConstructorBuilder cb = tb.DefineConstructor(
MethodAttributes.Public | MethodAttributes.HideBySig,
CallingConventions.Standard,
new[] {typeof (IntPtr)}
);
ILGenerator gen = cb.GetILGenerator();
//
// call base.ctor(context, delegateType)
//
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Ldtoken, delegateType);
gen.Emit(OpCodes.Call, typeof (Type).GetMethod("GetTypeFromHandle"));
gen.Emit(OpCodes.Call, NativeDelegateWrapper.CtorInfo);
gen.Emit(OpCodes.Ret);
//
// define method
//
// [MethodImpl(MethodImplOptions.InternalCall)]
// static extern <returni-type> NativeHandler(IntPtr context,
// <signature>)
//
MethodBuilder icallBuilder = tb.DefineMethod(
"NativeHandler",
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig,
CallingConventions.Standard,
method.ReturnType,
icallParameterTypes
);
icallBuilder.SetImplementationFlags(MethodImplAttributes.InternalCall);
//
// define method
//
// public <return-type> Invoke(<signature>)
//
MethodBuilder mb = tb.DefineMethod(
"Invoke",
MethodAttributes.Public | MethodAttributes.HideBySig,
method.CallingConvention,
method.ReturnType,
parameterTypes
);
gen = mb.GetILGenerator();
//
// public <return-type> Invoke(<signature>)
// {
// return NativeHandler(context, <signature>);
// }
//
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, NativeDelegateWrapper.ContextFieldInfo);
for (int i = 0; i < parameterTypes.Length; i++)
gen.Emit(OpCodes.Ldarg, i + 1);
gen.Emit(OpCodes.Call, icallBuilder);
gen.Emit(OpCodes.Ret);
return tb.CreateType();
}
}