Comment appeler C ++ / CLI depuis C #?

J’ai une classe implémentée en C ++ qui est responsable du calcul arithmétique du programme et d’une interface utilisant WPF. Je traite l’entrée avec C # mais comment puis-je utiliser ma classe C ++?

J’ai vu des commentaires sur la création d’une classe d’encapsuleur C ++ gérée pour interagir avec elle, mais je ne sais pas par où commencer. Je ne sais pas non plus comment je pourrais le comstackr avec tous les autres codes. Je ne trouve pas vraiment de tutoriel à ce sujet, et les choses que Google montre sur le C ++ géré ne semblent pas vraiment utiles.

Quelque chose là-bas pour m’aider? Cela ne me semble pas déraisonnable.

EDIT Essayé la solution m3rLinEz mais cela me donne une exception BadImageFormatException, je pense que c’est parce que la DLL n’est pas générée. J’ai tout fait comme dit, ne sais pas ce qui s’est passé. Des idées?

Avez-vous jeté un oeil à C ++ / CLI?

Permettez-moi de donner un exemple très court. Voici le fichier source d’un projet Visual C ++ -> CLR -> Class Library. Il récupère essentiellement le nom d’utilisateur Windows et le renvoie.

S’il vous plaît noter que, pour obtenir cela compilé, vous devez aller dans les parameters du projet et marquer “Dépendances supplémentaires” comme “Hériter de parent” parce que nous utilisons ces libs Windows (kernel32.lib, user32.lib, ..)

// CSCPP.h #pragma once #include "windows.h" using namespace System; namespace CSCPP { public ref class Class1 { // TODO: Add your methods for this class here. public: Ssortingng^ GetText(){ WCHAR acUserName[100]; DWORD nUserName = sizeof(acUserName); if (GetUserName(acUserName, &nUserName)) { Ssortingng^ name = gcnew Ssortingng(acUserName); return Ssortingng::Format("Hello {0} !", name); }else{ return gcnew Ssortingng("Error!"); } } }; } 

Maintenant créé un nouveau projet C # et ajoute une référence à notre premier projet de bibliothèque de classes C ++ / CLI. Et puis appelez la méthode d’instance.

 namespace CSTester { class Program { static void Main(ssortingng[] args) { CSCPP.Class1 instance = new CSCPP.Class1(); Console.WriteLine(instance.GetText()); } } } 

Cela a donné le résultat suivant sur ma machine:

Bonjour m3rlinez!

C ++ / CLI est fondamentalement une extension gérée par la norme C ++. Il vous permet d’utiliser les classes et les types de données CLR dans votre projet C ++ / CLI et de les exposer au langage géré. Vous pouvez créer un wrapper géré pour votre ancienne bibliothèque C ++ en utilisant ceci. Il existe des syntaxes étranges telles que Ssortingng^ pour définir le type de référence à la chaîne CLR. Je trouve “Quick C ++ / CLI – Learn C ++ / CLI en moins de 10 minutes” pour être utile ici.

Il existe au moins trois méthodes pour appeler du code non géré depuis le même processus:

  1. C ++ / CLI
  2. Invocation de plate-forme
  3. Enveloppez votre C ++ dans un object COM

Au travail, nous utilisons C ++ / CLI pour cela, cela semble fonctionner.

Je voudrais créer une bibliothèque de liens dynamics standard (non COM / Managed) comme décrit ici , puis utiliser l’ atsortingbut DllImport (invocation de plate-forme) dans le code c # pour accéder aux fonctions exscopes.

Le point clé de cet article:

Notez le modificateur __declspec (dllexport) dans les déclarations de méthode de ce code. Ces modificateurs permettent à la méthode d’être exscope par la DLL afin qu’elle puisse être utilisée par d’autres applications. Pour plus d’informations, voir dllexport, dllimport.

C’est une alternative plus légère à un wrapper d’interopérabilité COM et évite les problèmes tels que l’enregistrement, etc. (la DLL peut simplement être placée dans le répertoire de l’application).

Une autre alternative est It Just Works (IJW). C’est probablement un meilleur choix si vous avez géré du code C ++ et avez besoin d’y accéder depuis d’autres langages .NET. Mais ceci n’est qu’une option si vous êtes capable / heureux de convertir votre C ++ non géré en C ++ géré.

Je restrais loin de P / Invoke car c’est assez lent comparé à IJW (ça marche). Ce dernier vous permet d’entrelacer de manière transparente les c ++ gérés et non gérés. Tout ce que vous avez à faire est de créer un assembly c ++ géré, écrire une classe gérée visible à partir de c # et appeler le code non géré.

Uhm … OK. J’avais l’impression que les appels P / Invoke étaient plus lents qu’ils ne le sont pas. Cependant, en ayant un contrôle explicite sur le regroupement, vous pouvez améliorer la performance de votre version C ++ / CLI dans la plupart des cas.

Voici l’article de Microsoft sur les deux mécanismes:

http://msdn.microsoft.com/en-us/library/ms235282.aspx

Avantages de l’IJW

  • Il n’est pas nécessaire d’écrire des déclarations d’atsortingbuts DLLImport pour les API non gérées utilisées par le programme. Incluez simplement le fichier d’en-tête et le lien avec la bibliothèque d’importation.
  • Le mécanisme IJW est légèrement plus rapide (par exemple, les stubs IJW n’ont pas besoin de vérifier le besoin d’épingler ou de copier des éléments de données car cela est fait explicitement par le développeur).
  • Il illustre clairement les problèmes de performance. Dans ce cas, le fait que vous traduisez d’une chaîne Unicode en une chaîne ANSI et que vous disposez d’une allocation de mémoire et d’une désallocation concomitantes. Dans ce cas, un développeur écrivant le code en utilisant IJW se rendrait compte que l’appel de _putws et l’utilisation de PtrToSsortingngChars serait préférable pour les performances.
  • Si vous appelez de nombreuses API non managées en utilisant les mêmes données, le marshaling une fois et le passage de la copie marshalée est beaucoup plus efficace que le re-marshaling à chaque fois.

Il y a aussi des avantages esthétiques:

  • Le code C # ressemble à du code C # sans aucune interopérabilité.
  • Vous n’avez pas besoin de définir l’atsortingbut DLLImport , vous n’avez pas à définir les structures de données (également avec des atsortingbuts spécifiques à p / invoke) qui pourraient ressembler à ceci:

    [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)] structure publique DevMode {[MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] chaîne publique dmDeviceName; }

  • Vous n’avez pas besoin de convertir tous les types de primitives de paramètre en leurs homologues .NET (il y a un tableau sur cette page qui répertorie la manière dont les types gérés sont mappés sur les types non gérés).
  • Vous travaillez avec C ++ / CLI, ce qui est très amusant à apprendre et qui est vraiment perfectionné. Il a parcouru un long chemin depuis VS 2003 et est maintenant un langage .NET complet. La documentation Microsoft pour cela est très bonne, de même que toutes les informations IJW.
  • Faire de l’interopérabilité C ++ en C ++ / CLI semble très naturel par opposition à C #. Ceci est totalement subjectif, mais je préférerais de Marshal.PtrToSsortingng(ptr) faire du marshalling en C ++ qui fait Marshal.PtrToSsortingng(ptr) .
  • Si vous exposez une API, vous voudrez probablement envelopper tous les éléments P / Invoke dans un autre calque, vous n’avez donc pas à faire face à la laideur P / Invoke. De cette façon, vous avez la surcharge de tous les marshalling ET la couche C # qui l’entoure. Avec C ++ / CLI, le regroupement et l’abstraction d’interopérabilité sont au même endroit et vous pouvez choisir le nombre de processeurs dont vous avez besoin.

À mon humble avis, si vous appelez une fonction impaire dans Windows SDK, allez avec P / Invoke. Si vous exposez une API C ++ moyennement complexe au monde géré, indubitablement C ++ / CLI.