Tro*_*a55 4 c# pointers function
我在将 C++ .dll 函数转换为 C# 时遇到问题。
功能是这样的:
void funct(void*(*handler)(void*));
Run Code Online (Sandbox Code Playgroud)
我认为这意味着将指针传递给采用 void 指针并返回 void 指针的函数,如下所述:
我想做的是在 C# 中做同样的事情,但我知道如何做。我尝试使用委托,但我既不确定如何使用,也不确定他们是否可以做我想做的事情。
谢谢您的帮助!
编辑:
以下是 register_message_handler 和 message_handler 的 C++ 函数:
void register_message_handler(void*(*handler)(void*));
void *message_handler(void *raw_message);
Run Code Online (Sandbox Code Playgroud)
编辑:xanatos 在下面有准确的解释和转换为 C#。非常感谢 xanatos!
void funct(void*(*handler)(void*));
Run Code Online (Sandbox Code Playgroud)
是一个接受指针并返回指针的函数。
在 C# 中,它将是:
IntPtr MyFunc(IntPtr ptr);
Run Code Online (Sandbox Code Playgroud)
所以你需要一个像这样的代表:
public IntPtr delegate MessageHandlerDelegate(IntPtr ptr);
[DllImport("mydll.dll")]
public static extern void register_message_handler(MessageHandlerDelegate del);
Run Code Online (Sandbox Code Playgroud)
请注意,P/Invoke(调用本机方法)是Action<...>和Func<...>委托不起作用的罕见情况之一,您必须构建“特定”委托。
但是要调用它,它有点复杂,因为您必须保存委托的“副本”,以便如果 C 函数在任何时候调用此方法,该副本仍然“活着”并且没有被 GC(参见 参考资料)例如/sf/answers/382555211/)。最常见的方法是将所有内容封装在一个类中,并将副本放在类的属性/字段中:
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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您使用,IntPtr则不需要unsafe.
如果你想传递message_handler给register_message_handler最安全的方法是
// Make a copy of the delegate
Del = message_handler;
register_message_handler(Del);
Run Code Online (Sandbox Code Playgroud)
有可能你可以直接做 没有没有,检查
register_message_handler(message_handler);
Run Code Online (Sandbox Code Playgroud)
并且 CLR 将解决这个问题,但我不确定这一点......我无法轻松测试它,我也不会这样做。(如果你想测试它, GC.Collect()在 之后添加一个register_message_handler。如果一段时间后你收到一个CallbackOnCollectedDelegate错误,那么你知道你不能这样做:-))
嗯...检查。你不能做 raw 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);
Run Code Online (Sandbox Code Playgroud)
和 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);
Run Code Online (Sandbox Code Playgroud)
(或无处不在cdecl)
| 归档时间: |
|
| 查看次数: |
5453 次 |
| 最近记录: |