Type marshalling to call a fortran subroutine from C#

后端 未结 2 1839
忘了有多久
忘了有多久 2021-01-23 01:36

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

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-23 02:05

    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.

    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
    

    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.

    Notice the !DEC$ ATTRIBUTES VALUE decoration to avoid declaring everything as ref.

    In C# the code is called by

        [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.

提交回复
热议问题