using System; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; using System.Text; using Xunit; namespace Class1sharp { public class Program { [System.Flags] private enum LoadLibraryFlags : uint { DONT_RESOLVE_DLL_REFERENCES = 0x00000001, LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, LOAD_LIBRARY_AS_DATAFILE = 0x00000002, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 } [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.StdCall, SetLastError = true)] private delegate void ManagedTypeSignature(uint a, uint b); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int MessageBox(IntPtr hWnd, String text, String caption, int options); [DllImport("kernel32.dll")] private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool FreeLibrary(IntPtr hModule); internal delegate int DllRegisterServerInvoker(); public static IntPtr GetFunctionPointerForDelegate(T delegateCallback, out object binder) where T : class { var del = delegateCallback as Delegate; IntPtr result; try { result = Marshal.GetFunctionPointerForDelegate(del); binder = del; } catch (ArgumentException) // generic type delegate { var delegateType = typeof (T); var method = delegateType.GetMethod("Invoke"); var returnType = method.ReturnType; var paramTypes = method .GetParameters() .Select((x) => x.ParameterType) .ToArray(); // builder a friendly name for our assembly, module, and proxy type var nameBuilder = new StringBuilder(); nameBuilder.Append(delegateType.Name); foreach (var pType in paramTypes) { nameBuilder .Append("`") .Append(pType.Name); } var name = nameBuilder.ToString(); // check if we've previously proxied this type before var proxyAssemblyExist = AppDomain .CurrentDomain .GetAssemblies() .FirstOrDefault((x) => x.GetName().Name == name); Type proxyType; if (proxyAssemblyExist == null) { /// create a proxy assembly var proxyAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName(name), AssemblyBuilderAccess.Run ); var proxyModule = proxyAssembly.DefineDynamicModule(name); // begin creating the proxy type var proxyTypeBuilder = proxyModule.DefineType(name, TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.Public, typeof (MulticastDelegate) ); // implement the basic methods of a delegate as the compiler does var methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; proxyTypeBuilder .DefineConstructor( MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] {typeof (object), typeof (IntPtr)}) .SetImplementationFlags( MethodImplAttributes.Runtime | MethodImplAttributes.Managed ); proxyTypeBuilder .DefineMethod( "BeginInvoke", methodAttributes, typeof (IAsyncResult), paramTypes) .SetImplementationFlags( MethodImplAttributes.Runtime | MethodImplAttributes.Managed); proxyTypeBuilder .DefineMethod( "EndInvoke", methodAttributes, null, new Type[] {typeof (IAsyncResult)}) .SetImplementationFlags( MethodImplAttributes.Runtime | MethodImplAttributes.Managed); proxyTypeBuilder .DefineMethod( "Invoke", methodAttributes, returnType, paramTypes) .SetImplementationFlags( MethodImplAttributes.Runtime | MethodImplAttributes.Managed); // create & wrap an instance of the proxy type proxyType = proxyTypeBuilder.CreateType(); } else { // pull the type from an existing proxy assembly proxyType = proxyAssemblyExist.GetType(name); } // marshal and bind the proxy so the pointer doesn't become invalid var repProxy = Delegate.CreateDelegate(proxyType, del.Target, del.Method); result = Marshal.GetFunctionPointerForDelegate(repProxy); binder = Tuple.Create(del, repProxy); } return result; } public delegate int MessageBoxDelegate(IntPtr hWnd, string lpText, string lpCaption, uint uType); public delegate int Posy(int a, int b); [Fact] public static void Main() { // let's get a managed method and convert it to an int: var managedMethod = new ManagedTypeSignature(MyManagedMethod); var untypedManagedMethod = (Delegate) managedMethod; IntPtr nativeThunk = Marshal.GetFunctionPointerForDelegate(untypedManagedMethod); // nativeThunk can now be called by C++ using the following typedef: // void (__stdcall *NativeTypeSignature) ( uint32_t a, uint32_t b ); // now let's turn it back into a function: Delegate untypedNativeMethod = Marshal.GetDelegateForFunctionPointer(nativeThunk, typeof (ManagedTypeSignature)); var managedMethod2 = (ManagedTypeSignature) untypedNativeMethod; // let's call it, just to be sure: managedMethod2(37, 4); Posy m = (i, i1) => i + i1; var tx= Marshal.GetFunctionPointerForDelegate(m); //var ptr = GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA"); //var MessageBoxA = // GetDelegateForFunctionPointer>(ptr, CallingConvention.StdCall); //MessageBoxA(IntPtr.Zero, "Hello world", "Test", 0); } private static void MyManagedMethod(uint a, uint b) { Console.Write("{0} + {1} = {2}", a, b, a + b); } [Fact] public void Testd() { //var module = LoadLibrary("user32.dll"); //// Can't use MessageBoxW, seems to implicitly marshal to UTF8? Could have sworn .NET strings were internally UTF16 //// Then again, my system is setup for en-us... //var proc_ptr = GetProcAddress(module, "MessageBoxA"); //const System.Runtime.InteropServices.CallingConvention call_conv = // System.Runtime.InteropServices.CallingConvention.Winapi; //var msg_box = Util.GetDelegateForFunctionPointer(proc_ptr, call_conv); //msg_box(IntPtr.Zero, "Hello World", "Test1", 0); //var msg_box_gen = Util.GetDelegateForFunctionPointer(proc_ptr, call_conv); //msg_box_gen(IntPtr.Zero, "Goodbye World", "Test2", 0); //Func c = (x) =>x; //IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate(c); object ttys; IntPtr pointerForDelegate = GetFunctionPointerForDelegate>(i => 1, out ttys); Console.Write(pointerForDelegate); Marshal.GetDelegateForFunctionPointer() // FreeLibrary(module); } } }