在C#中传递函数指针



我在将C++.dll函数转换为C#时遇到问题。

功能如下:

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

我认为这意味着将一个指针传递给函数,接受一个void指针并返回一个void指示器,如下所述:

传递函数指针。

我想做的是在C#中做同样的事情,但我不知道该怎么做。我试着使用代表,但我既不确定如何使用,也不确定他们是否能做我想做的事情。

谢谢你的帮助!

编辑:

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

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

编辑:xanatos在下面给出了确切的解释和对C#的转换。非常感谢xanatos!

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<...>委托不起作用的罕见情况之一,您必须构建"特定"委托。

但是要调用它,它有点复杂,因为您必须保存委托的"副本",这样,如果C函数在任何时候调用该方法,该副本仍然是"活动的",并且还没有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会解决这个问题,但我不确定。。。我不能轻易测试它,我也不会这么做。(如果你想测试它,在register_message_handler之后添加一个GC.Collect()。如果一段时间后你收到CallbackOnCollectedDelegate错误,那么你知道你做不到:-)

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

请注意:最好始终在函数指针中指定调用约定C端和C#端,甚至。C#使用stdcall,而C使用cdecl。在x86模式下,你可能会遇到非常可怕的静默崩溃(在x64中,只有一个调用约定)

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

和C#侧

[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

最新更新