I'm trying to call a FORTRAN77 subroutine from C# code using P/invoke - in case you're interested, I'm trying to wrap some of the functionality offered by the ARPACK library (http://www.caam.rice.edu/software/ARPACK). I have 2 questions.
First off, I couldn't find clear instructions anywhere regarding type marshalling in this context. More specifically, here are the types that are declared in my FORTRAN subroutine:
subroutine getEigenVectors
& ( Matrix, n, which, nev, ncv, maxn, maxnev, maxncv, ldv, v, d)
c %------------------%
c | Scalar Arguments |
c %------------------%
character which*2
integer n, nev, maxn, maxnev, maxncv, ldv
c %-----------------%
c | Array Arguments |
c %-----------------%
c
Real
& Matrix(n,n), v(ldv,maxncv), d(maxncv,2)
I found some valuable info here: What Should I MarshalAs for Character Type in Fortran?, from which I implied (I might be wrong) that I should use:
[MarshalAs(UnmanagedType.I4)] int
to pass in integers[MarshalAs(UnmanagedType.LPArray)] byte[]
to pass in character strings
However, I have absolutely no idea what to do with the Real
arrays. Does anyone have any idea on that?
Secondly, I am confused as to whether I should pass my arguments as reference or not. I am by no means familiar with FORTRAN - I know, that makes the task a little difficult; however, only ARPACK does what I would like to do.I did read somewhere though that FORTRAN subroutines take all their arguments as reference by default. Should I therefore pass all arguments as references?
Thanks in advance for your help! Guillaume
EDIT (8/6/11)
So here's my final take:
[DllImport("Arpack.dll", EntryPoint = "#140")]
private static extern void getEigenVectors(
[MarshalAs(UnmanagedType.LPArray)] ref float[,] matrix,
[MarshalAs(UnmanagedType.I4)] ref int n,
[MarshalAs(UnmanagedType.LPArray)] ref byte[] which,
[MarshalAs(UnmanagedType.I4)] int whichLength,
[MarshalAs(UnmanagedType.I4)] ref int nev,
[MarshalAs(UnmanagedType.I4)] ref int ncv,
[MarshalAs(UnmanagedType.I4)] ref int maxn,
[MarshalAs(UnmanagedType.I4)] ref int maxnev,
[MarshalAs(UnmanagedType.I4)] ref int maxncv,
[MarshalAs(UnmanagedType.I4)] ref int ldv,
[MarshalAs(UnmanagedType.LPArray)] ref float[,] v,
[MarshalAs(UnmanagedType.LPArray)] ref float[,] d
);
Several things I did here:
- Pass
int
objects marshalled asUnmanagedType.I4
to match FORTRANinteger
objects - Pass
float[,]
objects of size (m, n) and marshalled asUnmanagedType.LPArray
to match FORTRANReal(n,m)
objects Pass
byte[]
objects obtained marshalled asUnmanagedType.LPArray
to match FORTRANCharacter*n
objects. Thebyte[]
objects are computed as follows:System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] which = encoding.GetBytes(myString);
- Pass an
int
object BY VALUE and marshalled asUnmanagedType.I4
to indicate the length of the string. Note that I tried to put that argument right after the string as well as at the end of the arguments list.
This is my best shot - neither this nor all the other things I tried worked. The method will execute, however it exits super fast (when it's supposed to be doing some pretty severe computations). Moreover, my 3 arrays are transformed into weird uni-dimensional arrays. Here what the debugger gives me:
Any idea?