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 :

Interfaçage avec C++


Sujet :

C#

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut Interfaçage avec C++
    Bonjour,

    j'ai un "petit" souci avec une DLL écrite en C++ non managé et que je voudrais utiliser en C# et forcément ça ne marche pas.
    Sachant que je n'y connais quasiment rien en C++, je ne sais pas trop où aller et quoi modifier...

    Dans le code C++, j'ai 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
     
    typedef int (CALLBACK* DS_SNAP_PROC)(BYTE *pImageBuffer, DS_DATA_TYPE TYPE, LPVOID lpContext);
     
    #ifdef DLL_EXPORT
    	#define DT_API extern "C" __declspec(dllexport) 
    #else
    	#define DT_API extern "C" __declspec(dllimport) 
    #endif
     
    /*==============================================================
    Name:	CameraInit
    Desc:  Initialize video equipment
     
    Param:	uiResolution  Resolution index
            hWndDisplay   Video display control handle
            lpThreadparam Video thread create address
    Return: Call returns a STATUS_OK on success,otherwise returns an error code
    Note:   
      --------------------------------------------------------------*/
    DT_API DS_CAMERA_STATUS _stdcall CameraInit(DS_SNAP_PROC pCallbackFunction, IN DS_RESOLUTION uiResolution, IN HWND hWndDisplay, IN LPVOID lpThreadparam );

    J'ai traduit en C#, en prenant des sources à droite à gauche, ce qui donne ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    [System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.StdCall)]
    unsafe public delegate int DS_SNAP_PROC(byte* pImageBuffer, DS_DATA_TYPE TYPE, System.IntPtr lpContext);
     
    [System.Runtime.InteropServices.DllImportAttribute("DICAMSDK.dll", EntryPoint = "CameraInit")]
    public static extern DS_CAMERA_STATUS CameraInit(DS_SNAP_PROC pCallbackFunction, DS_RESOLUTION uiResolution, System.IntPtr hWndDisplay, System.IntPtr lpThreadparam);
    Et le bout de code utilisant 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
    24
    25
    26
    27
    28
    29
    30
    31
            public static DS_SNAP_PROC MyDelegate;
     
            public static byte[] MyBuffer = new byte[(640*480*3)+512];
            unsafe public static byte* pMyBuffer;
     
            unsafe public static int MyProc(byte* pBuffer, DS_DATA_TYPE pDataType, IntPtr Pointeur)
            {
                Console.WriteLine("Begin delegate");
                int Width = 0, Height = 0;
                DS_DATA_TYPE DataType = pDataType;
                DS_CAMERA_STATUS Statut;
     
                Statut = MonWrapper.CameraGetImageSize(ref Width, ref Height);
                Console.WriteLine("Inside delegate, statut = " + Statut + ", Width : " + Width + ", Heigth : " + Height);
                pMyBuffer = pBuffer;
     
                return 1;
            }
     
            public Mon_Constructeur(IntPtr pHandle1, IntPtr pHandle2)
            {
                unsafe
                {
                    MyDelegate = new DS_SNAP_PROC(MyProc);
                    fixed (byte* pMyBuffer = &MyBuffer[0]) ;
     
                    MonWrapper.CameraInit(MyDelegate, (DS_RESOLUTION)0, pHandle1, pHandle2);
                    Thread.Sleep(250);  // Initial timeout
                    Console.WriteLine("Play : " + MonWrapper.CameraPlay(DS_SNAP_MODE.SNAP_MODE_CONTINUATION));  // Gives STATUS_OK
                }
            }
    Là, soit mon delegate n'est jamais appelé, soit j'ai des "stack overflow" ou "corruption mémoire"
    Je me dis qu'il doit manquer des "Marshal" un peu partout, mais je ne sais pas où ni quoi.
    Là je suis un peu coincé, je pars dans tous les sens sans trop savoir quoi faire


    Pour info, j'ai pris le parti de faire ce wrapper en C# car je n'y connais rien en C++. Mais j'ai le code source complet, sauf qu'il s'agit d'un code écrit à la base en VC++ 6.0 natif et que je n'arrive pas à compiler avec VS2008
    Sinon, j'aurais bien essayé de rendre le code C++ manageable, si possible.

    Que me conseillez-vous ? Dans quelle direction aller de préférence ? (je sens bien le C++ managé, non ?)


    Merci d'avance à toute âme charitable
    ________
    Christophe

  2. #2
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Août 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 24
    Par défaut
    En .NET, tu peux appeler un DLL écrite en code non managé, il te suffit d'écrire une interface avec les bon attributs en C#.
    L'intérêt est que tu n'as pas besoin de toucher au code source de ta DLL, et que l'exécution sera aussi plus rapide...

    Un exemple parmi tant d'autres est l'interfaçage de la bibliothèque GMP écrite en C, qui a été portée en .NET de cette manière. Je te conseille de te procurer et d'étudier les sources sur : http://www.emilstefanov.net/Projects/GnuMpDotNet/

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Merci pour cette réponse, mais justement, c'est ce que je suis en train d'essayer de faire

    J'ai déjà quelques fonctions de cette lib pour lesquelles j'ai écris un wrapper et qui fonctionnent très bien. Mais ce sont des types simples de données, genre Integer ou boolean.
    Là, il s'agit de traduire l'appel dans la lib c++ d'un callback que j'écrirai en C# et qui devra récupérer le contenu pointé par le premier paramètre du delegate

    Suis-je assez clair ou pas ? C'est pas simple à première vue...

  4. #4
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Août 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 24
    Par défaut
    Je vois ton problème oui...
    Et ben... bon courage

    Plus sérieusement, ça serait embêtant d'avoir à traduire tout ça en C#, d'autant plus qu'une bonne partie du code sera unsafe.

    Tu peux peut-être essayer d'écrire juste la fonction en C/C++ qui se chargera du callback et de récupérer les données, et puis C# appellera cette fonction...

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Je me demande en fait si je ne devrais pas "cross-poster" (oui, je sais, c'est mal ) sur le forum C++.

    En effet, j'arrive à créer une class C++ managée qui contient un char* que j'arrive à transformer et à récupérer ensuite en C#

    Donc, je me dis qu'il serait peut-être plus judicieux de (tenter de) rendre la librairie C++ managée. Sauf que je suis loin de m'y connaitre assez en C++ pour le faire

    J'ai tout un tas d'erreur de compilation ou de link que je ne sais pas résoudre.

    Pour info, voici à quoi ça ressemble pour la partie C++ managée :
    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
     
    #include "stdafx.h"
    #include <memory.h>
    #include <malloc.h>
    #include "classe_cpp.h"
     
    namespace classe_cpp 
    {
    	Class1::Class1()   // Constructor. Create and initialize both arrays
    	{
    		Class1::nSize = 640*480*3+512;
    		MyArray = gcnew array <unsigned char> (Class1::nSize+1);
    		for (int i = 0; i < Class1::nSize; ++i)
    		{
    			MyArray[i] = unsigned char(0);
    		}
    		pBuffer = (char*)malloc(Class1::nSize);
    		memset(pBuffer, 0, Class1::nSize);
    	}
     
    	void Class1::fonction1 (int a, unsigned char b) // Simple assignation + fill pBuffer
    	{
    		pin_ptr<unsigned char> p1 = &MyArray[0];
            unsigned char* p2 = p1;
    		for (int j=0; j<Class1::nSize; j+=3)    // Fake image retrieval
    		{
    			*(pBuffer+j) = b;
    			*(pBuffer+j+1) = b;
    			*(pBuffer+j+2) = b;
    		}
    		memcpy(p2,pBuffer,nSize+1);   // copy the internal image buffer to the public image buffer
    	}
     
    	void Class1::CopieBuffer()   // Copy the char *pbuffer to the managed array MyArray
    	{
    		pin_ptr<unsigned char> p1 = &MyArray[0];
            unsigned char* p2 = p1;
    		memcpy(p2,pBuffer,nSize+1);   // copy the internal image buffer to the public image buffer
    	}
    }

    Et comment je récupère le contenu en C# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public partial class Form1 : Form
        {
            static public Class1 TestCLR = new Class1();   // Class1 is the managed C++ class
     
            public Form1()
            {
                InitializeComponent();
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
             byte Toto = (byte)TestCLR.MyArray[i];   // C'est le tableau exposé par la classe C++
            }
    }

    J'en suis là. Je ne sais plus trop de quel côté partir :
    - re-coder la librairie C++ en code managé
    - trouver le moyen de m'en sortir avec un wrapper C#

    Dans les deux cas, ça risque de pas être simple

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Bonjour,

    bon, je commence à comprendre un peu mieux le fonctionnement de la partie C++.
    Voici ce que j'ai "découvert".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    DS_CAMERA_STATUS _stdcall CameraInit(DS_SNAP_PROC pCallbackFunction, IN DS_RESOLUTION uiResolution, IN HWND hWndDisplay, IN LPVOID lpThreadparam );
     
    // Lors de l'initialisation, on a  :
    if (STATUS_OK != CameraInit(SnapThreadCallback, (DS_RESOLUTION)0, GetDlgItem(IDC_VIDEO)->m_hWnd, (void*)this) )
    IDC_VIDEO étant une PictureBox. Le truc, c'est qu'une fonction interne utilise ce handle pour mettre à jour automatiquement la picturebox, sans intervention de l'utilisateur.

    Ma question devient donc : quel est le handle qui correspondrait en C# ?

    J'ai essayé, sans conviction, pictureBox1.Handle, puis Bitmap.GetHBitmap, mais évidemment ça ne donne rien.

    Avez-vous une idée ?


    Merci

  7. #7
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par LiveFromBx Voir le message
    En .NET, tu peux appeler un DLL écrite en code non managé, il te suffit d'écrire une interface avec les bon attributs en C#.
    Pas tout à fait, ou du moins, il y a une (sérieuse) limitation :

    on peut appeler des fonctions exportées depuis une DLL non managée. En revanche, utiliser des classes non managées (hors COM? bien sur)est impossible (à ma connaissance) sans écrire un wrapper C++/CLI.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    A priori, la DLL se contente d'exporter des fonctions. Elle est programmée en VC++ 6.0 MFC.

    J'arrive bien à utiliser d'autres fonctions et je sais que mon wrapper C# fonctionne bien dans ce cas : il y a des fonctions "Set" et des "Get" qui me permettent de vérifier que ce que je récupère est bien ce que j'ai envoyé. Pas de souci de ce côté-là.

    Non, ici, et toujours d'après ce que j'ai compris, je dois envoyer comme paramètre le handle d'une PictureBox, laquelle sera dessinée (mise à jour) dans une fonction de la librairie
    Un code C++ de démo est livré avec la librairie et il ne fait strictement rien sur la PictureBox à part la créer bien sûr. A aucun moment celui-ci ne touche à la PictureBox.

    Maintenant, est-ce qu'il existe quelque chose de comparable en C# ? C'est toute la question
    Je ne sais pas ce qui est fait en interne sur ce handle car la librairie concernée fait elle-même appel à une autre dont je n'ai pas le source et qui prend également ce handle comme paramètre. J'imagine que c'est dans cette dernière que la PictureBox est remplie.

    Est-ce qu'une PictureBox de VC++ 6.0 est compatible avec quelque chose en C# ?


    En tout cas, merci de vous pencher sur mon problème.

  9. #9
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Becafuel Voir le message
    Est-ce qu'une PictureBox de VC++ 6.0 est compatible avec quelque chose en C# ?
    La " PictureBox de VC++ 6.0" ca n'existe pas .
    La PictureBox est un contrôle natif Window (donc présent dans la toolbox des programmes .Net Winform - pour WCF, je ne sais pas/ne pense pas) , qu possède donc une proriété Handle de type IntPtr (signature certaine du coté "natif" de la chose )

    Pourquoi ne l'utilises tu pas ?

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Pourquoi ne l'utilises tu pas ?
    Tu penses bien que c'est une des premières choses que j'ai essayée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public Form1()
    {
      InitializeComponent();
     
      MonHandle = pictureBox1.Handle;
      MyDelegate = new DS_SNAP_PROC(MyProc);
      Console.WriteLine("Init : " + MonWrapper.CameraInit(MyDelegate, 0, MonHandle, this.Handle));
      pictureBox1.Refresh();
    }
    Ma comparaison avec VC6++ était plus orientée sur le traitement interne de la chose. Est-il le même qu'en C# ?

    Comme ce n'est pas le programme qui met à jour l'image, j'ai comme un doute.

  11. #11
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Becafuel Voir le message
    Tu penses bien que c'est une des premières choses que j'ai essayée
    Et qu'est ce qui se passe dans ce cas ?

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Rien

    La PictureBox reste désespérement vide ! J'ai mis un petit bouton pour forcer le Refresh(), histoire de, mais rien à faire.
    Images attachées Images attachées  

  13. #13
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Becafuel Voir le message
    Rien

    La PictureBox reste désespérement vide ! J'ai mis un petit bouton pour forcer le Refresh(), histoire de, mais rien à faire.
    Dans la mesure où on ne sait pas ce qui se passe dans ta DLL en C il est un peu difficile de tirer un diagnostic.

    Tu as essayé de mettre des traces dans la DLL pour voir ce qui merde ? tu es sur qu'elle fait son callback dans le thread d'appel et pas dans un autre ?

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Hélas, je n'ai qu'une version "Release" de la librairie et je ne peux la compiler avec VS2010 (trop d'erreur que je ne sais pas résoudre).

    Qui plus est, la deuxième lib appelée en sous-main, celle qui produit effectivement le remplissage de la PictureBox, ne m'est pas accessible. Je n'ai qu'un .LIB à me mettre sous la dent.

    Le callback, premier paramètre de la fonction CameraInit, n'est pas appelé en temps "normal", en lecture simple de la caméra. Il est par contre appelé dès que je dois faire une opération sur l'image, genre sauvegarde. Mon delegate est bien appelé et je récupère a-priori les bons éléments.
    Ce n'est de toute façon pas ma priorité, qui se trouve d'avoir l'image à l'écran.

    Au fait, j'ai mis le champs "Modifiers" à "public" dans la PictureBox, ça ne peut pas nuire, il me semble ?

    Tiens, en écrivant ça, je me demande si le fait que la PictureBox ne soit pas static peut avoir une influence ?
    Ne ferais-je pas mieux de déclarer une picturebox moi-même et utiliser celle de la fiche comme "copie", finalement ? Je vais essayer ça...

  15. #15
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Becafuel Voir le message
    Hélas, je n'ai qu'une version "Release" de la librairie et je ne peux la compiler avec VS2010 (trop d'erreur que je ne sais pas résoudre).

    Qui plus est, la deuxième lib appelée en sous-main, celle qui produit effectivement le remplissage de la PictureBox, ne m'est pas accessible. Je n'ai qu'un .LIB à me mettre sous la dent.
    Donc, là, ça revient à chercher dans le noir. C'est limite impossible.


    Au fait, j'ai mis le champs "Modifiers" à "public" dans la PictureBox, ça ne peut pas nuire, il me semble ?
    Certes, mais cela n'a certainement aucun interêt.

    Tiens, en écrivant ça, je me demande si le fait que la PictureBox ne soit pas static peut avoir une influence ?
    Ne ferais-je pas mieux de déclarer une picturebox moi-même et utiliser celle de la fiche comme "copie", finalement ? Je vais essayer ça...
    La encore, je ne suis pas sur du tout de l'interêt de la chose, mais bon ...

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 25
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Donc, là, ça revient à chercher dans le noir. C'est limite impossible.
    J'ai joint les personnes qui m'ont fourni tout ça pour qu'il me fournissent également les sources qui me manquent. On sait jamais...


    Citation Envoyé par Bluedeep Voir le message
    Certes, mais cela n'a certainement aucun interêt.
    Certainement. C'est d'ailleurs le cas.


    Citation Envoyé par Bluedeep Voir le message
    La encore, je ne suis pas sur du tout de l'interêt de la chose, mais bon ...
    Pareil que ci-dessus Mais parfois, ce sont les choses les plus évidentes qui ne se voient pas, donc bon...


    Dans tous les cas, je te remercie pour le temps que tu as passé à essayer de m'aider, même si le succès n'est pas au rendez-vous

    Si j'arrive à mes fins, je reviendrai ici avec la solution.

Discussions similaires

  1. Interfaçage avec explorateur Windows
    Par marcouille49 dans le forum SharePoint
    Réponses: 4
    Dernier message: 24/09/2008, 16h38
  2. Réponses: 6
    Dernier message: 04/01/2008, 11h47
  3. Interfaçage avec SAP
    Par cbleas dans le forum MS SQL Server
    Réponses: 10
    Dernier message: 01/12/2007, 10h00
  4. interfaçage avec terminal portable
    Par azg33 dans le forum 4D
    Réponses: 0
    Dernier message: 29/11/2007, 09h40
  5. Interfaçage avec les API de cdrtools
    Par jeanbi dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 17/07/2004, 16h35

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