Comment utiliser C ++ / CLI dans une application C #

J’essaie d’appeler ma bibliothèque C ++ à partir de mon application C # (via C ++ / CLI). J’ai suivi l’exemple de cette question (pour mon application spécifique). La configuration de mon application est:

  • Project1: Projet C ++ (je comstack cela en une DLL)
  • Project2: Projet C ++ (mon wrapper CLR; uniquement le fichier d’en-tête selon l’exemple ci-dessus; fait référence à Project1)
  • Project3: Projet C # (références Project2)

Malheureusement, lorsque je vais accéder à l’object wrapper CLR dans mon application C #, je reçois le message d’erreur suivant:

Impossible de trouver le type ou le nom de l’espace de noms ‘YourClass’ (il manque une directive using ou une référence d’assembly?)

Le projet est-il mal configuré ou y a-t-il autre chose sur lequel je devrais me pencher? (Malheureusement, je ne peux pas publier le code pour des raisons de propriété, mais c’est un morceau de code très simple qui suit facilement l’exemple ci-dessus.)

Mettre à jour:

J’ai donc fait exactement ce que Chris avait dit de faire (voir la réponse ci-dessous), mais je continue à recevoir un message de mon application C # indiquant que “Le type ou le nom de l’espace de nom ‘MonProgramme’ est introuvable. référence?). Voici une (maquette) de mon code.

  • Project1 – Ceci est mon application C ++. Il comstack / fonctionne. Je l’ai utilisé ailleurs. (Je reçois une DLL de cette version.)
  • Project2 – Voici mon code pour mon wrapper.

MyWrapper.h

#pragma once #include "myorigapp.h" using namespace System; namespace MyProgram { public ref class MyWrapper { private: myorigapp* NativePtr; public: MyWrapper() { NativePtr = new myorigapp(); } ~MyWrapper() { delete NativePtr; NativePtr = NULL; } void dostuff() { NativePtr->dostuff(); } } } 
  • Project3 – Ceci est mon application C #.

Program.cs

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyProgram; namespace Testing { class Program { static void Main(ssortingng[] args) { MyWrapper p = new MyWrapper(); p.dostuff(); } } } 

Project3 fait référence à Project2 qui fait référence à Project1. Tout se construit sans erreur (à l’exception de l’erreur que j’ai décrite ci-dessus dans le code C # de la ligne using MyProgram ).

Le simple fait d’inclure l’en-tête d’une application purement C ++ n’est pas suffisant. Vous devez encapsuler vos objects non gérés avec des objects gérés dans Project2 (c’est-à-dire public ref class YourClassDotNet ).

 #include "YourHeader.h" namespace MyManagedWrapper { public ref class YourClassDotNet { private: YourClass* ptr; public: YourClassDotNet() { ptr = new YourClass(); } ~YourClassDotNet() { this->!YourClassDotNet(); } !YourClassDotNet() { delete ptr; ptr = NULL; } void SomeMethod() { ptr->SomeMethod(); } } } 

D’accord, je me sens maintenant stupide.

Il s’est avéré que le problème que j’avais (et que j’ai résolu il ya quelques semaines – je viens de mettre à jour cette réponse) est que j’avais inclus le fichier d’en-tête (voir la réponse de Chris pour cela), le fichier CPP (qui est vide, à l’exception du fichier d’en-tête).

Une fois cette opération effectuée, la DLL a été compilée correctement et j’ai pu appeler les fonctions C ++ (à l’aide de C ++ / CLI) à partir de mon code C #.

Chris vous a montré comment créer une classe gérée utilisant du code non géré à l’intérieur. Il y a beaucoup de choses que vous pouvez faire en C # en utilisant peu sûr (c’est juste que presque personne ne le fait).

Cependant, l’inverse est également possible: utiliser des types .NET directement à partir d’un type / d’une fonction native.

La chose à surveiller est que tout pointeur géré doit être marqué comme tel. À cette fin, C ++ / CLI définit un type spécial de smartpointer gcroot (imitant boost :: shared_pointer ou std :: auto_ptr en quelque sorte). Donc, pour stocker une chaîne gérée dans votre classe C ++, utilisez ce qui suit:

 #include  #include  using namespace System; class CppClass { public: gcroot str; // can use str as if it were Ssortingng^ CppClass(const std::ssortingng& text) : str(gcnew Ssortingng(text.c_str())) {} }; int main() { CppClass c("hello"); c.str = gcnew Ssortingng("bye"); Console::WriteLine( c.str ); // no cast required } 

Notez que (si cela n’a pas été corrigé ces jours-ci), vous vous heurterez à la discordance entre null géré et C / C ++ NULL. Vous ne pouvez pas facilement taper, comme on peut s’y attendre:

 gcroot the_thing; ... if (the_thing != nullptr) ... } 

Au lieu de cela, vous devrez utiliser le style natif (le wrapper intelligent gcroot gère cela)

 gcroot< Object^ > the_thing; if ( the_thing != NULL ) {} // or equivalently... if ( the_thing ) {} // not too sure anymore, but I thought the following is also possible: if ( the_thing != gcroot(nullptr) ) {} 

Remarque: comme je n’ai pas access à une machine Windows, j’ai cité de mémoire