5

Right, what is needed sounds simple, but it is proving to be a real pain.

I have some GUI code in C# (note i've never used C# before but familiar with the syntax) and I have C++ code which interacts with it using CLI.

In C#, I want to create an array of doubles, and send it to my C++ code. I'm using the code below as the means of passing an array, and this complies in isolation.

So from C# im passing in a double[] array into that function.

public ref class KernelWrapper
{
public: 
    static void ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, array<double>^ values); 

What parameter type should I use to retrieve this array from the C++ side?

I've tried:

 MyFunction(double values[]){}
 MyFunction(double* values){}
 MyFunction(array<double>^ values){} 

but none compile, usually with the message of "array is not a template" for the last one, and

Error   1   error C2664: 'RunImageNoiseFilterKernel' : cannot convert parameter 4 from 'cli::array<Type> ^' to 'double *'

Any tips on how this achieve this will be greatly appreciated.


For readability, I'm updating with code up here

.cpp file:

void Bangor::KernelWrapper::ImageNoiseFilter(System::IntPtr imageData, int imageWidth,    int imageHeight, pin_ptr<double> pval){
    RunImageNoiseFilterKernel((Format24bppRgb*)((int)imageData), imageWidth, imageHeight); //If parameter would work, 4th argument would also be passed into this.
}

C# code:

    double[] randomValues = new double[ARRAY_LENGTH]; //Array of random numbers
    KernelWrapper.ImageNoiseFilter(ptr, image.Width, image.Height, randomValues);

The errors are:

Error   1   error C3824: 'cli::pin_ptr<Type>': this type cannot appear in this context (function parameter, return type, or a static member)
Error   3   The best overloaded method match for 'Bangor.KernelWrapper.ImageNoiseFilter(System.IntPtr, int, int, double*)' has some invalid arguments   
Error   4   Argument 4: cannot convert from 'double[]' to 'double*' 

Hope this clarifies a little.

5
  • Have you tried adding the cli namespace to array<double>^? Like this: cli::array<double>^ values. Note that there also is a std::array. Perhaps a namespace clash because of using namespace-directives? Commented Mar 17, 2013 at 13:51
  • Do you mean as a parameter inside MyFunction()? Error 1 error : name followed by "::" must be a class or namespace name is the result of that, followed by lots of expected a ")" errors. If you meant inside ImageNoiseFiler it makes no difference. Commented Mar 17, 2013 at 14:15
  • 1
    You don't really need to qualify with cli. The third signature you show is the correct one. What error message do you get when you use that one? Commented Mar 17, 2013 at 14:20
  • Are you certain you are compiling with the /clr option? I assume you're compiling from within VS. If so, the appropriate options should be buried somewhere in [your-project]->properties. Commented Mar 17, 2013 at 14:25
  • error : name followed by "::" must be a class or namespace name error : expected an identifier error : invalid combination of type specifiers error : expected a ")" those are the errors I get using the 3rd. /clr is being used, yes. Commented Mar 17, 2013 at 14:39

2 Answers 2

3

You should use the pin_ptr<> class to convert the managed array to a double*. It pins the array so the garbage collector cannot move it while your native function is executing and accessing the array data.

#include <vcclr.h>                 // Declares cli::pin_ptr<>
using namespace cli;
#pragma managed(push, off)
#  include "unmanagedstuff.h"      // Declaration of MyFunction here
#pragma managed(pop)

...

        pin_ptr<double> pvalues = &values[0];
        MyFunction(pvalues, values->Length);

With the assumption that surely MyFunction() also needs to know the size of the array so I added an extra argument that passes the size of the array. Not doing this is lethal, your native code is liable to destroy the managed heap integrity. Note that the array will only stay pinned while pvalues is in scope so it is important that MyFunction() does not store the passed pointer. If that's the case then you must copy the array.

Sign up to request clarification or add additional context in comments.

3 Comments

Not sure I follow this I'm afraid. If I declare a function which takes in a pin_ptr, i get this error: error C3824: 'cli::pin_ptr<Type>': this type cannot appear in this context (function parameter, return type, or a static member) and if I put it in the C# code, it won't accept it.
You put that inside of your ImageNoiseFilter() function. I can't guess where you might have put it.
I've updated the main post to highlight what I changed and what errors I get.
2

Okay, so most attempts have failed for me; likely because I'm doing it wrong :P, but here is a solution which does work.

Imports:

using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;

In the C# file, I create an array as so:

    float[] randomValues = new float[ARRAY_LENGTH]; //Array of random numbers
    GCHandle handle = GCHandle.Alloc(randomValues, GCHandleType.Pinned);
    var randPtr = handle.AddrOfPinnedObject();
    KernelWrapper.ImageNoiseFilter(ptr, image.Width, image.Height, randPtr);

The definition of ImageNoiseFilter is:

static void ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, System::IntPtr randValPtr);

To obtain in my C++ function which expects a float pointer, I do this:

void KernelWrapper::ImageNoiseFilter(System::IntPtr imageData, int imageWidth, int imageHeight, System::IntPtr randValues){
    RunImageNoiseFilterKernel((Format24bppRgb*)((int)imageData), imageWidth, imageHeight, (float*) ((int) randValues));
}

All this seems to work fine :), how good or safe this approach is I do not know, so anyone reading this should not assume its the "correct" approach, it just works.

1 Comment

+1 This is exactly what gcroot template is doing internally. I discovered it after reading your answer. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.