简体   繁体   中英

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#. I already have several (cpp) functions that i can call from c#, but only with simple arguments (arrays and primitives).

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#; 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'. 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)?

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

You forgot to declare it 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. Consider Action<array<double>^>^ instead, but do read the next bullet.

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. If it is not __stdcall then you must apply the [UnmanagedFunctionPointer] attribute to declare the calling convention.

  • A very tricky issue with the stubPointer variable is that it can become invalid before you make the native function call. 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); 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM