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 :

créer une fonction de callback entre DLL C++/cli et C#


Sujet :

C#

  1. #1
    LEK
    LEK est déconnecté
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    715
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 715
    Par défaut créer une fonction de callback entre DLL C++/cli et C#
    Bonjour à vous,
    je bloque actuellement sur le problème suivant : je dispose d'une dll écrite en c++ CLI qui référence une DLL écrite en c#. La première appelle des méthodes statiques de la seconde pour exécuter certaine tâches. jusque là tout fonctionne correctement, mais j'ai besoin maintenant que la dll c# puisse disposer elle même rappeler une méthode de ma library C++/CLI (une sorte de callback). Pour rappelle le shéma est le suivant :
    DLL C++/CLI ===connait/référence==> DLL C#
    mais l'iunverse n'est pas vrai et je désire que la DLL C# puisse disposer d'une sorte de pointeur de fonction et/ou délégué pointant sur une méthode statique de ma library C++/CLI....
    Cela fait quelque jour que j'essaye sans succès d'arriver à mes fins
    Est-ce que quelqu'un pourrait m'aider ou me guider vers un tuto/exemple.
    En vous remerciant par avance,
    Et Bonne année à tous

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    utilise un delegate

  3. #3
    LEK
    LEK est déconnecté
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    715
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 715
    Par défaut
    Bonsoir,
    merci pour ta réponse : j'ai essayé effectivement de voir du côté des delegate mais tous les exemples que je trouves portes sur des délégués utilisés par une seule classe ou en tout cas dans le même assembly.
    De plus ma DLL c# ne possède aucune référence à la dll c++/cli : elle ne sait pas qui la consomme : si un delegate est approprié dans ce cas, je ne vois pas comment faire ? Si tu as une piste je suis preneur ;-)
    Merci encore,
    Lek.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Ben ça dépend de quels paramètres la fonction C++ appelée a besoin... Si le type de ces paramètres est défini dans la DLL C++, c'est gênant, mais sinon la DLL C# n'a pas besoin de référencer la DLL C++.

    Regarde par exemple les évènements en Windows Forms : un bouton est capable d'appeler une méthode définie dans ton code, et pourtant Windows Forms ne référence évidemment pas ton programme... Les évènement sont un cas particulier d'utilisation des delegate.

    En gros, il faut que tu définisses dans la DLL C# un delegate public dont la signature correspond à celle de la fonction C++, et que la DLL C++ indique à la DLL C# la fonction de callback à utiliser, via ce delegate.

    Un exemple pour clarifier :

    Code C# : 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
    // déclaration du delegate
    public delegate void TotoCallback(string arg);
    ...
    public class UneClasseCSharp
    {
    ...
     
    // Callback (qui doit être assigné par la DLL "consommatrice")
    public TotoCallback Callback;
     
    ...
     
    // Appel du callback
    if (Callback != null)
        Callback("blabla");
     
    ...
     
    }

    Code C++ : 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
     
     
    ref class UneClassCpp
    {
     
    // fonction C++/CLI qui doit être appelée par C#
    void Toto(String^ arg)
    {
        ...
    }
     
    ...
     
    // Affectation de la fonction au callback
    UneClasseCSharp^ x = gcnew UneClasseCSharp();
    x->Callback = gcnew TotoCallback( this, &UneClassCpp::Toto);
     
    ...
     
    }

    (Y a pt-être qq erreurs dans le code C++, j'ai plus trop l'habitude de C++/CLI...)

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    La réponse de tomlev est parfaitement bonne.

    Je me permets seulement d'ajouter :

    Citation Envoyé par tomlev Voir le message
    Si le type de ces paramètres est défini dans la DLL C++, c'est gênant, mais sinon la DLL C# n'a pas besoin de référencer la DLL C++.
    ... c'est à peine génant en fait, car la solution naturelle est connue : il suffit de déporter les termes-types "fournisseurs" de ladite signature du delegate (dans le cas typique : juste le delegate lui même, et seulement les quelques types qui lui sont spécifiques, avec le type ou namespace englobant) dans un 3eme assembly qu'on pourrait qualifier "d'assembly de contrat", et qui sera donc simplement référencé par votre "assembly C++/CLI" ainsi que par votre autre "assembly C#".

    Pour ce 3eme assembly, si le besoin de l'existence de celui ci se fait sentir, vous choisirez probablement votre langage préféré, C++/CLI plutôt que C#, apparemment, l'intellisense pour la syntaxe C# fera le reste pour vous (merci .NET / l'EDI, etc ).

    Bonne année 2009.

    'HTH

  6. #6
    LEK
    LEK est déconnecté
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    715
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 715
    Par défaut
    Merci à vous deux!
    Cela fonctionne effectivement comme prévu et je pense que je vais replancher sur les délégués pour mieux appréhender le fonctionnement!
    J'ai juste du effectuer une petite modification dans le code C++ : la méthode callback (UneClassCpp::Toto) à rappeler a du être définie comme méthode statique de la classe et l'affectation de la fonction au callback a due être fait ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    x->Callback = gcnew TotoCallback(  &UneClassCpp::Toto);
    mais à part ces petits ajustement cela fonctionne du tonnerre ;-)
    Merci encore à vous,
    Bonne et heureuse année!

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    pense au bouton si c'est OK...

  8. #8
    LEK
    LEK est déconnecté
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    715
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 715
    Par défaut
    Bonjour,
    je rouvre le sujet car je me rend compte désormais que la solution proposée ne répond pas totalement à mon besoin : comme je l'ai précisé, j'ai été obligé pour la création du delegate en c++/cli de fournir l'adresse d'une méthode statique et c'est cela qui est en fait la cause de mon problème : j'aurais en fait souhaité pouvoir dans cette fonction accéder à ds données d'instance et donc faire référence non pas à une méthode statique mais bien à une fonction membre de ma classe c++/cli...
    Pour essayez de parer à celà je me suis dis qu'une solution serait peut être d'utiliser le code actuel et de passer une référence à mon instance de classe au travers du délégie de manière à pouvoir accéder à mes données d'instance dans la méthode statiqu appelée... Un peu à la manièrere dont les API windows contiennent en paramètre un handle...
    J'ai donc modifié la signature du delegate en c# ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public delegate void TotoCallback(IntPtr ptrCppClass, string arg);
    Et j'ai ajouté à ma classe 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
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // déclaration du delegate
    public delegate void TotoCallback(IntPtr ptrCppClass, string arg);
    ...
    public class UneClasseCSharp
    {
       private IntPtr m_ptrCppClass;
       public void setCallBackInstance(IntPtr ptrCppClass){
         m_ptrCppClass = ptrCppClass;
      }
     
    ...
     
    // Callback (qui doit être assigné par la DLL "consommatrice")
    public TotoCallback Callback;
     
    ...
     
    // Appel du callback
    if (Callback != null)
        Callback(m_ptrCppClass, "blabla");
     
    ...
     
    }

    et au niveau du code 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
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    ref class UneClassCpp
    {
     
    // fonction C++/CLI qui doit être appelée par C#
    static void Toto(IntPtr  pCpp, String^ arg)
    {
      //Erreur ici : conversion Inptr vers UneClassCpp impossible
      ((UneClassCpp*)pCpp)->faireQQChose(); 
       ...
     
    }
     
    ...
     
    // Affectation de la fonction au callback
    UneClasseCSharp^ x = gcnew UneClasseCSharp();
    //fournit une référence à l'instance c++ en cours
    x->setCallBackInstance((IntPtr )this);
    x->Callback = gcnew TotoCallback(  &UneClassCpp::Toto);
    ...
     
    }
    Mais comme je l'ai précisé dans le code de la fonction C+++, j'ai une erreur lorsque j'essaie de caster le pointeur vers une pointeur de ma classe CPP... A vrai dire, je ne sais pas si c'est ainsi qu'il faut s'y prendre...
    J'essaye de trouver des exemples similaires mais je n'en trouve pas... J'ai bien trouvé un exemple de code sur le site de microsoft qui pourrait s'apparenter à mon problème mais je n'arrive pas à l'exploiter dans mon cas : http://msdn.microsoft.com/fr-fr/library/367eeye0.aspx
    Est ce que je dont j'ai besoin est réalisable ? Si oui, auriez-vous une idée sur la marche à suivre ?


    Cordialement,
    Lek.

  9. #9
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    Ma foi, je verrais plutôt (aux identificateurs près.. pardon pour l'infidélité) :

    (C#)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public delegate void CppClassCallback(string arg);
     
    public class CSharpClass
    {
        // Fields
        public CppClassCallback CallBack;
    }
    et

    (C++)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public __gc class CppClass
    {
        // Methods
        public: void __gc* cppHandler(String __gc* arg)
        {
        }
    };
    Enfin, plus loin :

    (C++)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public: void __gc* CppEventSinkConfig()
        {
            CSharpClass __gc* csharpObject = //...
            CppClass __gc* cppObject = //...
            csharpObject->CallBack = new CppClassCallback __gc*(cppObject.cppHandler);
        }
    Où cppObject peut aussi être, en fonction de votre contexte syntaxique, l'instance C++ courante (this).

    'HTH

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Oula, lysiandad, ça doit faire un moment que t'as pas fait du C++/CLI
    Depuis la version 2005 tous les opérateurs commencant par __ ont été remplacés :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public ref class CppClass
    {
        // Methods
        public: void cppHandler(String^ arg)
        {
        }
    };
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public: void CppEventSinkConfig()
        {
            CSharpClass^ csharpObject = //...
            CppClass^ cppObject = //...
            csharpObject->CallBack = gcnew CppClassCallback (cppObject->cppHandler);
        }

    Sinon, j'ai regardé des exemples dans la doc MSDN, et apparemment la bonne syntaxe si Toto est non-statique est :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    x->Callback = gcnew TotoCallback(  this, &UneClassCpp::Toto);
    (cf l'exemple en C++ pour l'évènement Application.ApplicationExit)

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Oula, lysiandad, ça doit faire un moment que t'as pas fait du C++/CLI
    Depuis la version 2005 tous les opérateurs commencant par __ ont été remplacés :[...]
    Tout à fait, je m'en cache pas... ... donc, la version 2005 a mis a la diète le MC++ en enlevant "tout le sucre syntaxique" __gc and co...

    Bah, moi, j'adore le sucre.. je brule les calories a vitesse grand V, de toute façon

    Pour le reste de la réponse de tomlev, je suppose que c'est ça, oui... on le saura bientôt, quand notre ami l'aura mis en oeuvre dans son contexte avec le petit tag "résolu" souriant qui va bien, j'espère.

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par lysiandad Voir le message
    donc, la version 2005 a mis a la diète le MC++ en enlevant "tout le sucre syntaxique" __gc and co...
    Tiens c'est marrant, pour moi tous ces __gc* etc c'est justement le contraire du sucre syntaxique
    Je trouve la nouvelle syntaxe beaucoup plus agréable

    Mais bon, d'un autre côté je ne code quasiment jamais en C++, donc je m'en fous...

  13. #13
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Tiens c'est marrant, pour moi tous ces __gc* etc c'est justement le contraire du sucre syntaxique
    Hmm.. je ne pense pas. "L'ancien" et "le nouveau" MC++ ont chacun "un sucre syntaxique" propre, qui leur offre la possibilité de mettre en oeuvre les spécificités .NET largement sémantiques (présence du GC, etc) au langage C++ ANSI/ISO qui a servit de "matrice" (quoique "matrice" est largement un abus de langage, français, car le MC++ n'a plus grand chose a voir avec le C++ ANSI/ISO, si on y regarde de près..)

    En fait, pour tout dire, sur ces deux sucres syntaxiques MC++ pre-2005 et post-2005, c'est une reflexion que je me suis faite il y a quelque temps quand j'ai decouvert le nouveau, post-2005, "allégé", que je n'ai pas etudié plus loin, comme tout le monde l'a vu.

    Ma théorie (et ce n'est que spéculation de ma part), c'est que les gars chez MS qui etaient en charge du compilo MC++ ont dans un premier temps (pre-2005) eu pour priorité de ré écrire surtout la partie "backend" du compilateur VC++ (natif), en essayant de toucher au minimum le front end (la partie analyse syntaxique). D'où tous ces "__gc..." et autres "newgc", "__gc* ...", etc, qui ont une "forte odeur" de modificateurs ajoutés au langage C++ (comme __stdcall, en son temps, etc) de manière ad hoc, sans remise en cause profonde des regles de production de la grammaire EBNF du C++ natif...

    Puis, avec la version post-2005, le sucre allégé, on sent qu'ils ont voulu faire un effort, oui, de simplification/de confort d'utilisation (et, amha, peut être aussi de coherence "inspirée" du cousin C#) avec ce "^" et autres...

    .. et là, je suspecte qu'ils ont fini par devoir reprendre de manière plus profonde la partie syntaxe proprement dite, une fois que la production de MSIL etait acquise depuis "assez longtemps".

    Mais, bon, encore une fois : que speculations de ma part sur le pourquoi la syntaxe post-2005 pour MC++ n'etait pas arrivée dès le début.

    Citation Envoyé par tomlev Voir le message
    Je trouve la nouvelle syntaxe beaucoup plus agréable
    Donc, oui : je suis d'accord (d'autant que j'ai essayé de me l'expliquer à moi même ; cf remarque ci dessus).

    Citation Envoyé par tomlev Voir le message
    Mais bon, d'un autre côté je ne code quasiment jamais en C++, donc je m'en fous...
    Et là, on est alors (au moins...) deux, en fait.

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Par définition, le "sucre syntaxique", c'est quelque chose qui rend le langage plus facile et à écrire, mais ne modifie pas ses fonctionnalités. Donc on ne peut pas utiliser ce terme pour les mots-clés de MC++. CQFD
    http://en.wikipedia.org/wiki/Syntactic_sugar
    http://fr.wikipedia.org/wiki/Sucre_syntaxique

    Mais bon, on est un peu hors sujet là

  15. #15
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Par définition, le "sucre syntaxique", c'est quelque chose qui rend le langage plus facile et à écrire, mais ne modifie pas ses fonctionnalités. Donc on ne peut pas utiliser ce terme pour les mots-clés de MC++. CQFD
    Hehe.. oui, bien vu dès le départ, j'ai donc bien fait un joli abus de langage en parlant de "sucre syntaxique" pour "__gc" (MC++ pre 2005) et autres "ref" (MC++ post 2005)

    "My bad."

    Mais c'était à défaut d'avoir un meilleur terme pour traiter de ces bestioles ajoutées au C++, en deux temps, par MS, pour en faire ce fameux MC++... on pourrait peut etre alors utiliser "sel syntaxique" ? mais...

    Citation Envoyé par tomlev Voir le message
    Mais bon, on est un peu hors sujet là
    ... car oui : ça devient carrément hors sujet, là.

  16. #16
    Membre expérimenté
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Par défaut
    Citation Envoyé par lysiandad Voir le message
    on pourrait peut etre alors utiliser "sel syntaxique" ?
    "Damn." ..et c'est même pas sûr qu'on puisse :

    http://www.tout-savoir.net/definitio...sel_syntaxique

    Je viens de découvrir.

    Oh bon.. bref.

  17. #17
    LEK
    LEK est déconnecté
    Membre éclairé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    715
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 715
    Par défaut
    Salut les gars,
    désolé de m'immiscer dans votre débat. C'était juste pour dire que j'avais réussis à m'en tirer avec ma première idée : effectivement il était normalement possible de faire créer un délégué pointant sur une fonction membre et la syntaxe que vous m'avez donné était la bonne mais je n'ai pas pu l'appliquer dans mon cas : en fait le code c++ était un mix de managé et de non managé...
    Pour m'en sortir j'ai du transmettre à la dll c# une référence à mon instance c++ : lors du rappel du délégué c++ (méthode statique) j'ai renvoyer en paramètre le pointeur vers mon instance que j'ai recasté... Bon je sais pas si c'est clair pour tout le monde, mais en tous cas sa fonctionne et je vous remercie encore de votre aide et de votre patience. Je me tiens à la disposition de celui qui aurais le même type de probleme que moi et voudrais jeter un oeil à mon code ;-)
    Bonne soirée et encore merci,
    Lek.

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

Discussions similaires

  1. Comment créer une fonction d'archivage des entrées
    Par vietzims dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 27/05/2008, 23h15
  2. Créer une Fonction recherche sur Access
    Par remwideco dans le forum Access
    Réponses: 4
    Dernier message: 30/01/2006, 10h36
  3. créer une fonction avec parametre optionnel
    Par maximenet dans le forum Langage
    Réponses: 2
    Dernier message: 29/01/2006, 20h51
  4. Réponses: 6
    Dernier message: 10/08/2005, 11h36
  5. Créer une fonction mathématique pendant l'exécution
    Par zeprogrameur dans le forum Langage
    Réponses: 5
    Dernier message: 09/07/2004, 11h36

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