none
Problème de compatibilité COM lors du passage d'une implémentation C++ à C# RRS feed

  • Discussion générale

  • Bonjour,

    Nous avons actuellement un ancien projet (DLL) implémenté en C++ avec interface COM.

    Nous souhaitons passer en implémentation C#/.NET avec COM Interop, mais nous rencontrons des problèmes de compatibilité avec les logiciels existants ! Le problème concerne les paramètres de type int qui se transforment en long...

    Voici les détails à travers un exemple :

    Implémentation d'une méthode en C++ :

    MyMethod(int i_param1, int* io_param2, int* o_result);

    IDL généré à partir de cette implémentation :

    HRESULT MyMethod(int i_param1, int* io_param2, [out,retval] int* o_result);

    Les clients c++ utilisaient cette méthode de cette manière :

    int param2 = 1;
    int return = MyMethod(0, &param2);

    Voici maintenant l'implémentation faite en C# :

    Int32 MyMethod(Int32 i_param1,ref Int32 io_param2);

    En utilisant Tlbexp, on peut voir la méthode exposée en COM:

    HRESULT MyMethod([in] long i_param1, [in, out] long* io_param2, [out, retval] long* pRetVal);

    Comme vous pouvez le voir, tous les Int32 sont remplacés par des long...

    Avec ce changement, tous les clients C++ ne compilent plus :

    error C2664: 'IMyInterface::MyMethod' : cannot convert parameter 2 from 'int *' to 'long *'

    Ma question est donc la suivante :

    Est-il possible de forcer le type à int dans l'exposition COM ? Ou tous els clients utilisant les "nouvelles" interfaces doivent-ils modifier leur code source pour pouvoir compiler ???

    Merci d'avance pour vos réponses.

    • Type modifié Nico5000 vendredi 16 novembre 2012 08:31
    • Type modifié Aurel Bera vendredi 23 novembre 2012 09:04 New Thread in other forum
    vendredi 16 novembre 2012 08:31

Toutes les réponses

  • Bonjour,

    Avez-vous mis à jour votre tlb généré en .Net dans vos applications C++ ?

     

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    samedi 17 novembre 2012 09:33
  • Bonjour,

    Oui dans l'application C++ j'utilise maintenant le tlb (généré par Tlbexp). En ouvrant le tlb avec Oleview, je vois que les méthodes prennent des long et long* en paramètre lorsque que ce sont des int (ou int32) ou int* dans le code de la Dll C# qui expose en COM...

    Pensez-vous que je doive faire une demande de support technique via mon abonnement MSDN ?

    Merci de votre aide.

    lundi 19 novembre 2012 07:54
  • Bonjour,

    Je ne pense pas que ce soit nécessaire d'ouvrir un ticket d'incident. J'ai aussi le même "problème". Je pense que cela vient du fait que le Int en VB6 était Long. Essayez de faire une compilation x86 des deux cotés.

    Je regarde en même temps comment résoudre le problème.

     

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    lundi 19 novembre 2012 15:29
  • Bonjour,

    J'ai essayé la compilation x86 de la Dll et du programme : pas de changement... J'ai aussi essayé de générer le tlb avec tlbexp avec les options win32 ou win64 : pas de changement non plus...

    lundi 19 novembre 2012 16:17
  • Bonjour,

    Cela donne quoi si on reférence la TLB depuis C# (chez moi je vois bien un int C#) ? Le but est de comprendre si c'est la TLB qui n'est pas générée correctement ou si elle n'est pas vue correctement côté C++.

    Eventuellement que donne un sizeof(int), sizeof(long) côté C++ ? De mémoire, les types de données C++ dépendent de l'archi et/ou du compilateur (c'est aussi VS ?) et les autres possibilités s'amenuisant, je ne vois plus guère qu'un micmac à ce niveau...

    Vérification faite le standard C++ indique qu'un int fait au moins 16 bits et un long au moins 32 bits. Il semblerait donc relativement logique qu'un int C# soit vu comme un long côté C++ (un int pouvant éventuellement ne faire que 16 bits selon l'archi/compilo)...

    Si cela se confirme, voir peut-être un groupe C++ pour voir quelles sont les bonnes pratiques pour bien gérer ces variations.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    jeudi 22 novembre 2012 13:04
    Modérateur
  • Bonjour,

    Côté C# la DLL est utilisée en l'ajoutant en tant que référence sans passer par le .tlb

    Si c'est possible, comment utiliser le tlb dans une application .net ?

    L'application C++ est également compilée avec VS (VS2010 précisément). sizeof(int) et sizeof(long) retournent 4.

    Du côté de la DLL C#, si je déclare un paramètre int ou Int32, cela ne change rien. Le tlb généré et ouvert avec Oleview montre un LONG, identique à ce qui est vu par l'application C++.

    De mémoire,

    - un Int32 est un entier signé sur 32 bits

    - un long est un entier signé sur 32 bits (plateforme 32 bits) ou sur 64 bits (plateforme 64 bits)

    donc en compilant en x86 je m'attend à voir un int dans le tlb, ou au moins à ne pas avoir d'erreur de compilation vu que les int et long sont tous les deux des entiers signés 32 bits...

    jeudi 22 novembre 2012 13:20
  • Bonjour,

    C'est ce que je vous disais dans mon 2ème post ;)

    Les anciennes applications tel que VB6 utilise Long pour du int32 (4 Octets). Il en va de même pour le C++ 32 bits.

    Je pense qu'il est normal que vous ayez un long dans OleView.

     

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond à votre demande !

    jeudi 22 novembre 2012 15:48
  • Mais dans ce cas, comment expliquer :

    - que lorsque la DLL est écrite en C++, elle expose un int à l'application C++ qui voit bien un paramètre 'int' dans l'interface COM

    - que lorsque la DLL est écrite en C#, elle expose un Int32, vu alors comme un LONG pour une application C++ ? (à travers TLB)

    N'y-a-il pas un moyen de préciser en C# que le Int32 en paramètre est bien un int pour l'application C++ ? Lorsque la DLL était écrite en C++ elle exposait bien un paramètre int 32 bits, pas un LONG...

    jeudi 22 novembre 2012 15:59
  • Dans l'onglet "Parcourir" des références il est possible de selectionner un fichier TLB mais finalement je ne vois plus très bien ce que je comptais prouver en faisant cela ;-) on verra juste que l'on voit bien un "int" C# ce qui est tout à fait normal.

    D'après ce que je vois dans OLEVIEW, sur d'autres bibliothèques trouver des int semble bien plus rare que trouver des long.

    J'aurais donc tendance à dire que la norme est :
    - une TLB exposant un entier 32 bits utilise le type long (car cette taille minimale est garantie par le standard C++ ce qui n'est pas le cas du int)
    - d'après une source wikipedia un long est également en 32 bits sous Windows (ce qui n'est pas forcément le cas sous d'autres OS/compilateur encore une fois C++ ne donne que des contraintes minimales).

    Donc je dirais que c'est normal de voir et d'utiliser un long.

    En C++ vous utilisiez un int (qui normalement ne garantie que 16 bits) et vous obteniez tout de même le résultat voulue parce qu'il se trouve que dans cet environment un int va au delà et utilise 32 bits au lieu du minimum de 16 bits garanti par le standard (et il est possible qu'avec des veilles versions de Windows int était bien à l'origine un type 16 bits ?...)

    Après ma connaissance de C++ est académique. Je suggère encore un forum C++ pour vérifier les suppositions ci-dessus (et éventuellement merci de revenir les confirmer ou pas dans cette discussion ci).

    Donc en résumé, je dirais que le type long est bien le type à utiliser pour un entier 32 bits (int fonctionne mais c'est juste parce "par chance" son implémentation sous l'OS/compilateur que vous utilisez convient à cet usage). L'article wikipedia auquel je fais allusion plus haut est http://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    jeudi 22 novembre 2012 17:34
    Modérateur
  • Cf réponse détaillée plus haut.

    Si vous écrivez du code C++ en utilisant int, il est normal que le type soit préservé et que la bibliothèque expose un int. En réalité, si c'est un entier 32 bits je dirais que le type long est à favoriser (et c'est donc ce que fait tlbexp en exposant un entier 32 bits sous forme d'un long plutôt que sous forme d'un int) et donc même dans votre code C++ vous auriez du sans doute utiliser long plutôt que int.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".



    jeudi 22 novembre 2012 17:39
    Modérateur
  • Merci pour vos réponses.

    Par contre tout cela pose le fameux problème de la "compatibilité ascendante des interfaces COM" : d'après ce qu'on m'a toujours dit, une interface COM ne doit jamais être modifiée d'une version à l'autre, on a seulement le droit d'ajouter de nouvelles méthodes aux interfaces, mais on ne doit jamais modifier les méthodes déjà exposées... et c'est justement ce qui se produit avec le TLB généré par Tlbexp à partir de la réimplémentation en C#...

    vendredi 23 novembre 2012 07:55
  • Je pense que le problème est qu'il aurait fallu utiliser long dans le code initial ? J'arrête là, la suite semblant clairement relever de compétences C++ (je garde un oeil sur la suite de la discussion dans le forum C++).

    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    vendredi 23 novembre 2012 09:40
    Modérateur