views:

489

answers:

3

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.)

+1  A: 

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.

Andy
+1  A: 

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);
Hans Passant
Ah, thank you!The key for this problem was that in C++ the array is declared as double[][], but in C# as double[,]. Although the former is legal C# syntax, it does not represent the same internal organization.Without that key piece of insight, it wouldn't work.
Mark T
A: 

use swig, it will generate your pinvoke for you

iterationx