键入编组调用从C#,Fortran子例程 [英] Type marshalling to call a fortran subroutine from C#

查看:113
本文介绍了键入编组调用从C#,Fortran子例程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用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:

    作为编组 UnmanagedType.I4 来匹配FORTRAN
  • INT 对象整数对象

  • 浮法[,] 尺寸(M,N)和编组为对象 UnmanagedType.LPArray 来匹配FORTRAN 雷亚尔(N,M)对象

  • 字节[] 对象中获取编组为 UnmanagedType.LPArray 来匹配FORTRAN 字符* ñ的对象。在字节[] 对象的计算方法如下:

  • Pass int objects marshalled as UnmanagedType.I4 to match FORTRAN integer objects
  • Pass float[,] objects of size (m, n) and marshalled as UnmanagedType.LPArray to match FORTRAN Real(n,m) objects
  • Pass byte[] objects obtained marshalled as UnmanagedType.LPArray to match FORTRAN Character*n objects. The byte[] objects are computed as follows:

System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] which = encoding.GetBytes(myString);


  • 传递 INT 对象按价值计算,整理为 UnmanagedType.I4 来表示字符串的长度。请注意,我试图把该参数字符串之后以及在参数列表的末尾。

  • Pass an 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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆