80 votes

Utiliser une classe définie dans une DLL C++ dans le code C#

J'ai une DLL qui a été écrite en C++, j'ai besoin d'utiliser cette DLL dans mon code C#. Après avoir cherché, j'ai trouvé que l'utilisation de P/Invoke me donnerait accès à la fonction dont j'ai besoin, mais ces fonctions sont définies dans une classe et utilisent des variables membres privées non statiques. J'ai donc besoin de pouvoir créer une instance de cette classe pour utiliser correctement les fonctions. Comment puis-je accéder à cette classe pour pouvoir créer une instance? Je n'ai pas pu trouver de moyen de le faire.

Je suppose que je devrais noter que la DLL en C++ n'est pas mon code.

106voto

JaredPar Points 333733

Il n'y a pas de moyen d'utiliser directement une classe C++ dans le code C#. Vous pouvez utiliser PInvoke de manière indirecte pour accéder à votre type.

Le schéma de base est que pour chaque fonction membre de la classe Foo, créez une fonction non membre associée qui appelle la fonction membre.

class Foo {
public:
  int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }

Maintenant, il s'agit d'utiliser PInvoke pour ces méthodes dans votre code C#

[DllImport("Foo.dll")]
public static extern IntPtr Foo_Create();

[DllImport("Foo.dll")]
public static extern int Foo_Bar(IntPtr value);

[DllImport("Foo.dll")]
public static extern void Foo_Delete(IntPtr value);

L'inconvénient est que vous aurez un IntPtr maladroit à passer autour, mais il est assez simple de créer une classe wrapper en C# autour de ce pointeur pour créer un modèle plus utilisable.

Même si vous ne possédez pas ce code, vous pouvez créer une autre DLL qui enveloppe la DLL originale et fournit une petite couche PInvoke.

2 votes

Le libellé "Il n'y a aucun moyen d'utiliser directement une classe C++ dans du code C#" n'est pas correct. Une fonction statique C++ fonctionne de la même manière qu'une fonction de style C et les fonctions d'instance peuvent être déclarées comme convention d'appel ThisCall en ajoutant ThisObject pointant vers l'instance elle-même en tant que premier argument. Pour plus de détails, vous voudrez peut-être lire mes Blogs. Vous voudrez peut-être également essayer notre outil. (Je suis l'auteur)

3 votes

Bien que la réponse soit bonne à l'époque, il est peut-être préférable d'utiliser c++/CLI afin d'éviter la création manuelle de fonctions proxy - quelque chose qui pourrait devenir assez fastidieux plutôt rapidement

2 votes

Les fonctions de proxy C++ doivent-elles être entourées de extern "C" { .... } ou est-il acceptable de le faire uniquement en C++ ?

5voto

Dmitry Khalatov Points 2172

Voici un exemple de comment appeler une méthode de classe C++ depuis VB - pour C#, vous n'avez qu'à réécrire le programme d'exemple dans l'étape 4.

4voto

Joris Timmermans Points 8075

La façon dont j'ai fait cela est en créant une fine enveloppe Managed C++ autour de ma DLL C++ non gérée. Le wrapper géré contient des classes "proxy" qui enveloppent le code non géré en exposant l'interface nécessaire par l'application .NET. Cela implique un peu de travail supplémentaire mais permet un fonctionnement assez fluide dans des environnements normaux. Les choses se compliquent avec les dépendances dans certaines circonstances (comme ASP.NET) mais vous ne devriez probablement pas rencontrer ce problème.

3voto

Brian Points 2013

Vous devrez peut-être écrire une DLL intermédiaire (en C++, peut-être) qui gère cela pour vous et expose l'interface dont vous avez besoin. Votre DLL serait chargée de charger la DLL tierce, de créer une instance de cet objet C++ et d'exposer ses fonctions membres selon les besoins via l'API que vous concevez. Ensuite, vous utiliseriez P/Invoke pour accéder à votre API et manipuler proprement l'objet.

Remarque : Pour l'API de votre DLL, essayez de limiter les types de données aux types primitifs (long, int, char*, etc.) pour éviter les problèmes de limite de module.

2voto

badbadboy Points 1754

Je suis d'accord avec JaredPar. Créer des instances de classes non gérées dans du code géré ne devrait pas être possible.

Autre chose - si vous pouviez recompiler le DLL en C++ géré ou en faire un composant COM, ce serait beaucoup plus facile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X