bonjour wil4linux
Faux .Le "Type" fortran permet d'inclure tous type de fields :double,character ,bool ,y compris un autre "type" comme en C#......
Vire cet exemple de code VS parce que c'est un code specifique à VB6 ou une structure s'appelle "Type" (mot cle type vb6)
Ce "type" de VB6 transparent pour les users est en fait un tableau SafeArray win32 ou BSTR(tableau auto-descriptif)......
En fait tu peux simplement utiliser un struc ou meme un class de C#.....qui se "mappe" (correspond) parfaitement au "Type" du fortan mais en respectant les contraintes d'alignement et de marshalling des types......
Relativement à ton code voici les observations :
1/methode P/Invoke:
- appel StdCall
- passer tjrs les args par reference(fortran ne connait pas le passage par valeur)
- exception tableau: "ref" en C# ne s'utilise pas sur un tableau ,car un tableau est toujours passe par reference par defaut (ptr sur le 1er element du tableau)....Si tu mets un ref c'est l'adresse du ptr que tu transmets d'ou acces memory violation....
- Vu cet exception si on veut une valeurs de retour (comme avec un ref) prefixer tableau avec prefixes "In,Out" (ils ont ete crees pour ca).
=>Ils existent aussi cote fortran
2/marshalling de struc
- meme alignement structure (2,4,8 octet) cotes C# et fortran
=>Utiliser Directive c# pack=8) cote Fortran ! Dec pack: 8
=>Uiliser directive Layout.Sequentiel C# cote fortan "sequence"
- string fortran => array de char ANSI(1 octet) et un string C# ) => array de char Unicode(2 octet).
=>Specifie au marshaleur CharSet=ANSI cote C#....
- le struct ou class doit comporter un ctor d'initilisation avec initialisation des tous ses membres.
Moyennant ces precautions on peut passer n'importe quoi à fortran.. un struct ,un class ou un array de struc C# ou de class tres simplement :
Voici un exemple qui passe un array de struct au fortan ,modifie les valeurs et les renvoies à C#...
fichier code "type_struc.f90" du module fortran (declaration de la structure):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
MODULE type_struc
!
! C# Declaration
! //Simple struct C#
! [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 8)]
! public struct SimpleStruct
! {
! [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
! public String FileName;
!
! [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
! public String FilePath;
!
! [MarshalAs(UnmanagedType.I2)]
! public short TotalShort;
!
! [MarshalAs(UnmanagedType.R8)]
! public double TotalDouble;
!
! //Iniatiliser les fields et props du struc
! public SimpleStruct(bool dummyargs)
! {
! FileName = String.Empty;
! FilePath = String.Empty;
! TotalShort = 0;
! TotalDouble = 0.0;
! }
! }
!--------------------------------------------------------------------
IMPLICIT NONE
!Declaration du Type
!Pas de probleme avec les tableaux de caracteres "Ansi"
!comme en C ou C++
!note le pack 8 et le sequence (sequential du c#)
! dec$ pack : 8
TYPE SimpleStruct
SEQUENCE
CHARACTER*100 :: FileName
CHARACTER*255 :: FilePath
INTEGER*2 :: TotalShort
REAL*8 :: TotalDouble
END TYPE SimpleStruct
END MODULE type_struc |
fichier code "ArrayFortranType.f90" du subroutine fortran appele qui utilise le module precedent type_struc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
! Subroutine ArrayFortranType
! Parametre:
! arrStruct: => tableau de type SimpleStruct passe
! num_elem: => nbre d'elements dans le tableau
SUBROUTINE ArrayFortranType(arrStruct, num_elem)
!DEC$ ATTRIBUTES DLLEXPORT :: ArrayFortranType
!DEC$ ATTRIBUTES ALIAS :'ArrayFortranType' :: ArrayFortranType
USE type_string
IMPLICIT NONE
!Prefixes IN OUT car passe par "ref"
INTEGER*4 ,INTENT(INOUT):: num_elem
!Prefixes IN OUT pour avoir une valeur de retour
'Index base des tableaux Fortran => 1
TYPE(SimpleStruct), INTENT(INOUT):: arrStruct(1:num_elem)
LOGICAL :: bstatus
INTEGER :: i, j, k ! Loop variables
!dec$ if defined (DEBUG)
! Pour besoin de deboggage fenetre console ....
bstatus = AllocConsole()
WRITE (6, *) "Info from arrStruct"
DO i = 1 , num_elem
WRITE (6, *) arrStruct(i).FileName
WRITE (6, *) arrStruct(i).FilePath
WRITE (6, *) arrStruct(i).TotalShort
WRITE (6, *) arrStruct(i).TotalDouble
END DO
!dec$ endif
! Now, fill in the fields FileName,FilePath, TotalShort,TotalDouble
DO i = 1, num_elem
arrStruct(i).FileName = 'FileName fortran'
arrStruct(i).FilePath = 'FilePath fortran'
arrStruct(i).TotalShort = arrStruct(i).TotalShort*10
arrStruct(i).TotalDouble = arrStruct(i).TotalDouble*10.0
END DO
!dec$ if defined (DEBUG)
bstatus = FreeConsole()
!dec$ endif
RETURN
END SUBROUTINE |
a compiler en un fichier projet fortan "TestStruc.dll"
fichier code behind .cs du form appelant...:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WinArrayStructFortran
{
public partial class frmArrayStruct : Form
{
StringBuilder sb;
public SimpleStruct ss;
//notre Array struct
public int nbElem = 5;
public SimpleStruct[] arrStruct;
public frmArrayStruct()
{
InitializeComponent();
}
private void btnCalcul_Click(object sender, EventArgs e)
{
}
private void btnArrayStruct_Click(object sender, EventArgs e)
{
// Fill the struct
arrStruct = new SimpleStruct[nbElem];
listBox1.Items.Clear();
sb = new StringBuilder();
for (int i = 0; i < nbElem; i++)
{
sb.Clear();
ss = new SimpleStruct();
ss.FileName = "mon fichier " + (i + 1).ToString();
ss.FilePath = "mes/documents/" + (i + 1).ToString();
ss.TotalShort = 15;
ss.TotalDouble = 50.15;
arrStruct[i] = ss;
sb.Append(ss.FileName + "; " + ss.FilePath + ";" + ss.TotalShort + ";" + ss.TotalDouble + Environment.NewLine);
listBox1.Items.Add(sb);
}
// CallingL
ArrayFortranType(arrStruct, ref nbElem);
// Display result
listBox2.Items.Clear();
listBox2.Items.Add(nbElem );
for (int i = 0; i < arrStruct.Length ; i++)
{
sb.Clear();
ss = arrStruct[i];
sb.Append(ss.FileName.Trim() + "; " + ss.FilePath.Trim() + ";" + ss.TotalShort + ";" + ss.TotalDouble + Environment.NewLine);
listBox2.Items.Add(sb);
}
sb.Append(ss.FileName + "; " + ss.FilePath + ";" + ss.TotalShort + ";" + ss.TotalDouble + Environment.NewLine);
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
/* Declaration methode P/INVOKE */
//Convention d'appel StdCall
//pas de ref devant arrayStruct mais prefixe [In, Out]
[DllImport("TestStruc.dll",
EntryPoint = "ArrayFortranType",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
public static extern void ArrayFortranType(
[In, Out] [MarshalAs(UnmanagedType.LPArray,ArraySubType=UnmanagedType.Struct)] SimpleStruct[] arrStruct,
[In, Out] ref int Num_Elem);
}
/* Declaration Simple struct C# */
//note le CharSet.Ansi & le Pack = 8
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 8)]
public struct SimpleStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public String FileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
public String FilePath;
[MarshalAs(UnmanagedType.I2)]
public short TotalShort;
[MarshalAs(UnmanagedType.R8)]
public double TotalDouble;
//NB:Iniatiliser les fields et props du struc
public SimpleStruct(bool dummyargs)
{
FileName = String.Empty;
FilePath = String.Empty;
TotalShort = 0;
TotalDouble = 0.0;
}
}
} |
Tu peux meme passer un array de Class si tu le souhaites va....
bon code....
Partager