I have an answer, although it's not entirely satisfactory in my view. That's mostly limited by my knowledge of C# though, so you can probably make it work better than I can.
I don't think arrays_csharp is what you're looking for here. It seems to be about pinning memory so it can be used as input to a function, but in your scenario you've got memory already allocated that you'd like to work with.
That's fairly easy (and for a 3D vector pretty cheap), using System.InteropServices.Marshal normally. So I put together a few typemaps using that which does what you want:
%module test
%typemap(csout,excode=SWIGEXCODE) unsigned *getVector {
global::System.IntPtr cPtr = $imcall;$excode
int[] tmp = new int[3];
// I have no idea why Marshal.Copy does not seem to have any support for unsigned types...
global::System.Runtime.InteropServices.Marshal.Copy(cPtr, tmp, 0, 3);
// There is probably a better way to go from int[3] -> uint[3], but it is not obvious to me
return new $typemap(cstype, $*1_type)[3]{($typemap(cstype, $*1_type))tmp[0],($typemap(cstype, $*1_type))tmp[1],($typemap(cstype, $*1_type))tmp[2]};
}
%typemap(cstype) unsigned *getVector "$typemap(cstype, $*1_type)[]"
%inline %{
unsigned *getVector() {
static unsigned arr[3] = {1,2,3};
return arr;
}
%}
A few notes though:
$typemap(cstype, $*1_type)
is a fancy way of saying find me the C# type corresponding to my C element type. I tend to try and avoid explicitly writing types in typemaps as it makes things more generic.
- Having said that
Marshal.Copy
only seems to work with signed rather than unsigned array types, for reasons I can't quite figure out. And I can't see an automatic way to find the corresponding signed type for an unsigned one, so I did have to explicitly write int[]
- I'm not sure that signed -> unsigned casting is actually well defined behaviour in C#. Maybe this won't work properly for values where the last bit is set. You can work around that by increasing the size of the
int
type for tmp
. (E.g. use int64
instead of int32
, but that's not pretty)
- There ought to be a better way to cast a whole array than what I've done, but I don't know the C# language all that well.
That said this is sufficient that I can run the following program (with Mono) and get the output expected
public class runme {
static void Main(string[] args) {
uint[] arr = test.getVector();
System.Console.WriteLine(arr[0]);
System.Console.WriteLine(arr[1]);
System.Console.WriteLine(arr[2]);
}
}
We could do a bunch more work to make this generic (i.e. other size vectors, other datatypes int16[4]
, etc.) if that was useful.