简体   繁体   English

我如何创建可以从c#中调用的cpp函数,并将函数作为参数

[英]How do i create a cpp function that can be called from c# with a function as an argument

Exactly as in the question. 与问题完全相同。

I have a pair of libraries, one in cpp, the other in c#. 我有一对库,一个在cpp中,另一个在c#中。 I already have several (cpp) functions that i can call from c#, but only with simple arguments (arrays and primitives). 我已经有几个(cpp)函数,可以从c#调用,但只能使用简单的参数(数组和基元)。

How do i pass a function? 如何传递功能?

I've read loads of answers on here, and none of them are helping me out - what am i missing? 我在这里读了很多答案,但是没有一个人在帮助我-我想念什么?

Here's what i have: 这是我所拥有的:

    delegate double ManagedFunction(cli::array<System::Double>^ xIn);
    ...

    ...
    static int LevMar(
        ManagedFunction^ function,
        cli::array<System::Double, 1>^ x0,
        cli::array<System::Double, 1>^ xHigh,
        cli::array<System::Double, 1>^ xLow,
        int maxIters//,
        //double tolerance
        ) {

        IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(function);
        Unmanaged::WrapperClass::functionToMinimize = static_cast<Unmanaged::UnmanagedFunction>(stubPointer.ToPointer());

        int m = x0->Length; //nDim
        int N = 1; //observables dimension

        double* fx = new double[m];

        double* x0Arr = Utility::CreateDoubleArrayFromManaged(x0);
        double* xLowArr = Utility::CreateDoubleArrayFromManaged(xLow);
        double* xHighArr = Utility::CreateDoubleArrayFromManaged(xHigh);

        double info[LM_INFO_SZ];


        double tolerance[5];
        tolerance[0] = 0.01; //scale factor for initial \mu/ 
        tolerance[1] = tolerance[2] = tolerance[3] = tolerance[4] = 1.0e-5;

        dlevmar_bc_dif(Unmanaged::WrapperClass::functionToPassToLevMar, x0Arr, fx, m, N, xLowArr, xHighArr, NULL, maxIters, tolerance, info, NULL, NULL, NULL);
        int nElements = sizeof x0Arr / sizeof x0Arr[0];
        for (int i = 0; i < nElements; i++) x0[i] = x0Arr[0];
        return 0;
    }

And this all compiles, but i've not been able to test it yet, since i can't call it from the c#; 所有这些都可以编译,但是我还不能测试它,因为我不能从c#调用它。 this is what i've tried: 这是我尝试过的:

CostDelegate costDelegate = new CostDelegate(cost);
XXXCpp.Minimization.LevMar(costDelegate, x0, xhigh, xlow, 1000);

But it's telling me it cannot cast from 'CostDelegate' to 'ManagedFunction'. 但这告诉我它不能从“ CostDelegate”转换为“ ManagedFunction”。 Both are delegates, and both have the same signatures. 两者都是委托,并且都具有相同的签名。

How can i achieve what i wawnt here? 我如何才能在这里实现自我?

Is there a way to do it so that in the c#, when i call the function i can just pass it a function without having to create a delegate too (ie can i write the cpp such that the function takes a Func<double[], double> instead of this 'ManagedFunction' object)? 有没有办法做到这一点,以便在c#中,当我调用该函数时,我可以仅将其传递给一个函数而不必创建委托(即,我可以编写cpp以便该函数使用Func<double[], double>而不是此“ ManagedFunction”对象)?

delegate double ManagedFunction(cli::array<System::Double>^ xIn);

You forgot to declare it public . 您忘了宣布它为public Required, two delegate types are never compatible, not even when their signature is the same. 必需,两个委托类型永远不兼容,即使它们的签名相同也是如此。 Your C# code must create a ManagedFunction delegate, it can only do so when you make it public. 您的C#代码必须创建ManagedFunction委托,只有在将其公开后才能这样做。 Consider Action<array<double>^>^ instead, but do read the next bullet. 考虑使用Action<array<double>^>^代替,但请阅读下一个项目符号。

Some other quirks that you need to pay attention to: 您需要注意的其他一些怪癖:

  • Beware of the calling convention that the native code assumes on the function pointer. 注意本机代码在函数指针上采取的调用约定。 The default is __cdecl, your delegate however is only compatible with __stdcall. 默认值为__cdecl,但是您的委托仅与__stdcall兼容。 If it is not __stdcall then you must apply the [UnmanagedFunctionPointer] attribute to declare the calling convention. 如果不是__stdcall,则必须应用[UnmanagedFunctionPointer]属性来声明调用约定。

  • A very tricky issue with the stubPointer variable is that it can become invalid before you make the native function call. stubPointer变量的一个非常棘手的问题是,在调用本机函数之前,它可能变得无效。 That will happen, very rarely, when other threads in your program run managed code and one of them triggers a garbage collection. 当程序中的其他线程运行托管代码并且其中一个触发垃圾回收时,这种情况很少发生。 You must write GC::KeepAlive(function); 您必须编写GC :: KeepAlive(function); after the function call to ensure this cannot go wrong, that extends the reported lifetime of the delegate object. 在确保确保不会出错的函数调用之后,这将延长报告的委托对象的生存期。

  • Copying the arrays is inefficient and not necessary. 复制数组效率低下,没有必要。 You can use pin_ptr<double> to avoid this. 您可以使用pin_ptr<double>避免这种情况。 That generates a pointer to the first element of the array and pins it for the lifetime of the function body. 这将生成一个指向数组第一个元素的指针,并将其固定在函数体的整个生命周期中。 The native code addresses the array elements directly from the GC heap. 本机代码直接从GC堆寻址数组元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用moq断言在C#中调用的函数? - How do I use moq to assert a function is called in c#? 如何从C#中的另一个类调用函数 - how can function called from another class in C# 如何从 Python 将 ulong 类型参数传递给 C# 函数? - How do I pass a ulong type argument to a C# function from Python? 在ASP.net C#中,如何将参数从Javascript函数传递给onclick处理程序 - In ASP.net C# how do I pass an argument from a Javascript function to the onclick handler C#使用CPP中未知数量的args调用CPP函数 - C# invoking CPP function with unknown number of args from CPP 如何编组包含 function 指针的 ac/cpp 结构? - How do I Marshal a c/cpp struct containing a function pointer? 如何在C#中的函数中创建动态(?)变量? - How do I create a dynamic (?) variable in a function in C#? 我如何在 C# 中创建一种方法或 function 可以减少数据库中的库存,因为它正在超市出售 - How do i create a method or function in C# that can reduce the stock in the database as it is being sold in the supermarket 如何将 function 传递给 C# class dll,这是我从另一个 C# 应用程序调用的? function 在调用 dll 的应用程序中定义 - How can I pass a function to a C# class dll, that I am calling from another C# app? The function is defined in the app where the dll is called 如何在C#中创建MySql函数? - How can I create a MySql function in C#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM