Question

Cette question est liée à la " comment rendre cohérente Fichiers binaires DLL sur différentes versions de VS? "

  • Nous avons des applications et des DLL créées avec VC6 et une nouvelle application construite avec VC9. L'application VC9 doit utiliser DLL compilées avec VC6, la plupart des qui sont écrits en C et un en C ++.
  • La bibliothèque C ++ pose problème en raison de Nommez les problèmes de décoration / brassage.
  • Tout compiler avec VC9 est actuellement pas une option car il semblent être des effets secondaires. Résoudre ces problèmes serait assez long consommer.
  • Je peux modifier la bibliothèque C ++, mais elle doit être compilée avec VC6.
  • La bibliothèque C ++ est essentiellement un wrapper OO pour une autre bibliothèque C. L'application VC9 utilise des fonctions statiques ainsi que des fonctions non statiques.

Bien que les fonctions statiques puissent être gérées avec quelque chose comme

// Header file
class DLL_API Foo
{
    int init();
}

extern "C"
{
    int DLL_API Foo_init();
}

// Implementation file
int Foo_init()
{
    return Foo::init();
}

ce n'est pas si facile avec les méthodes non statiques.

Si j'ai bien compris, Chris Becke's Est-ce que je suis juste là?

La seule solution serait-elle d'écrire une interface DLL de style C à l'aide de gestionnaires pour les objets ou manque-t-il quelque chose? Dans ce cas, j'imagine que j'aurais probablement moins d'efforts à utiliser directement la bibliothèque C enveloppée.

Était-ce utile?

La solution

Les noms des membres d'interface ne seront pas décorés. Ce sont simplement des décalages dans une table virtuelle. Vous pouvez définir une interface (à l'aide d'une structure C, plutôt que d'une "interface") dans un fichier d'en-tête, ainsi:

struct IFoo {
    int Init() = 0;
};

Ensuite, vous pouvez exporter une fonction à partir de la DLL, sans modification:

class CFoo : public IFoo { /* ... */ };
extern "C" IFoo * __stdcall GetFoo() { return new CFoo(); }

Cela fonctionnera correctement, à condition que vous utilisiez un compilateur générant des vtables compatibles. Microsoft C ++ a généré le même format vtable depuis (au moins, je pense) MSVC6.1 pour DOS, où vtable est une simple liste de pointeurs sur des fonctions (avec thunking dans le cas de plusieurs héritages). GNU C ++ (si je me souviens bien) génère des tables vtables avec des pointeurs de fonction et des décalages relatifs. Celles-ci ne sont pas compatibles entre elles.

Autres conseils

Le problème le plus important à prendre en compte lors de l'utilisation d'une DLL compilée avec un compilateur C ++ différent de l'EXE appelant est l'allocation de mémoire et la durée de vie d'un objet.

Je suppose que vous pouvez contourner le nom mangling (et la convention d'appel), ce qui n'est pas difficile si vous utilisez un compilateur compatible, (je pense que VC6 est largement compatible avec VS2008), ou si vous utilisez extern "C".

Vous rencontrez des problèmes lorsque vous allouez quelque chose à l'aide de nouveau (ou malloc ) à partir de la DLL, puis que vous le renvoyez à l'appelant. Le delete de l'appelant (ou le free ) tentera de libérer l'objet d'un tas différent. Cela ira terriblement mal.

Vous pouvez effectuer une opération IFoo :: Release de style COM ou une opération MyDllFree () . Dans la mesure où ils rappellent dans la DLL, ils utiliseront la bonne implémentation de delete (ou free () ), afin de supprimer le bon objet.

Vous pouvez également vous assurer d'utiliser LocalAlloc (par exemple), de sorte que le fichier EXE et la DLL utilisent le même segment de mémoire.

Eh bien, je pense que la suggestion de Chris Becke c'est très bien. Je n'utiliserais pas la la première solution de Roger , qui utilise une interface nom et, comme il le mentionne, peut rencontrer des problèmes de traitement incompatible par le compilateur de classes abstraites et de méthodes virtuelles. Roger souligne l’attrayant cas compatible avec COM dans sa suite .

  1. Le point douloureux: vous devez apprendre à faire des requêtes d'interface COM et à gérer correctement IUnknown, en utilisant au moins IUnknown: AddRef et IUnknown: Release. Si les implémentations d'interfaces peuvent prendre en charge plusieurs interfaces ou si les méthodes peuvent également renvoyer des interfaces, vous devrez peut-être aussi vous familiariser avec IUnknown: QueryInterface.

  2. Voici l'idée clé. Tous les programmes qui utilisent l'implémentation de l'interface (mais ne l'implémentent pas) utilisent un #include " *. H " commun fichier qui définit l'interface en tant que struct (C) ou classe C / C ++ (VC ++) ou struct (non VC ++ mais C ++). Le fichier * .h s’adapte automatiquement de manière appropriée selon que vous compilez un programme en langage C ou un programme en langage C ++. Vous n'avez pas besoin de connaître cette partie simplement pour utiliser le fichier * .h. Le fichier * .h définit la structure ou le type de l’interface, par exemple, IFoo, avec ses fonctions de membre virtuel (et seulement ses fonctions, sans visibilité directe des données membres dans cette approche).

  3. Le fichier d'en-tête est construit pour respecter le standard binaire COM d'une manière qui fonctionne pour C et qui fonctionne pour C ++, quel que soit le compilateur C ++ utilisé. (Le folk JNI de Java a découvert celui-ci.) Cela signifie qu'il fonctionne entre des modules compilés séparément de n'importe quelle origine tant qu'une structure constituée entièrement de pointeurs d'entrée de fonction (une vtable) est mappée de la même manière par tous. (ils doivent donc être tous x86 32 bits ou x64, par exemple).

  4. Dans la DLL qui implémente l'interface COM via une classe d'encapsulage, vous avez uniquement besoin d'un point d'entrée d'usine. Quelque chose comme un

    extern " C " HRESULT MkIFooImplementation (void ** ppv);

qui retourne un HRESULT (vous devrez également en savoir plus sur ceux-là) et retournera également un * pv à l'emplacement que vous indiquez pour recevoir le pointeur d'interface IFoo. (J'écrase et vous aurez besoin de plus de détails minutieux ici. Ne faites pas confiance à ma syntaxe.) Le stéréotype de la fonction que vous utilisez pour cela est également déclaré dans le fichier * .h.

  1. Le fait est que l'entrée d'usine, qui est toujours un extern non décoré "C" effectue toute la création de classe wrapper nécessaire, puis fournit un pointeur d'interface Ifoo à l'emplacement que vous spécifiez. Cela signifie que toute la gestion de la mémoire pour la création de la classe et toute la gestion de la mémoire pour sa finalisation, etc., auront lieu dans la DLL où vous créez le wrapper. C’est le seul endroit où vous devez traiter ces détails.

  2. Lorsque vous obtenez un résultat OK de la fonction de fabrique, un pointeur d'interface vous a été attribué et il vous a déjà été réservé (une opération implicite IFoo: Addref a déjà été effectuée pour le compte du pointeur d'interface ont été livrés).

  3. Lorsque vous avez terminé avec l'interface, vous la libérez avec un appel sur la méthode IFoo: Release de l'interface. C’est la dernière implémentation de la version (au cas où vous auriez créé davantage de copies AddRef) qui détruira la classe et sa prise en charge de l’interface dans la DLL d’usine. C’est ce qui vous permet de vous fier correctement à une allocation d’arrêt dynamique cohérente et à une libération derrière l’interf

Vous devez également prendre en compte d'autres éléments, tels que les temps d'exécution utilisés par les différentes bibliothèques. Si aucun objet n'est partagé, c'est bien, mais cela semble assez improbable à première vue.
Les suggestions de Chris Becker sont plutôt précises: l'utilisation d'une interface COM actuelle peut vous aider à obtenir la compatibilité binaire dont vous avez besoin. Votre kilométrage peut varier:)

pas amusant, mec. vous allez avoir beaucoup de frustration, vous devriez probablement donner ceci:

  

La seule solution serait-elle d'écrire un   Interface DLL de style C utilisant des gestionnaires   aux objets ou suis-je manquant   quelque chose? Dans ce cas, je suppose, je   aurait probablement moins d'effort avec   directement à l'aide de la bibliothèque C enveloppée.

un regard vraiment étroit. bonne chance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top