gpt4 book ai didi

c# - 在 C# 中传递函数指针

转载 作者:行者123 更新时间:2023-11-30 16:08:25 26 4
gpt4 key购买 nike

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

函数是这样的:

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

我认为这意味着将指针传递给采用 void 指针并返回 void 指针的函数,如此处解释:

Passing Function Pointer .

我想做的是在 C# 中做同样的事情,但我知道怎么做。我尝试使用委托(delegate),但我不确定如何使用,也不确定他们是否可以做我想做的事情。

感谢您的帮助!

编辑:

下面是 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(调用 native 方法)是 Action<...> 的罕见情况之一。和 Func<...>委托(delegate)不起作用,您必须构建“特定”委托(delegate)。

但是调用它,有点复杂,因为你必须保存委托(delegate)的“副本”,这样如果 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_handlerregister_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 端 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 )

关于c# - 在 C# 中传递函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29300465/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com