[C#, C++] Marshal.GetFunctionPointerForDelegate
От: adontz Грузия http://adontz.wordpress.com/
Дата: 01.03.09 11:09
Оценка: 26 (2)
Известно, что в .Net Compact Framework не реализован метод Marshal.GetFunctionPointerForDelegate. Это создаёт достаточно большие проблемы при интеропе. В связи с вышесказанным была написана небольшая DLL. Она не является абсолютно универсальным решением, но покрывает подавляющее большинство случаев.

Реализация

bifrost.cpp
/******************************************************************************/
/*                                                                            */
/*    _                ___        _..-._                                      */
/*    \`.|\..----...-'`   `-._.-'' _.-..'                                     */
/*    /  ' `         ,       __.-''                                           */
/*    )/` _/     \   `-_,   /                                                 */
/*    `-'" `"\_  ,_.-;_.-\_ ',  NABU Project                                  */
/*        _.-'_./   {_.'   ; /  Bifrost Library                               */
/*       {_.-``-'         {_/   Copyright © 2005-2009, TrifleSoft             */
/*                                                                            */
/******************************************************************************/
#include <windows.h>
//
typedef DWORD (__stdcall * StdCall0)();
typedef DWORD (__stdcall * StdCall1)(DWORD arg1);
typedef DWORD (__stdcall * StdCall2)(DWORD arg1, DWORD arg2);
typedef DWORD (__stdcall * StdCall3)(DWORD arg1, DWORD arg2, DWORD arg3);
typedef DWORD (__stdcall * StdCall4)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4);
typedef DWORD (__stdcall * StdCall5)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5);
typedef DWORD (__stdcall * StdCall6)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6);
typedef DWORD (__stdcall * StdCall7)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7);
typedef DWORD (__stdcall * StdCall8)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8);
typedef DWORD (__stdcall * StdCall9)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9);
typedef DWORD (__stdcall * StdCallA)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA);
typedef DWORD (__stdcall * StdCallB)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB);
typedef DWORD (__stdcall * StdCallC)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC);
typedef DWORD (__stdcall * StdCallD)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD);
typedef DWORD (__stdcall * StdCallE)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD, DWORD argE);
typedef DWORD (__stdcall * StdCallF)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD, DWORD argE, DWORD argF);
//
typedef DWORD (__cdecl * CDecl0)();
typedef DWORD (__cdecl * CDecl1)(DWORD arg1);
typedef DWORD (__cdecl * CDecl2)(DWORD arg1, DWORD arg2);
typedef DWORD (__cdecl * CDecl3)(DWORD arg1, DWORD arg2, DWORD arg3);
typedef DWORD (__cdecl * CDecl4)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4);
typedef DWORD (__cdecl * CDecl5)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5);
typedef DWORD (__cdecl * CDecl6)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6);
typedef DWORD (__cdecl * CDecl7)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7);
typedef DWORD (__cdecl * CDecl8)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8);
typedef DWORD (__cdecl * CDecl9)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9);
typedef DWORD (__cdecl * CDeclA)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA);
typedef DWORD (__cdecl * CDeclB)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB);
typedef DWORD (__cdecl * CDeclC)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC);
typedef DWORD (__cdecl * CDeclD)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD);
typedef DWORD (__cdecl * CDeclE)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD, DWORD argE);
typedef DWORD (__cdecl * CDeclF)(DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8, DWORD arg9, DWORD argA, DWORD argB, DWORD argC, DWORD argD, DWORD argE, DWORD argF);
//
DWORD __stdcall CallUnmanagedFunctionPointer(
    BOOL isCDecl,
    LPVOID lpFunction,
    DWORD argCount,
    LPDWORD lpArgs)
{
    if (isCDecl)
    {
        switch (argCount)
        {
            case 0x0: return ((CDecl0)lpFunction)();
            case 0x1: return ((CDecl1)lpFunction)(lpArgs[0]);
            case 0x2: return ((CDecl2)lpFunction)(lpArgs[0], lpArgs[1]);
            case 0x3: return ((CDecl3)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2]);
            case 0x4: return ((CDecl4)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3]);
            case 0x5: return ((CDecl5)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4]);
            case 0x6: return ((CDecl6)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5]);
            case 0x7: return ((CDecl7)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6]);
            case 0x8: return ((CDecl8)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7]);
            case 0x9: return ((CDecl9)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8]);
            case 0xA: return ((CDeclA)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9]);
            case 0xB: return ((CDeclB)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10]);
            case 0xC: return ((CDeclC)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11]);
            case 0xD: return ((CDeclD)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12]);
            case 0xE: return ((CDeclE)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12], lpArgs[13]);
            case 0xF: return ((CDeclF)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12], lpArgs[13], lpArgs[14]);
        }
    }
    else
    {
        switch (argCount)
        {
            case 0x0: return ((StdCall0)lpFunction)();
            case 0x1: return ((StdCall1)lpFunction)(lpArgs[0]);
            case 0x2: return ((StdCall2)lpFunction)(lpArgs[0], lpArgs[1]);
            case 0x3: return ((StdCall3)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2]);
            case 0x4: return ((StdCall4)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3]);
            case 0x5: return ((StdCall5)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4]);
            case 0x6: return ((StdCall6)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5]);
            case 0x7: return ((StdCall7)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6]);
            case 0x8: return ((StdCall8)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7]);
            case 0x9: return ((StdCall9)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8]);
            case 0xA: return ((StdCallA)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9]);
            case 0xB: return ((StdCallB)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10]);
            case 0xC: return ((StdCallC)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11]);
            case 0xD: return ((StdCallD)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12]);
            case 0xE: return ((StdCallE)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12], lpArgs[13]);
            case 0xF: return ((StdCallF)lpFunction)(lpArgs[0], lpArgs[1], lpArgs[2], lpArgs[3], lpArgs[4], lpArgs[5], lpArgs[6], lpArgs[7], lpArgs[8], lpArgs[9], lpArgs[10], lpArgs[11], lpArgs[12], lpArgs[13], lpArgs[14]);
        }
    }

    return 0xDEADBEAF;
}
/******************************************************************************/
/*                                END OF FILE                                 */
/******************************************************************************/


bifrost.def
LIBRARY "Bifrost"

EXPORTS CallUnmanagedFunctionPointer


Использование

NativeMethods.cs
internal static class NativeMethods
{
    [DllImport("bifrost.dll")]
    public static extern IntPtr CallUnmanagedFunctionPointer(
        [In][MarshalAs(UnmanagedType.Bool)] bool isCDecl,
        [In] IntPtr lpFunction,
        [In] int argCount,
        [In][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] IntPtr[] args);
}

MarshalCF.cs

public static class MarshalCF
{
    private static IntPtr GetIntPtr(object value)
    {
        switch (value.GetType().FullName)
        {
            case "System.Char":
                return new IntPtr((int)(char)value);
            case "System.Int8":
                return new IntPtr((sbyte)value);
            case "System.UInt8":
                return new IntPtr((int)(byte)value);
            case "System.Int16":
                return new IntPtr((short)value);
            case "System.UInt16":
                return new IntPtr((int)(ushort)value);
            case "System.Int32":
                return new IntPtr((int)value);
            case "System.UInt32":
                return new IntPtr((long)(uint)value);
            case "System.Int64":
                return new IntPtr((long)value);
            case "System.UInt64":
                return new IntPtr((long)(ulong)value);
            case "System.IntPtr":
                return (IntPtr)value;
            case "System.UIntPtr":
                return new IntPtr((long)((UIntPtr)value).ToUInt64());
        }
            throw new ArgumentException("value");
    }

    public static IntPtr CallUnmanagedCDeclFunction(
        IntPtr lpFunction,
        params object[] arguments)
    {
        IntPtr[] args = new IntPtr[arguments.Length];
            for (int index = 0; index < args.Length; ++index)
        {
            args[index] = GetIntPtr(arguments[index]);
        }

        return
            NativeMethods.CallUnmanagedFunctionPointer(
                true,
                lpFunction,
                args.Length,
                args);
    }

    public static IntPtr CallUnmanagedStdCallFunction(
        IntPtr lpFunction,
        params object[] arguments)
    {
        IntPtr[] args = new IntPtr[arguments.Length];

        for (int index = 0; index < args.Length; ++index)
        {
            args[index] = GetIntPtr(arguments[index]);
        }

        return
            NativeMethods.CallUnmanagedFunctionPointer(
                false,
                lpFunction,
                args.Length,
                args);
    }
}
A journey of a thousand miles must begin with a single step © Lau Tsu
.net compact framework cf getfunctionpointerfordelegate
Re: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: Аноним  
Дата: 02.03.09 06:19
Оценка:
Здравствуйте, adontz, Вы писали:

A>Известно, что в .Net Compact Framework не реализован метод Marshal.GetFunctionPointerForDelegate.


А Emit подерживаеся в .Net Compact Framework?
Если да, то вот чисто managed реализация (написана для .NET v1), должна работать и в CF :

ps: есть правда некоторые ограничения, в частности не реализован user-marshaling,
за ненадобностью , но при желании можно добавить

    /// <summary>
    /// Summary description for DelegateHelper.
    /// </summary>
    internal static class DelegateHelper
    {
        private const string InvokerAssemblyPrefix = "UnmanagedCodeInvokerAssembly_";
        private const string InvokerTypePostfix = "_UnmanagedCodeInvoker";

        private const string FuncPointerFieldName = "_funcPointer";
        private const string FuncPointerParamName = "aFuncPointer";
        private const string InvokeMethodName = "Invoke";

        private static readonly Type DelegateType = typeof(Delegate);

        private static readonly ConstructorInfo ObjectCtorInfo = typeof(object).GetConstructor(new Type[0]);

        private static readonly object StaticSyncRoot = new object();
        private static int _asmNum = 0;

        private static AssemblyBuilder _asmBuilder = null;
        private static ModuleBuilder _modBuilder = null;

        /// <summary>
        /// key: type of delegate; value: type of generated unmanaged invoker.
        /// </summary>
        private static Hashtable GeneratedTypes = new Hashtable();
        /// <summary>
        /// key: type of delegate; value: <see cref="DelegateInfo"/>.
        /// </summary>
        private static Hashtable CachedTypesToGenerate = new Hashtable();

        private class DelegateInfo
        {
            public readonly Type DelegateType;
            public readonly CallingConvention CallConv;

            public DelegateInfo(Type aDelegateType, CallingConvention aCallConv)
            {
                DelegateType = aDelegateType;
                CallConv = aCallConv;
            }
        }

        public static bool PersistGeneratedCode
        {
            get
            {
#if DEBUG
                return true;
#else
                return false;
#endif // DEBUG
            }
        }

        private static MethodInfo GetInvokeMethodInfo(Type aDelegateType)
        {
            MethodInfo mi = aDelegateType.GetMethod(InvokeMethodName, 
                BindingFlags.DeclaredOnly | 
                BindingFlags.Public | 
                BindingFlags.Instance);
            return mi;
        }

        private static string GetInvokerTypeName(Type aDelegateType, int aTypeNum)
        {
            return aDelegateType.Name + InvokerTypePostfix + aTypeNum.ToString();
        }

        private static int GetNextAssemblyNumber()
        {
            return _asmNum++;
        }

        private static AssemblyName GenerateAssemblyName()
        {
            AssemblyName theAsmName = new AssemblyName();
            theAsmName.Name = InvokerAssemblyPrefix + 
                AppDomain.CurrentDomain.GetHashCode().ToString() + "_" + GetNextAssemblyNumber();
            return theAsmName;
        }

        public static void PreCompile(params Type[] aDelegateTypes)
        {
            PreCompile(false, aDelegateTypes);
        }

        public static void PreCompile(bool aCompileImmediately, params Type[] aDelegateTypes)
        {
            PreCompile(aCompileImmediately, CallingConvention.StdCall, aDelegateTypes);
        }

        public static void PreCompile(CallingConvention aCallConv, params Type[] aDelegateTypes)
        {
            PreCompile(false, aCallConv, aDelegateTypes);
        }

        public static void PreCompile(bool aCompileImmediately, CallingConvention aCallConv, params Type[] aDelegateTypes)
        {
            if (aDelegateTypes == null)
            {
                throw new ArgumentNullException("aDelegateTypes");
            }

            lock (StaticSyncRoot)
            {
                foreach (Type t in aDelegateTypes)
                {
                    if (t == null)
                    {
                        throw new  ArgumentNullException("aDelegateTypes", "At least one type is null.");
                    }

                    if (!DelegateType.IsAssignableFrom(t))
                    {
                        throw new ArgumentException("At least one type not derived from System.Delegate.", "aDelegateTypes");
                    }

                    if (t.IsAbstract)
                    {
                        throw new ArgumentException("At least one type is abstract.", "aDelegateTypes");
                    }

                    if (GeneratedTypes.Contains(t))
                    {
                        //already generated
                        continue;
                    }
                    if (CachedTypesToGenerate.Contains(t))
                    {
                        //already cached to generate
                        continue;
                    }

                    CachedTypesToGenerate.Add(t, new DelegateInfo(t, aCallConv));
                }

                if (CachedTypesToGenerate.Count > 0 && aCompileImmediately)
                {
                    GenerateFromCache();
                }
            }
        }

        public static void Compile()
        {
            GenerateFromCache();
        }

        private static void GenerateFromCache()
        {
            lock (StaticSyncRoot)
            {
                if (CachedTypesToGenerate.Count == 0)
                {
                    return;
                }

                if (_asmBuilder == null)
                {
                    AssemblyName theAsmName = GenerateAssemblyName();

                    AssemblyBuilder theAsmBuilder = null;

                    if (PersistGeneratedCode)
                    {
                        string dir = Path.GetDirectoryName(new Uri(Assembly.GetEntryAssembly().Location).AbsolutePath);
                        theAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(theAsmName, 
                            AssemblyBuilderAccess.RunAndSave, dir);
                    }
                    else
                    {
                        theAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(theAsmName, 
                            AssemblyBuilderAccess.Run);
                    }

                    ModuleBuilder theModBuilder = theAsmBuilder.DefineDynamicModule(theAsmName.Name + ".dll");

                    _asmBuilder = theAsmBuilder;
                    _modBuilder = theModBuilder;
                }

                int theTypeNum = 0;
                foreach (DelegateInfo theDelInfo in CachedTypesToGenerate.Values)
                {
                    if (GeneratedTypes.Contains(theDelInfo.DelegateType))
                    {
                        continue;
                    }

                    theTypeNum = GeneratedTypes.Count;
                    Type theInvokerType = GenerateInvokerType(_modBuilder, theDelInfo.DelegateType, 
                        theDelInfo.CallConv, theTypeNum);
                    GeneratedTypes.Add(theDelInfo.DelegateType, theInvokerType);
                }

                CachedTypesToGenerate.Clear();

                if (PersistGeneratedCode)
                {
                    //NOTE: после сохранения сборки ее нельзя модифицировать
                    _asmBuilder.Save(_modBuilder.Name);
                    _asmBuilder = null;
                    _modBuilder = null;
                }
            }
        }

        private static Type GenerateInvokerType(ModuleBuilder aModBuilder, Type aDelegateType, 
            CallingConvention aCallConv, int aTypeNum)
        {
            //create helper invoker class, which look like:
            //        class UnmanagedCodeInvoker
            //        {
            //            private IntPtr _funcPointer;
            //
            //            public UnmanagedCodeInvoker(IntPtr aFuncPointer)
            //            {
            //                _funcPointer = aFuncPointer;
            //            }
            //
            //            public RETVALUE Invoke(ARGUMENTS)
            //            {
            //                return _funcPointer(ARGUMENTS);
            //            }
            //        }

            string theTypeName = GetInvokerTypeName(aDelegateType, aTypeNum);
            TypeBuilder theTypeBuilder = aModBuilder.DefineType(theTypeName, 
                TypeAttributes.Sealed | TypeAttributes.NotPublic);

            //create instance field which will be hold ref to function ptr
            FieldBuilder theFieldBuilder = theTypeBuilder.DefineField(FuncPointerFieldName, typeof(IntPtr), FieldAttributes.Private);

            //create ctor with one parameter: function ptr
            ConstructorBuilder theCtorBuilder = theTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] {typeof(IntPtr)});
            theCtorBuilder.DefineParameter(1, ParameterAttributes.In, FuncPointerParamName);
            ILGenerator theCtorGen = theCtorBuilder.GetILGenerator();

            //NOTE: Ldarg_0 contains "this", Ldarg_1 input parameter: function ptr
            //call base ctor
            theCtorGen.Emit(OpCodes.Ldarg_0);
            theCtorGen.Emit(OpCodes.Call, ObjectCtorInfo);
            //remember input function ptr in the instance field
            theCtorGen.Emit(OpCodes.Ldarg_0);
            theCtorGen.Emit(OpCodes.Ldarg_1);
            theCtorGen.Emit(OpCodes.Stfld, theFieldBuilder);

            theCtorGen.Emit(OpCodes.Ret);

            MethodInfo theMethodPrototype = GetInvokeMethodInfo(aDelegateType);

            //extract return type
            Type theRetType = theMethodPrototype.ReturnType;
            //extract parameters info
            ParameterInfo[] theParamsInfo = theMethodPrototype.GetParameters();
            Type[] theParamsType = new Type[theParamsInfo.Length];
            for (int i = 0; i < theParamsInfo.Length; i++)
            {
                ParameterInfo theParamInfo = theParamsInfo[i];
                theParamsType[i] = theParamInfo.ParameterType;
            }

            //create invoker method
            MethodBuilder theInvokeMethodBuilder = theTypeBuilder.DefineMethod(InvokeMethodName, 
                MethodAttributes.Public, theRetType, theParamsType);

            //todo: define marshal attributes
            //note: 
            //in .NET 1.1 more difficult get\set this information, 
            //in .NEt v2 we can use MarshalAs attribute for get\set this information
            //code look like:
            //theInvokeMethodBuilder.SetMarshal(UnmanagedMarshal.DefineUnmanagedMarshal(UnmanagedType.LPWStr));

            //for (int i = 0; i < theParamsInfo.Length; i++)
            //{
            //    ParameterInfo theParamInfo = theParamsInfo[i];
            //    ParameterBuilder theParamBuilder = theInvokeMethodBuilder.DefineParameter(i + 1, theParamInfo.Attributes, theParamInfo.Name);

            //    if ((theParamInfo.Attributes & ParameterAttributes.HasFieldMarshal) == ParameterAttributes.HasFieldMarshal)
            //    {
            //        //code look like:
            //        //theParamBuilder.SetMarshal(UnmanagedMarshal.DefineUnmanagedMarshal(UnmanagedType.LPWStr));
            //    }
            //}

            ILGenerator theInvokeMethodGen = theInvokeMethodBuilder.GetILGenerator();

            //load parameters
            for (int i = 0; i < theParamsInfo.Length; i++)
            {
                //ParameterInfo theParamInfo = theParamsInfo[i];
                theInvokeMethodGen.Emit(OpCodes.Ldarg_S, (byte) (i + 1));
            }

            //load unmanaged function ptr
            theInvokeMethodGen.Emit(OpCodes.Ldarg_0);
            theInvokeMethodGen.Emit(OpCodes.Ldfld, theFieldBuilder);

            //call unmanaged function
            theInvokeMethodGen.EmitCalli(OpCodes.Calli, aCallConv, theRetType, theParamsType);

            theInvokeMethodGen.Emit(OpCodes.Ret);

            return  theTypeBuilder.CreateType();
        }

        private static Type GetOrCreateInvokerType(Type aDelegateType, CallingConvention aCallConv)
        {
            Type theInvokerType = (Type) GeneratedTypes[aDelegateType];
            if (theInvokerType == null)
            {
                lock (StaticSyncRoot)
                {
                    theInvokerType = (Type) GeneratedTypes[aDelegateType];
                    if (theInvokerType == null)
                    {
                        if (!CachedTypesToGenerate.Contains(aDelegateType))
                        {
                            CachedTypesToGenerate.Add(aDelegateType, new DelegateInfo(aDelegateType, aCallConv));    
                        }

                        GenerateFromCache();
                        theInvokerType = (Type) GeneratedTypes[aDelegateType];
                    }
                }
            }
            return theInvokerType;
        }

        public static Delegate GetDelegateForFunctionPointer(IntPtr aFuncPtr, Type aDelegateType)
        {
            return GetDelegateForFunctionPointer(aFuncPtr, aDelegateType, CallingConvention.StdCall);
        }

        public static Delegate GetDelegateForFunctionPointer(IntPtr aFuncPtr, 
            Type aDelegateType, CallingConvention aCallConv)
        {
            if (aFuncPtr == IntPtr.Zero)
            {
                throw new ArgumentNullException("aFuncPtr");
            }

            if (aDelegateType == null)
            {
                throw new ArgumentNullException("aDelegateType");
            }

            if (!DelegateType.IsAssignableFrom(aDelegateType))
            {
                throw new ArgumentException("Type must be derived from System.Delegate.", "aDelegateType");
            }

            Type theInvokerType = GetOrCreateInvokerType(aDelegateType, aCallConv);
            object theInvoker = Activator.CreateInstance(theInvokerType, new object[] {aFuncPtr});
            return Delegate.CreateDelegate(aDelegateType, theInvoker, InvokeMethodName);
        }
    }
Re[2]: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: adontz Грузия http://adontz.wordpress.com/
Дата: 02.03.09 06:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А Emit подерживаеся в .Net Compact Framework?


Ну а сам-то как думаешь?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[3]: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: Аноним  
Дата: 02.03.09 07:27
Оценка:
Здравствуйте, adontz, Вы писали:

А>>А Emit подерживаеся в .Net Compact Framework?


A>Ну а сам-то как думаешь?


были конечно подозрения
Re: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: Блудов Павел Россия  
Дата: 14.03.09 05:15
Оценка:
Здравствуйте, adontz, Вы писали:

A>public static class MarshalCF

A>{
A> private static IntPtr GetIntPtr(object value)
A> {
A> switch (value.GetType().FullName)
A> {
A> case "System.Char":
A> return new IntPtr((int)(char)value);

CF поддерживает Type.GetTypeCode, с ним веселей.
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Re[2]: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: adontz Грузия http://adontz.wordpress.com/
Дата: 14.03.09 10:26
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

БП>CF поддерживает Type.GetTypeCode, с ним веселей.


Для IntPtr нет TypeCode
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[2]: [C#, C++] Marshal.GetFunctionPointerForDelegate
От: adontz Грузия http://adontz.wordpress.com/
Дата: 14.03.09 10:39
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

Хотя, можно и так
public static IntPtr GetIntPtr(object value)
        {
            Type type = value.GetType();

            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Char:
                    return new IntPtr((int)(char)value);
                case TypeCode.SByte:
                    return new IntPtr((sbyte)value);
                case TypeCode.Byte:
                    return new IntPtr((int)(byte)value);
                case TypeCode.Int16:
                    return new IntPtr((short)value);
                case TypeCode.UInt16:
                    return new IntPtr((int)(ushort)value);
                case TypeCode.Int32:
                    return new IntPtr((int)value);
                case TypeCode.UInt32:
                    return new IntPtr((long)(uint)value);
                case TypeCode.Int64:
                    return new IntPtr((long)value);
                case TypeCode.UInt64:
                    return new IntPtr((long)(ulong)value);
                default:
                    switch (type.FullName)
                    {
                        case "System.IntPtr":
                            return (IntPtr)value;
                        case "System.UIntPtr":
                            return new IntPtr((long)((UIntPtr)value).ToUInt64());
                    }
                    break;
            }

            throw new ArgumentException("value");
        }

Так и оставлю
A journey of a thousand miles must begin with a single step © Lau Tsu
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.