在C#中传递函数指针

时间:2015-03-27 12:16:25

标签: c# function pointers

我无法将C ++ .dll函数转换为C#。

功能如下:

    void funct(void*(*handler)(void*));

我认为这意味着将一个指针传递给函数,该函数采用void指针并返回一个void指针,如下所述:

Passing Function Pointer

我想要做的是在C#中做同样的事情,但我已经知道如何做。我试图使用代表,但我不确定如何以及他们是否能做我想做的事情。

感谢您的帮助!

编辑:

以下是register_message_handler和message_handler的C ++函数:

void register_message_handler(void*(*handler)(void*));
void *message_handler(void *raw_message);

编辑: xanatos具有下面C#的确切解释和转换。非常感谢xanatos!

1 个答案:

答案 0 :(得分:3)

void funct(void*(*handler)(void*));

是一个接受指针并返回指针的函数。

在C#中它将是:

IntPtr MyFunc(IntPtr ptr);

所以你需要一个代表:

public IntPtr delegate MessageHandlerDelegate(IntPtr ptr);

[DllImport("mydll.dll")]
public static extern void register_message_handler(MessageHandlerDelegate del);

请注意,P / Invoke(调用本机方法)是Action<...>Func<...>代表无法工作的极少数情况之一,您必须构建&#34;特定&# 34;委派。

但是来调用它,它有点复杂,因为你必须保存&#34;副本&#34;如果C函数随时调用此方法,则该副本仍然是&#34; alive&#34;并且还没有GC(参见例如https://stackoverflow.com/a/5465074/613130)。最常见的方法是将所有内容封装在一个类中,并将副本放在类的属性/字段中:

class MyClass
{
    public delegate IntPtr MessageHandlerDelegate(IntPtr ptr);

    [DllImport("mydll.dll")]
    public static extern void register_message_handler(MessageHandlerDelegate del);

    [DllImport("mydll.dll")] 
    public static extern IntPtr message_handler(IntPtr message);

    public MessageHandlerDelegate Del { get; set; }

    public void Register()
    {
        // Make a copy of the delegate
        Del = Handler;
        register_message_handler(Del);            
    }

    public IntPtr Handler(IntPtr ptr)
    {
        // I don't know what ptr is
        Console.WriteLine("Handled");
        return IntPtr.Zero; // Return something sensible
    }
}

请注意,如果您使用IntPtr,那么您就不需要unsafe

如果您想将message_handler传递给register_message_handler,最安全的方法是

// Make a copy of the delegate
Del = message_handler;
register_message_handler(Del);

您可以直接进行 没有,检查 <击>

<击>
register_message_handler(message_handler);

并且CLR会解决这个问题,但我不确定这个...我不能轻易测试它,我也不会这样做。 (如果您要对其进行测试,请在GC.Collect()之后添加register_message_handler。如果在一段时间后您收到CallbackOnCollectedDelegate错误,则表示您无法执行此操作: - ))

嗯......检查。 你不能执行原始register_message_handler(message_handler),你必须使用MyClass

非常了解某些事情:总是指定调用约定C-side C#-side 甚至更好在函数指针中。 C#使用stdcall,而C使用cdecl。在x86模式下,你可以得到非常糟糕的无声崩溃(在x64中有一个调用约定)

void __stdcall register_message_handler(void* (__stdcall *handler)(void*));
void * __stdcall message_handler(void *raw_message);

和C#side

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr MessageHandlerDelegate(IntPtr ptr);

[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void register_message_handler(MessageHandlerDelegate del);

[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr message_handler(IntPtr message);

(或任何地方cdecl