Question

I have some ANSI standard C code which is authoritative. What that means is that although I have the source, I can not translate to another language nor modify calling arguments, as those actions would invalidate the authority. There are over 150 functions.

I can make incidental changes, such as change the file names from .C to .CPP so that it compiles using Visual Studio 2009's C++ compiler, which I have done. Compiler directives and such can also be added. I can also go through a wrapper layer, if necessary.

Another restriction is my company does not want me to use the unsafe key word in any C# code.

I need to get at these functions from a C# program.

A typical C/C++ function looks like this:
double SomeFunction(double a, double[3] vec, double[3][3] mat);
Where the array contents are sometimes input, sometimes output, and rarely both.

I first tried making an unmanaged DLL (with the functions marked Extern C). Functions with only simple arguments (int, double) worked fine, but I could not determine how to Marshal the arrays. (Actually, I did find some sample code, but it was extremely complex and unreasonable to duplicate 150 times.)

I then tried two projects within the same solution, one in C++ and the other in C#. In the C++ project, I created a managed function which just called the original function which was marked as unmanaged. This was extremely clean and simple, and again, simple arguments worked fine. But for arrays, I couldn't find how to make the argument types match across the C# to C++ boundary:
Argument '2': cannot convert from 'double[]' to 'double*'
(and as mentioned above, I can't use unsafe to get a pointer).

Certainly what I am trying to do must be possible.
What is the best way to get at these functions?
(Sample code using the above function would be really cool.)

Was it helpful?

Solution

Sample C/C++ implementation:

extern "C" __declspec(dllexport)
double SomeFunction(double a, double vec[3], double mat[3][3]) {
  double sum = a;
  for (int ix = 0; ix < 3; ++ix) {
    sum += vec[ix];
    for (int iy = 0; iy < 3; ++iy) {
      sum += mat[ix][iy];
    }
  }
  return sum;
}

Sample C# usage:

private void Form1_Load(object sender, EventArgs e) {
  double[] vec = new double[3];
  double[,] mat = new double[3, 3];
  for (int ix = 0; ix < 3; ++ix) {
    vec[ix] = ix;
    for (int iy = 0; iy < 3; ++iy) {
      mat[ix, iy] = (ix + 1) * iy;
    }
  }
  double sum = SomeFunction(1, vec, mat);
}
[System.Runtime.InteropServices.DllImport("cpptemp8.dll")]
private static extern double SomeFunction(double a, double[] vec, double[,] mat);

OTHER TIPS

If you can't get the extern and P/Invoke solution to work, a wrapper is probably your best bet. Create a managed C++ DLL that uses both managed and unmanaged code. Add a .NET class to this DLL that is just a thin wrapper over the functions in your C DLL. Your C# code can call the C++ .NET class, which will in turn forward on the C functions.

This way you can write the translation between .NET and unmanaged code yourself, instead of relying on the runtime to do it for you.

use swig, it will generate your pinvoke for you

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top