views:

406

answers:

1

I have some legacy code I want to port to C#. I cannot modify the C++ code, I just have to make do with what I'm given.

So, the situation. I'm using SwIG, and I came across this function:

void MarshalMe(int iNum, FooClass** ioFooClassArray);

If I ran SWIG over this, it wouldn't know what to do with the array, so it will create a SWIGTYPE_p_pFooClass. Fair enough! C# code for this would look like

void MarshalMe(int iNum, SWIGTYPE_p_p_FooClass ioFooClassArray); // Not ideal!

There are some techniques for marshalling this kind of code correctly, so I tried a few of them:

%typemap(ctype)   FooClass** "FooClass**"
%typemap(cstype)  FooClass** "FooClass[]"
%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") FooClass** "FooClass[]"
%typemap(csin)    FooClass** "$csinput"
%typemap(in)      FooClass** "$1 = $input;"
%typemap(freearg) FooClass** ""
%typemap(argout)  FooClass** ""

This effectively creates a nicer signature:

void MarshalMe(int iNum, FooClass[] ioFooClassArray); // Looks good! Would it work?

However, when I try to run it, I get the following error:

{"Exception of type 'System.ExecutionEngineException' was thrown."}

Any ideas about the actual typemap?

+1  A: 

The exception tells you that the function has corrupted the garbage collected heap. It writing past the end of the array. If it is actually a FooClass[], big question, then you'll have to create the array first:

 FooClass[] array = new FooClass[666];
 MarshalMe(42, array);

Which assumes that the function will fill the array with FooClass objects. The size of the array really matters here, you'll have to have some kind of idea how many elements you'll get back. That can only work reliable if "iNum" is an argument that says how long the array is. Pass array.Length.

It could also mean that the function will create the array itself and return a pointer to it. You're really screwed if that's the case, you cannot release the memory for the array.

Hans Passant