键入编组调用从C#,Fortran子例程 [英] Type marshalling to call a fortran subroutine from C#
问题描述
我试图使用P / Invoke调用从C#代码FORTRAN77子程序 - 如果你有兴趣,我试图总结一些(由ARPACK库提供的功能的 http://www.caam.rice.edu/software/ARPACK )。我有2个问题。
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.
首先,我找不到任何地方就在这种背景下型编组站明确的指示。更具体地讲,这里是在我的FORTRAN子程序声明的类型:
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)
我发现了一些有价值的信息在这里:
我应该的MarshalAs ?在Fortran语言字符类型,从中我暗示(我可能是错的),我应该使用:
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
在整数传递 -
[的MarshalAs(UnmanagedType.LPArray)字节[]
来的字符串传递
[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?
其次,我很困惑,我是否应该通过我的论点作为参考与否。我绝不熟悉FORTRAN - 我知道,这使得任务有点困难;然而,只有ARPACK做我想做,我没地方读尽管这FORTRAN子程序采取一切它们的参数作为默认的引用内容。 我应该因此通过所有参数作为参考?
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
修改(11年8月6日)
因此,这里是我的最终看法:
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:
- 作为编组
- 通
INT
对象整数
对象 - 通
浮法[,]
尺寸(M,N)和编组为对象UnmanagedType.LPArray
来匹配FORTRAN雷亚尔(N,M)
对象 -
通
字节[]
对象中获取编组为UnmanagedType.LPArray
来匹配FORTRAN字符* ñ
的对象。在字节[]
对象的计算方法如下:
UnmanagedType.I4
来匹配FORTRAN - 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);
INT
对象按价值计算,整理为 UnmanagedType.I4
来表示字符串的长度。请注意,我试图把该参数字符串之后以及在参数列表的末尾。
int
object BY VALUE and marshalled as UnmanagedType.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.这是我最好的射击 - 非此非彼的所有其他的事情我试着努力。该方法将执行,但它退出超快速(当它应该做一些相当严重的计算)。此外,我的3个阵列被转化成怪异单维数组。在这里,有什么调试器给我:
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:
任何想法?
推荐答案
我建议你先一些小的测试代码。一些子程序用简单的参数编译FORTRAN .dll和玩弄的 C#的获取调用工作。你也不妨与许多论据来包装的Fortran成一个单一的结构(键入
关键字),这使得互操作容易得多。
I suggest you start with some small test code. Compile a FORTRAN .dll with some subroutines with simple parameters and play around with C# to get the calling to work. Also you may wish to wrap the Fortran with many arguments into a single structure (TYPE
keyword), which makes the interop so much easier.
下面是一个工作的例子,你可以用得到它是如何工作的很多想法
Here is a working example that you can use the get many ideas of how it works.
原始FORTRAN代码:
Original FORTRAN code:
SUBROUTINE CALC2(BLKL,BLKW, N_LAMINA,N_SLICE, LOAD, SLOP,SKW, &
DIA1,DIA2, Y1, Y2, N1, N2, DROP1, DROP2, &
PARRAY, P_MAX, P_MAX_INDEX, ENDEFCT)
!DEC$ ATTRIBUTES DLLEXPORT :: CALC2
!DEC$ ATTRIBUTES ALIAS:'CALC2' :: CALC2
!DEC$ ATTRIBUTES VALUE :: BLKL, BLKW, N_LAMINA, N_SLICE, LOAD, SLOP, SKW
!DEC$ ATTRIBUTES VALUE :: DIA1, DIA2, Y1, Y2, N1, N2
IMPLICIT NONE
INTEGER*4, INTENT(IN) ::N_LAMINA, N_SLICE
REAL*4, INTENT(IN) :: BLKL, BLKW, LOAD, SLOP, SKW, &
DIA1, DIA2, Y1, Y2, N1, N2, &
DROP1(MAX_LAMINA), DROP2(MAX_LAMINA)
REAL*4, INTENT(OUT):: PARRAY(MAX_PATCH), P_MAX
INTEGER*4, INTENT(OUT) :: P_MAX_INDEX, ENDEFCT
INTEGER*4 :: NDIAG, N_PATCH
REAL*4 :: SLNG, SWID
REAL*4 :: DROPS_1(MAX_LAMINA), DROPS_2(MAX_LAMINA)
...
END SUBROUTINE CALC2
在不同的标量和数组值真正的和以整数形式。例如 DROP1
输入一维数组。 粒子阵列
是一个允许输出二维数组作为一维数组。 BLKL左张力传感器
输入浮动。
with various scalar and array values in real and integer form. For example DROP1
is input 1D array. PARRAY
is outputing a 2D array as a 1D array. BLKL
are input floats.
注意!DEC $属性value
装修要避免宣告一切, REF
。
Notice the !DEC$ ATTRIBUTES VALUE
decoration to avoid declaring everything as ref
.
在 C#的代码由
[DllImport("mathlib.dll")]
static extern void CALC2(float major_dim, float minor_dim,
int N_lamina, int N_slices, float total_load,
float slope, float skew, float diameter_1, float diameter_2,
float youngs_1, float youngs_2, float nu_1, float nu_2,
float[] drops_1, float[] drops_2, float[] pressures,
ref float p_max, ref int p_max_index, ref EndEffect end_effect);
...
{
float max_pressure = 0;
int max_pressure_index = 0;
float[] pressures = new float[Definition.MAX_PATCH];
EndEffect end_effect = EndEffect.NO;
CALC2(length, width, lamina_count, slice_count, load, slope, skew,
dia_1, dia_2, y_1, y_2, n_1, n_2, drops_1, drops_2, pressures,
ref max_pressure, ref max_pressure_index, ref end_effect);
}
的注意的我不传递任何字符串。
note I do not pass any strings.
这篇关于键入编组调用从C#,Fortran子例程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!