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 :

Appel Dll C++ et pointeur C#


Sujet :

C#

  1. #1
    Membre chevronné Avatar de jacky01
    Profil pro
    Développeur .NET
    Inscrit en
    Juin 2007
    Messages
    537
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2007
    Messages : 537
    Par défaut Appel Dll C++ et pointeur C#
    Bonjour,

    J'aimerais passer des pointeurs en paramètre à ma dll.

    Voici le code :

    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
     
    [DllImport(@"MaDLL.dll")]
    private static unsafe extern void ProduitScalaire(float* va, float* vb, float* vc);
     
            public static Vector ProduitScalaire_Vector(Vector v1, Vector v2)
            {
                Vector _out = new Vector();
     
                float[] tab_v1 = new float[3];
                tab_v1[0] = (float)v1.x;
                tab_v1[1] = (float)v1.y;
                tab_v1[2] = (float)v1.z;
     
                float[] tab_v2 = new float[3];
                tab_v2[0] = (float)v2.x;
                tab_v2[1] = (float)v2.y;
                tab_v2[2] = (float)v2.z;
     
                float[] tab_v3 = new float[3];
     
                // Ce que je veux :
                // ProduitScalaire(pointeur sur tab_v1, pointeur sur tab_v2, pointeur sur tab_v3)
            }
    Comment puis-je faire ?
    Je galère vraiment sur la gestion des pointeurs en C#

    Merci d'avance.

    PS : La dll est compiler en C++

  2. #2
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Salut,

    La solution devrait être quelque chose du genre :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    [DllImport(@"MaDLL.dll")]
    private static extern void ProduitScalaire(ref float va, ref float vb, ref float vc);

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ProduitScalaire(ref tab_v1, ref tab_v2, ref tab_v3);

    Le principe c'est qu'on a pas besoin du unsafe, un pointeur c'est soit :
    - Passer un tableau, dans ce cas on déclare type[] dans le DllImport
    - Passer l'adresse d'une valeur initialisée coté .Net, dans ce cas c'est le mot "ref"
    - Passer l'adresse d'une zone mémoire destinée à recevoir une valeur initialisée dans le code natif. Dans ce cas c'est sensé être le mot clef "out", mais là il y a des choses a faire avec le garbage pour allouer de la mémoire, la libérer, tout ça tout ça

    EDIT : Regarde aussi tous les attributs qui existent vis à vis du marshalling (marshal.AsXXX par exemple), tu trouveras sans doute de quoi préciser ce que tu cherches à faire pour que le service Interop fasse bien son boulot.

    EDIT 2 : Tout pleins d'exemples ici : http://msdn.microsoft.com/en-us/library/aa446538.aspx
    L'article dit que ç'est pour le Compact Framework, mais c'est valable aussi pour le framework normal.

  3. #3
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour jacky01.

    Si c'est de l 'unsafe" (non securise donc non-verifiable à la compilation) avec des pointeurs cela est possible.Mais avec des tableaux surgit une autre contrainte :
    - leur taille doit etre passee en parametre (tampon à taille fixe)
    - les tailles fixes doivent etre declare avec le mot cle "fixed"....
    - le mot cle "fixed" ne peut figurer que dans un struct unsafe
    - dans un struct unsafe on ne peut declarer que les types suivants:
    Msdn doc:
    Mémoires tampons de taille fixe (Guide de programmation C#)
    En C#, vous pouvez utiliser l'instruction fixed pour créer un tampon avec un tableau de taille fixe dans une structure de données. Cette action est utile lorsque vous utilisez un code existant, comme le code écrit dans d'autres langages, les DLL préexistantes ou les projets COM. Le tableau fixe peut accepter tous les attributs ou modificateurs qui sont prévus pour les membres de structures régulières. La seule restriction est que le type de tableau doit être bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float ou double.
    Moyennant ces precautions voici ton exemple repris avec un struct intermediare et l'appel comme tu le veux:
    code C (pojet win32)
    fichier .cpp:
    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
     
    //fichier .c ou .cpp
    //rajouter un fichier .def (voir  simple.def  ci-apres pour 
    //les symboles exportes(fonctions ou variables visible à l'exterieur de la dll) 
    #include "stdafx.h"
    #include <WINDOWS.H>
     
    	// Il s'agit d'un exemple de fonction exportée.
    		int fn(void)
    		{
    			return 42;
    		}
    	// Il s'agit d'un exemple de fonction exportée.
    		int ProduitScalaire( float*  myVect,int size)
    		{
    			int i = 0;
    			int result=size;
     
    			for (i = 0 ; i <size ; i++)
    			{
    			 *myVect = *myVect * 10.0f;
    			 myVect++;
    			}
     
     
    			return result;
    		}
    fichier .def:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    LIBRARY	"LibMaDLL"
    DESCRIPTION 'Sample C DLL for use with CSharp.NET'
          EXPORTS
            fn
            ProduitScalaire
    partie CSharp:
    un bloc unsafe encadre l'appel & un pointeur float est caste sur le 1er element de l'array
    Ensuite le pointeur est initialise par incement sur les valeurs de l'array...
    & on fait l'appel..
    Au retour on recupere les valeurs du ponteur par incrementation...
    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
     
    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 WinMarshalCopy
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
     
     
            }
            // function exemple renvoyant un int
            [DllImport("LibMaDLL.dll")]
            public static  extern int fn();
     
            private void button1_Click(object sender, EventArgs e)
            {
                // appel à fn
                int n = fn();
     
                this.textBox1.Text = n.ToString() + "\r";
     
                // appel à ProduitScalaire_Vector(V)
                Vector V = new Vector();
                V = ProduitScalaire_Vector(V);
                this.textBox1.Text =this.textBox1.Text+ V.X.ToString() + V.Y.ToString() + V.Z.ToString()+"\r";
     
     
            }
            [DllImport("LibMaDLL.dll")]
            private static unsafe extern int ProduitScalaire(float* va, int size);
     
            public static Vector ProduitScalaire_Vector(Vector v1)
            {
     
                Vector _outVector = new Vector();
     
                unsafe
                {
     
                    myStruct myStruct=new myStruct();
                    myStruct.size = 3;
                    myStruct.tab_v1[0] = (float)v1.X;
                    myStruct.tab_v1[1] = (float)v1.Y;
                    myStruct.tab_v1[2] = (float)v1.Z;
     
                    // declare un ptr float
                    float* tab_v1Ptr = (float*)& myStruct.tab_v1[0];
     
                    // initialisation becessaire du ptr
                    *tab_v1Ptr = (float)myStruct.tab_v1[0];
                    *(tab_v1Ptr + 1) = (float)myStruct.tab_v1[1];
                    *(tab_v1Ptr + 2) = (float)myStruct.tab_v1[2]; ;
                    // Ce que je veux :
                    int result = 0;
                    result = ProduitScalaire(tab_v1Ptr, myStruct.size);
                    MessageBox.Show( result.ToString() ) ;
     
                    _outVector.X = *tab_v1Ptr;
                    _outVector.Y = *(tab_v1Ptr + 1);
                    _outVector.Z = *(tab_v1Ptr + 2); ;
                    return _outVector;
                }
     
            }
     
     
        }
        // le struct necessaire encapsulant l'array tab_v1
        // à taille fixe
        public  unsafe struct myStruct
        {
            public int size;
            public    fixed float tab_v1[3];
     
        }
        // class vector pour "mimic"
        public class Vector 
        {
            public Vector()
            {
                this.X = 100.0;
                this.Y = 150.0;
                this.Z = 250.0;
            }
            public double X { get; set; }
            public double Y { get; set; }
            public double Z { get; set; }
     
     
        }
    }
    En esperant que cela reponde au souci.....

  4. #4
    Membre chevronné Avatar de jacky01
    Profil pro
    Développeur .NET
    Inscrit en
    Juin 2007
    Messages
    537
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2007
    Messages : 537
    Par défaut
    Merci pour vos réponse, je me penche sur ces deux axes.
    Pour ce qui est de la solution de ctxnop, j'ai essayé comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ProduitScalaire(ref tab_v1,ref tab_v2,ref tab_v3);
    avec comme déclaration :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    [DllImport(@"MaDll.dll")]
            private static unsafe extern void ProduitScalaire(ref float* va, ref float* vb, ref float* vc);
    Et j'ai une exception plutôt cocasse et carrément incompréhensible pour moi... J'espère que vous pourrez m'expliquer le hic en "français"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Un appel à la fonction PInvoke 'MaLib!MaLib.Maths.MathsTools::ProduitScalaire' a déséquilibré la pile. Cela peut se produire, car la signature PInvoke managée ne correspond pas à la signature cible non managée. Vérifiez que la convention d'appel et les paramètres de la signature PInvoke correspondent à la signature non managée cible.
    EDIT : J'ai la même exception dans la seconde solution...

  5. #5
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Par défaut
    Bonjour,

    Cette exception est du au fait qu'avec Visual 2010 la convention d'appel par défaut a changé.
    Precise que tu veux utiliser cdecl, ou change la compilation C/C++ pour utiliser std soit sur ta méthode, soit dans les parametre du projet.

    Au passage, pour passer un tableau de float, tu n'a pas besoin de "*", comme le disait ctxnop.
    Personnelement j'utilise juste le marshalling dans ce cas là, en mode UnmanagedType.LPArray en precisant le SubType

  6. #6
    Membre chevronné Avatar de jacky01
    Profil pro
    Développeur .NET
    Inscrit en
    Juin 2007
    Messages
    537
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2007
    Messages : 537
    Par défaut
    Si ça peut vous aider, j'ai essayer avec un opération très basique afin de voir si le problème était lié aux pointeurs ou autre chose et le problème reste le même.

    Je pense que j'ai donc un problème ailleurs qui génère ce "déséquilibre" cité par l'exception.

    Voici le code :

    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int Multiply(int a, int b)
    {
        return a * b;
    }
    .def
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    LIBRARY	"MaDll"
    DESCRIPTION 'Ma Lib'
          EXPORTS
    		Multiply
    C#
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            [DllImport(@"MaDll.dll")]
            private static unsafe extern int Multiply(int a, int b);
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
           int a = 0;
           a = Multiply(2, 3);
    J'y comprend plus rien...

  7. #7
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Nan mais c'est pas tout à fait ça...
    1 - Pas de "unsafe", c'est le service Interop qui se charge du boulot, le unsafe n'est pas réellement utile ici.

    2 - Soit tu met "float*", soit "ref float", mais clairement pas "ref float*". Pour faire les choses bien comme préconisé par Microsoft, c'est "ref float".

    3 - Comme le dit antoine.debyser, la convention d'appel par défaut de Visual C++ 2010 est cdecl au lieu de stdcall. Donc soit tu modifie la fonction C++ pour indiquer "__stdcall" sur ta fonction, soit tu modifie le DllImport pour spécifier que la CallingConvention est Cdecl [DllImport("malib.dll", CallingConvention = CallingConvention.Cdecl)].

    4 - Tu peux donner plus d'information au service Interop pour qu'il sache comment transformer les paramètres en placant des attributs devant eux private static extern void ProduitScalaire([MarshalAs(UnmanagedType.LPArray)] ref float va, ref float vb, ref float vc);. Comme l'a également dit antoine.debyser.

  8. #8
    Membre chevronné Avatar de jacky01
    Profil pro
    Développeur .NET
    Inscrit en
    Juin 2007
    Messages
    537
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2007
    Messages : 537
    Par défaut
    Re,

    Bon j'ai trouvé une solution :

    dans ma dll :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void __stdcall ProduitScalaire(float* va, float* vb, float* vc)
    Ainsi j'ai plus le problème de l'exception et tout fonctionne a merveille.

    Milles merci à vous !!!!!!

  9. #9
    Invité de passage
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 1
    Par défaut besoin d'aide
    j'ai créé un dll en c++ que je veux utiliser en c# 2010 mais quand j’exécute il entre dans ma dll mais il ne trouve pas le point d'entré.
    ma dll
    #include <stdio.h>
    #include <iostream>
    #include <string>
    using namespace std;




    int __stdcall addition(int a,int b)
    {
    return a+b;
    }

    l'utilisation de ma dll en csharp

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;

    namespace TestDllCsharp
    {
    class Program
    {

    [DllImport(@"TestDll.dll", EntryPoint = "addition")]
    public static extern int addition(int a, int b);


    static void Main(string[] args)
    {
    Console.WriteLine(addition(10, 15));
    }
    }
    }


    il me manque koi svp.

  10. #10
    Membre émérite Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Par défaut
    Il te dis qu'il te manque un point d'entrée, donc il te manque probablement un grille-pain...

    A moins que ce ne soit un point d'entrée... ?

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

Discussions similaires

  1. [WinCE5.0] Dll-Appel de fonction avec pointeur
    Par Bart_lx dans le forum Windows
    Réponses: 11
    Dernier message: 11/12/2007, 11h43
  2. [WinService][C#] Comment appeler dll C/C++ ?
    Par avrama dans le forum Windows Forms
    Réponses: 5
    Dernier message: 27/01/2006, 12h05
  3. Appel Dll Ecrite en C++
    Par scelines dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 26/07/2005, 11h58
  4. appel DLL C++ en Delphi (pb avec type)
    Par fkerbourch dans le forum Langage
    Réponses: 7
    Dernier message: 11/07/2005, 17h31
  5. [MFC]ActiveX + appel DLL
    Par Xeron dans le forum MFC
    Réponses: 4
    Dernier message: 22/06/2005, 16h39

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