如何从 C++ 调用带有参数的 C# 方法?

问题描述 投票:0回答:1
using System;
using System.Runtime.InteropServices;
using System.Reflection;
public struct StructCreatedByUser
{
    public int x;
    public float anything;
    public string name;
}

class Program
{
    [DllImport("CppLibrary")]
    private static extern void SetPointer(IntPtr ptr);

    [DllImport("CppLibrary")]
    private static extern void CallCppFunctionWithParam(IntPtr param); 


    public static void FunctionCreatedByUser(StructCreatedByUser data){
        Console.WriteLine(data.x + "  " + data.anything + "   " + data.name );
    }

    static void Main()
    {
        StructCreatedByUser data = new StructCreatedByUser { x = 10, anything = 20.5f, name = "wedf" };
        IntPtr param = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(StructCreatedByUser)));
        Marshal.StructureToPtr(data, param, false);
        IntPtr methodPtr = typeof(Program).GetMethod("FunctionCreatedByUser").MethodHandle.GetFunctionPointer();
        SetPointer(methodPtr);
        CallCppFunctionWithParam(param);

    }
}
#include <iostream>
#include <functional>
#include <string>

typedef void (*FunctionStorage)(void*); 
FunctionStorage func;

extern "C" void SetPointer(void* methodPtr) {
    func = reinterpret_cast<FunctionStorage>(methodPtr);
}

extern "C" void CallCppFunctionWithParam(void* param) {
    func(param);  
}

我试图通过使用内存操作直接从 C++ 调用方法来避免在 C# 反射中使用

MethodInfo.Invoke()
带来的性能开销。我的目标是在运行时完全绕过反射。

我成功地在C++中调用了通过反射获得的方法而不传递参数,但是当我尝试传递参数时,我无法让它工作。我怀疑用户定义的方法需要接受

IntPtr
并在内部处理数据转换,但这种方法对用户不友好。理想情况下,与 C++ 和内存管理相关的所有内容都应在后台处理。

这是我的具体问题:

  1. 如何将参数(例如结构体)从 C++ 传递到通过反射获得的 C# 方法?

  2. 当我尝试传递参数时,没有遇到编译时错误,但在运行时,调用失败。导致此问题的可能原因是什么?

任何有关如何实现这一点的指导或示例将不胜感激。

我的.NET版本是8.0.110

c# c++ performance interop system.reflection
1个回答
0
投票

这么多问题:

  • 您的 C++ 代码期望函数具有单个
    void*
    参数,这意味着您需要通过引用传递结构,因为它对于本机 int 来说太宽了。
  • 您还存在明显的内存泄漏,因为您没有释放 HGlobal。
  • GetFunctionPointer()
    是危险的,在大多数情况下不打算直接使用,因为运行时通常需要根据函数的设计和调用位置来设置蹦床垫片。您需要使用带有
    Marshal.GetFunctionPointerForDelegate
    的委托来代替。

老实说,我很不清楚为什么你不让编组员为你解决这一切。只需使用实际的

delegate
声明一个
ref StructCreatedByUser
类型并传递它即可。不要忘记使用
GC.KeepAlive
保留委托或将其存储在字段中,直到完成回调。

[DllImport("CppLibrary")]
private static extern void SetPointer(FunctionStorage func);

[DllImport("CppLibrary")]
private static extern void CallCppFunctionWithParam(ref StructCreatedByUser p1);

private delegate void FunctionStorage(ref StructCreatedByUser p1);

private static FunctionStorage _func = FunctionCreatedByUser;  // need to keep this alive

public static void FunctionCreatedByUser(ref StructCreatedByUser data)
{
    Console.WriteLine(data.x + "  " + data.anything + "   " + data.name );
}

static void Main()
{
    StructCreatedByUser data = new StructCreatedByUser { x = 10, anything = 20.5f, name = "wedf" };
    SetPointer(_func);
    CallCppFunctionWithParam(ref data);
}
© www.soinside.com 2019 - 2024. All rights reserved.