IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

P/Invoke C# + Fortran77


Sujet :

C#

  1. #1
    Membre habitué Avatar de wil4linux
    Inscrit en
    Février 2005
    Messages
    205
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2005
    Messages : 205
    Points : 174
    Points
    174
    Par défaut P/Invoke C# + Fortran77
    Bonjour,
    J'ai des problèmes pour appeler une librarie fortran.
    je n'arrive pas à trouver le prototype C# permettant d'appeler la méthode SetData.
    J'ai Visual Fortran d'un côté et VS2012 de l'autre.
    J'ai fait une appli console c#. j'ai paramétré cette application pour pouvoir exécuter ma DLL fortran en mode debug.

    code fortran:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    SUBROUTINE SETDATA(VBARRAY_PTR,NUM_ELEMENT)
            $ ATTRIBUTES DLLEXPORT::SETDATA
    	!dec$ ATTRIBUTES ALIAS :'SetData'::SETDATA
     
    C	VBARRAY : array of type VB F_LSP_FILE
    C	NUM_ELEMENT : NUmber of elements in the array 
    	! Definition of the VBARRAY  structure 
     
    	use type_Vb
    	use dfcom
    	use dfnls
     
    	implicit none
    	Integer NUM_ELEMENT
     
    	!  Declare ARRAY_PTR to be a pointer to an integer
    	integer dummy
    	pointer(VBARRAY_PTR,dummy) 
     
    	! Declare a pointer to the head of VB F_LSP_FILE structure
    	pointer (F_File_ptr,F_LSP_File_data)
     
    	type(F_LSP_File) :: F_LSP_File_Data(NUM_ELEMENT)
     
    	character(100) FileName
    	character(255) FilePath
    	character(100) TypeName
    	character(100) FormatName
    	character(3) Extention
    	integer*2 EngineIndice
     
    	include "tlccom.for"
     
    	character*255 LOGFILE
     
          COMMON /TAPEWIN/ LOGFILE
     
    	integer status
    	integer i
    	! Use the SafaArray routine to get address of the F_LSP_DATA structure
     
    	status=safeArrayAccessData(VBARRAY_PTR,F_File_ptr)
     
    	! get info
     
    	do i =1,NUM_ELEMENT
     
    	! loop for all files
     
    		status = MBConvertUnicodeToMB(F_LSP_File_Data(i).FileName,
         +			FileName)
    		status= MBConvertUnicodeToMB(F_LSP_File_Data(i).FilePath,
         +		FilePath)
     
    		status= MBConvertUnicodeToMB(F_LSP_File_Data(i).TypeName,
         +		TypeName)
     
    		status= MBConvertUnicodeToMB(F_LSP_File_Data(i).FormatName,
         +		FormatName)
     
    		status= MBConvertUnicodeToMB(F_LSP_File_Data(i).Extention,
         +		Extention)
    		EngineIndice=F_LSP_File_Data(i).IndexEngine
     
    (...)
    Le code fortran fait référence à ce fichier. De ce que j'ai compris, fortran ne permet pas d'inclure des types characterdans une struct, c'est pourquoi le type F_LSP_File a été redéfini dans la méthode SetData, remplaçant les integer*2 par des Character(N).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    module type_Vb
       ! Use of type F_LSP_File from VB
     
       ! The Visual Basic declaration is:
     
       !Type F_LSP_Files
       ! FileName as String*100
       ! FilePath As String*255
       ! TypeName as String*100
       ! FormatType As String*100
       ! Extention As String*3
       ! IndexEngine as Integer
       !End Type
       !--------------------------------------------------------------------
       implicit none
     
     
       !Type declarations
    !dec$ pack : 4
       type F_LSP_File
       ! Strings are passed as Unicode, and so must be defined as arrays
       !  of Integer*2
          sequence
          integer*2      :: FileName(100)
    	  integer*2      :: FilePath(255)
    	  integer*2      :: TypeName(100)
    	  integer*2      :: FormatName(100)
    	  integer*2      :: Extention(3)
    	  integer*2		 :: IndexEngine
     
       end type F_LSP_File
     
     end module type_vb
    Côté C# cela donne ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
            [StructLayout(LayoutKind.Sequential)]
            public struct F_Lsp_File
            {
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
                public string FileName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)]
                public string FilePath;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
                public string TypeName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
                public string FormatName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
                public string Extention;
     
                [MarshalAs(UnmanagedType.I2, SizeConst = 2)]
                public short IndexEngine;
            }
     
    [DllImport("LSPTOW.dll", EntryPoint = "SetData", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
            public static extern void LSP_SetData(
                [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.Struct)]  ref F_Lsp_File[] Fos_Data,
                ref int Num_Elem);
    J'ai toujours des problèmes de violation mémoire, ou de type non attendu... je ne sais plus trop quoi tester...

    le code fortran suivant:
    status=safeArrayAccessData(VBARRAY_PTR,F_File_ptr) inclut surement d'utiliser des types SafeArray. j'ai même essayer les attributs de ce type dans ma signature [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.Struct)], sans résultats...

    J'ai déja réussi a passer des valeurs dans les variables correspondantes (FilePath, Filename...) il faut bien forcer l'unicode côté c# avec UnmanagedType.BStr sur les variables de la structure, mais tout était désordonné.

    Please help

  2. #2
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour wil4linux
    De ce que j'ai compris, fortran ne permet pas d'inclure des types characterdans une struct, c'est pourquoi le type F_LSP_File a été redéfini dans la méthode SetData, remplaçant les integer*2 par des Character(N).
    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):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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...:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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....

  3. #3
    Membre habitué Avatar de wil4linux
    Inscrit en
    Février 2005
    Messages
    205
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2005
    Messages : 205
    Points : 174
    Points
    174
    Par défaut
    je ne connaissais pas le Pack 8...je testais en pack 1...

    Merci beaucoup. Je teste de suite !

  4. #4
    Membre habitué Avatar de wil4linux
    Inscrit en
    Février 2005
    Messages
    205
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2005
    Messages : 205
    Points : 174
    Points
    174
    Par défaut
    Citation Envoyé par MABROUKI Voir le message
    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):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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...:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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....
    Bon toujours des problèmes...
    mon tableau de structures, je suis obligé d'utiliser le mot clé ref, sinon exception.
    Ca marche aussi comme ceci, avec un pointeur.
    Voici en dessous les 2 fonctions qui ne génère pas d'erreurs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    [DllImport("LSPTOW.dll", EntryPoint = "SetData",
                CallingConvention = CallingConvention.StdCall, CharSet=CharSet.Auto)]
            public static extern void LSP_SetData7(
                [In, Out] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStruct)] ref Fos_Lsp_File7[] Fos_Data,
                [In, Out] ref int Num_Elem);
     
            [DllImport("LSPTOW.dll", EntryPoint = "SetData",
                CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
            public static extern void LSP_SetData77(
                ref IntPtr Fos_Data,
                [In, Out] ref int Num_Elem);
    Côté fortran j'ai toujours un décalage entre chaque élement de structure. je voit bien mes données côté fortran. je suis en dec$ pack : 4. Comment le force-ton en 8 ??

    En fortran : quelle est la différence entre
    character(100) FileName ET character*100 FileName ??

    Merci

  5. #5
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    rebonjour wil4linux
    Côté fortran j'ai toujours un décalage entre chaque élement de structure. je voit bien mes données côté fortran. je suis en dec$ pack : 4. Comment le force-ton en 8 ??
    Deja donne(recommende meme) dans le code fortran communique precedent post...!
    le voici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    !Declaration du Type 
       !Pas de probleme avec les chaines 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
    En fortran : quelle est la différence entre
    character(100) FileName ET character*100 FileName ??
    Aucune......il existe aussi une autre version:
    CHARACTER*(*)....quand c'est une chaine passee comme argument d'un subroutine,mais dans ce cas la longueur de chaine est cense etre fourni par un autre argument du subroutine...

    J'ai comme l'impression aussi que, en plus du probleme d'alignement , tu persistes à utiliser le "ref" ce qui explique tes deboires car si tu transmets un "pointeur" ce sera un pointeur type "CRAY" (integer*4) du fortran qui doit etre utilise
    Comme celui de l'exemple du SafeArray ,car son dereferencement sera assez complique pour acceder à sa valeur ......
    Pareillement si tu utilise un code "unsafe" avec un IntPtr....

    Le pointeur "CRAY" a ete en fait introduit en ViSUAL Fortran pour faire plutot l'inverse c.à.d passer des "arguments type pointeur" vers les langages qui supportent des pointeurs(c,c++,masm)..

    Voir doc VS Fortran topic POINTER - Compaq Fortran.....

    C'est pour cela que le code communique evite les complications dues au passage d'un pointeur "CRAY"...et passe simplement un tableau:
    -à la convention fortran
    -à la convention C# par valeur et specifie [IN,OUT] ...et tenant compte en plus du comportement du marshaleur d'interoperability suivant :
    Rappel :
    Les tableaux sont passes par defaut par valeur(en entree) par le marshalleur d'interopérabilité d'ou l'exigence de mettre [IN,OUT].....
    CITATION MSDN
    Dans une application composée dans son ensemble de code managé, le Common Language Runtime passe des types tableau comme paramètres en entrée/sortie.
    Par contre, le marshaleur d'interopérabilité passe un tableau comme paramètre en entrée par défaut.
    Autre point important la Configuration du projet fortan:
    project settings ->panneau fortran->
    combo dataoptions =>cocher :allow sequence types to be padded for alignement
    combo default real kind =>mettre :8 (double 8 octets)
    combo default integer =>mettre :4 (int32 4 octets)

    combox common alignement type => mettre : neant(concerne les applications fortran)
    combox structure alignement type => mettre : 8


    bon courage et code...........

  6. #6
    Membre habitué Avatar de wil4linux
    Inscrit en
    Février 2005
    Messages
    205
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2005
    Messages : 205
    Points : 174
    Points
    174
    Par défaut
    OK parfait ! ton code fonctionne bien, pas de problème.

    En fait pour transmettre mes données côté fortran, j'ai été obligé de modifier le code fortran pour que la subroutine prenne en entrée directement un tableau de Struct contenant des Character.

    Dans le code existant ce n'était pas le cas. Je devais transmettre un tableau de struct contenant des integer*2 car les string qui étaient passées depuis VB6, étaient envoyés dans un format unicode. Ensuite dans la subroutine, on parsait chacun des élements de cette structure de integer*2 puis on décodait les integer*2 dans des character(LEN) en fonction via le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    character*100 FileName
    status = MBConvertUnicodeToMB(FOS_LSP_File_Data(i).FileName, FileName)
    Du coup j'ai trouvé une bonne alternative. maintenant je vais essayé de voir si le peux passer par la structure initiale avec les integer*2.

  7. #7
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    rebonjour wil4linux

    Bah il suffit de marshaller la structure avec CharSet=Unicode cote C#..
    Et de redeclarer tes tableaux de char fortran en tableaux d'integer*2 avec les dimensions appropries (100,255,etc...)
    Ensuite tu accedes aux elements des tableaux via les fonctions de la lib DFNLS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    'n'oublie pas ceci
    USE DFNLS
     
    character*100  fileName 
    character*255 filePath 
     
    status = MBConvertUnicodeToMB(arrStruct(i).FileName, fileName)
    status = MBConvertUnicodeToMB(arrStruct(i).FileName, filePath)
    L'ecriture se faisant par les fonctions inverses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      fileName='FileName fortran MB'
      status = MBConvertMBToUnicode (fileName,arrStruct(i).FileName ) 
     
      filePath= 'FilePath fortran MB' 	
      status = MBConvertMBToUnicode (filePath, arrStruct(i).FilePath  )
    bon code..............

  8. #8
    Membre habitué Avatar de wil4linux
    Inscrit en
    Février 2005
    Messages
    205
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Février 2005
    Messages : 205
    Points : 174
    Points
    174
    Par défaut
    Merci pour tes réponses.
    J'ai ré-essayé sur cette voie en passant direct de l'unicode... sans succès.. toujours un violation exception côté C#.

    J'ai beau forcer le charset unicode et gardant le même prototype que celui fonctionnant en ANSI... marche pas ...

    J'ai mis un Pack 4 sur ma structure c# car côté Fortran, mon projet ne compile plus sur la structure d'integer*2 si je mets un pack 8. Pourtant, sur la struct de character fortran, le pack 8 fonctionne...

    Citation Envoyé par MABROUKI Voir le message
    rebonjour wil4linux

    Bah il suffit de marshaller la structure avec CharSet=Unicode cote C#..
    Et de redeclarer tes tableaux de char fortran en tableaux d'integer*2 avec les dimensions appropries (100,255,etc...)
    Ensuite tu accedes aux elements des tableaux via les fonctions de la lib DFNLS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    'n'oublie pas ceci
    USE DFNLS
     
    character*100  fileName 
    character*255 filePath 
     
    status = MBConvertUnicodeToMB(arrStruct(i).FileName, fileName)
    status = MBConvertUnicodeToMB(arrStruct(i).FileName, filePath)
    L'ecriture se faisant par les fonctions inverses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      fileName='FileName fortran MB'
      status = MBConvertMBToUnicode (fileName,arrStruct(i).FileName ) 
     
      filePath= 'FilePath fortran MB' 	
      status = MBConvertMBToUnicode (filePath, arrStruct(i).FilePath  )
    bon code..............

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 30/01/2006, 12h10
  2. org.apache.axis.client.invoke() en exception
    Par ep31 dans le forum Services Web
    Réponses: 2
    Dernier message: 27/01/2006, 15h26
  3. [C#]Comment utiliser P/Invoke ?
    Par pataphysicien dans le forum C#
    Réponses: 3
    Dernier message: 19/01/2006, 01h58
  4. [SOAP] Invoke en ligne de commande
    Par ouechouech dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 30/09/2005, 09h27
  5. [Com] Interface IDispatch.Invoke
    Par Laurent Dardenne dans le forum Windows
    Réponses: 4
    Dernier message: 15/06/2004, 22h51

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo