The current project I did for a customer faced me with tons of legancy code which was written in C++ years back. This code is supposed to die at some point, but due some requirements the code needed to interact with some .Net / C# with COM Interop. The code uses a lot of function pointers passed to the callee to supply callbacks for logging and user notification. Exposing events for interaction from .Net via COM to the C++ code would have caused a major rewrite of the code, so we decided to stick with the callback pattern. Directly using the Marshal.GetDelegateForFunctionPointer stuff would have been possible but sadly the function does not accept generic delegate classes like Action
private static readonly ModuleBuilder CallbackModuleBuilder; static NativeCallbackFactory() { CallbackModuleBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("NativeCallbacks"), AssemblyBuilderAccess.Run) .DefineDynamicModule("Delegates", false); }
Now I need a helper function that created the delegate type I need:
public static Type CreateCallbackType(params Type[] parameters) { Type returnType = typeof(void); TypeBuilder typeBuilder = GetBuilder("Delegate" + Guid.NewGuid()); typeBuilder.DefineConstructor(MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, CallingConventions.Standard, DelegateCtorSignature) .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); typeBuilder.DefineMethod("Invoke", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, returnType, parameters) .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); var attributeType = typeof(UnmanagedFunctionPointerAttribute); var builder = new CustomAttributeBuilder(attributeType.GetConstructor(new[] { typeof(CallingConvention) }), new object[] { CallingConvention.StdCall }, new[] { attributeType.GetField("CharSet") }, new object[] { CharSet.Ansi }); typeBuilder.SetCustomAttribute(builder); return typeBuilder.CreateType(); }
Lets look at all the code in a little more detail to see what I am actually doing.
Type returnType = typeof(void); TypeBuilder typeBuilder = GetBuilder("Delegate" + Guid.NewGuid());
I created a TypeBuilder (more on that in little while), in my case the return type is always void, thats why it is hard coded in here, but you can specify your own if you need. Currently the name of the delegate type I am building is a random name and different for each delegate that is created. If you want to, you can implement your own naming here, to e.g. allow caching or get not that obfuscated names. The TypeBuilder creation is straightforward:
private static TypeBuilder GetBuilder(string name) { var stringBuilder = new StringBuilder(name); stringBuilder.Append("$"); //remove illegal chars from name stringBuilder.Replace('+', '_').Replace('[', '_').Replace(']', '_').Replace('*', '_').Replace('&', '_').Replace(',', '_').Replace('\\', '_'); name = stringBuilder.ToString(); return CallbackModuleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AutoClass, typeof(MulticastDelegate)); }
It simply removes illegal chars from the name of the delegate and builds a new type using the ModuleBuilder I defined in the type constructor. The new type is a public type that is sealed, since I don’t want to inherit from it any further and it allows the CLR to apply some optimizations. Once I have the TypeBuilder I create my own constructor. The DelegateCtorSignature is a static variable that holds the default delegate constructor signature.
typeBuilder.DefineConstructor(MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, CallingConventions.Standard, DelegateCtorSignature) .SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
After the constructor I need a Invoke method to invoke the delegate. This method is of the returntype of out native method, in this case void and has the parameters of the native method.
typeBuilder.DefineMethod("Invoke", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, returnType, parameters).SetImplementationFlags(MethodImplAttributes.CodeTypeMask);
Now I would have a fully functional delegate class but it would be missing some nice stuff the runtime is offering us, string conversion and calling conventions. This is controlled by attributes which you apply to the delegate the UnmanagedFunctionPointerAttribute. So I apply this attribute to the new type:
var attributeType = typeof(UnmanagedFunctionPointerAttribute); var builder = new CustomAttributeBuilder(attributeType.GetConstructor(new[] { typeof(CallingConvention) }), new object[] { CallingConvention.StdCall }, new[]{ attributeType.GetField("CharSet")}, new object[] { CharSet.Ansi }); typeBuilder.SetCustomAttribute(builder);
In my case the strings are passed as LPTSTR which is the Ansi Charset on the CLR you can use Unicode if you want by changing it. Finally I need to tell the TypeBuilder to build the type:
return typeBuilder.CreateType();
I have hooked everything up in a static class that provides these functionality with generic methods. This makes it easy to create type safe delegates from function pointer and you can easily extend it. E.g. you can add value converter to the delegates if you need to. If you have to create a lot of delegates at runtime with the same signature you might want to implement some caching since the code emit at runtime is quite expensive. You can download the complete source code here. It is free to use and comes with no license restrictions. Have fun with it.