Comment appeler une bibliothèque C# à partir de C++ natif (en utilisant C++CLI et IJW)

Background: dans le cadre d'une mission plus vaste, je dois rendre une bibliothèque c/" class="blnk">C# accessible au code C++ et C non géré. Pour tenter de répondre à cette question, j'ai moi-même appris le C++/CLI au cours des derniers jours/ semaines.

il semble y avoir un certain nombre de façons différentes de réaliser en utilisant un C# dll non géré C++ et C. Certaines des réponses en bref semblent être: utiliser les services Interlope, utiliser .com. et regasm, en utilisant PInvoke (qui semble passer de C# à C++ seulement), et en utilisant IJW dans le C++/CLR (qui semble être des services Interlope). Je pense qu'il serait préférable de mettre en place une bibliothèque qui est peut-être un wrapper CLR qui utilise IJW pour appeler mon c# dll au nom du code natif C++ et C.

Spécificités: j'ai besoin de transmettre des valeurs de chaîne ainsi que int C# dll à partir d'un code c++, et de retour void.

pertinence: de nombreuses entreprises avoir de nombreuses excuses pour mélanger et faire correspondre C++, C et c#. Performance: le code non géré est généralement plus rapide, les interfaces: les interfaces gérées sont généralement plus faciles à entretenir, à déployer, et sont souvent plus faciles aux yeux, disent les gestionnaires. Le code d'héritage nous force aussi. Il était là (Comme la montagne que nous avons grimpé). Alors que les exemples de comment appeler une bibliothèque C++ à partir de C# sont abondants. Les exemples de comment appeler les bibliothèques C# à partir du code C++ sont difficiles à trouver via Googling surtout si vous voulez voir mis à jour 4.0+ code.

Software: C#, C++ / CLR, C++, C, Visual Studio 2010, and .NET 4.0

détails de la Question: OK question en plusieurs parties:

  1. y a-t-il un avantage à utiliser des objets com? Ou la PInvoke? Ou une autre méthode? (Je sens que la courbe d'apprentissage sera juste aussi raide, même si je ne trouver plus d'informations sur le sujet dans Google Terres. IJW semble promesse de ce que je veux faire. Devrais-je abandonner la recherche d'une solution IJW et me concentrer sur celle-ci à la place?) (Avantage/ inconvénient?)

  2. ai-je raison d'imaginer qu'il existe une solution où j'écris un wrapper qui utilise IJW dans le C++/CLR? Où puis-je trouver plus d'informations sur ce sujet, et ne pas dire que je N'ai pas assez Google/ ou regarder MSDN sans me dire où vous l'avez vu là. (Je crois que je préfère cette option, dans l'effort de Ecrivez un code clair et simple.)

  3. un rétrécissement de la portée de la question: je pense que mon véritable problème et besoin est de répondre à la petite question qui suit: Comment puis-je configurer une bibliothèque C++/CLR qu'un fichier C++ non géré peut utiliser dans visual studio. Je pense que si je pouvais simplement instancier une Classe C++ gérée dans du code C++ non géré, alors je pourrais peut-être m'occuper du reste (interfacer et emballer, etc.).). J'attends que mon principal folie est en essayant de mettre en place références / #includes etc. dans Visual Studio, j'ai clairement pensé que je pouvais avoir d'autres idées fausses. Peut-être la réponse à tout ceci pourrait être juste un lien vers un tutoriel ou des instructions que m'aider avec cela.

projet de Recherche: j'ai Googlé et Boulimiques plus et plus avec un certain succès. J'ai trouvé de nombreux liens qui vous montrent comment utiliser une bibliothèque non gérée à partir du code C#. Et je dois admettre qu'il y a eu des liens qui montrent comment le faire en utilisant des objets com. Peu de résultats ont été ciblés par rapport à 2010.

, les Références: J'ai lu et relu de nombreux postes. J'ai essayé de travailler à travers les plus pertinents. Certains semblent terriblement proche de la réponse, mais je n'arrive pas à les faire fonctionner. Je soupçonne que la chose que je suis absent est tellement petit, comme l'utilisation abusive du mot-clé ref, ou de manquer un #include ou en utilisant la déclaration, ou un usage abusif de l'espace de noms, ou ne pas utiliser correctement la fonctionnalité IJW, ou manquer un paramètre dont VS a besoin pour gérer la compilation correctement, etc. Alors pourquoi ne pas inclure le code? J'ai l'impression de ne pas être à un endroit où je comprends et où je m'attends à ce que le code fonctionne. Je veux être dans un endroit où je le comprends, quand j'y serai peut-être, j'aurai besoin d'aide pour le réparer. Je vais inclure au hasard deux des liens mais je ne suis pas autorisé à les montrer tous à mon niveau actuel de point D'impact.

http://www.codeproject.com/Articles/35437/Moving-Data-between-Managed-Code-and-Unmanaged-Cod

ceci appelle du code géré et non géré dans les deux directions allant de C++ à Visual Basic et retour via C++CLR, et bien sûr je suis intéressé par C#.: http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice

33
demandé sur amalgamate 2012-11-08 20:58:57

5 réponses

, Vous pouvez le faire assez facilement.

  1. créer un .h./rpc combo
  2. activer / clr sur le nouveau créer .fichier cpp. (CPP -> clic droit -> Propriétés)
  3. définit le chemin de recherche pour" #additional using directories " pour pointer vers votre C# dll.

Native.h

void NativeWrapMethod();

Native.cpp

#using <mscorlib.dll>
#using <MyNet.dll>

using namespace MyNetNameSpace;

void NativeWrapMethod()
{
    MyNetNameSpace::MyManagedClass::Method(); // static method
}

C'est la base de l'utilisation d'un C# lib en C++\CLI avec du code natif. (Référence seulement natif.h le cas échéant, et appelez la fonction.)

utilisant le code C# avec le code géré par C++\CLI est à peu près le même.

Il ya beaucoup de désinformation sur ce sujet, donc, espérons que cela sauve quelqu'un beaucoup de tracas. :)


j'ai fait ceci dans: VS2010 - VS2012 (cela fonctionne probablement aussi dans VS2008.)

30
répondu Smoke 2012-11-16 00:29:40

si vous voulez utiliser COM, voici ma solution pour ce problème:

C# bibliothèque

tout d'abord, vous avez besoin d'une bibliothèque COM compatible.

  • vous en avez déjà un? Parfait, vous pouvez sauter cette partie.

  • Vous avez accès à la bibliothèque? Assurez-vous qu'il est compatible COM en suivant les étapes.

    1. assurez-vous que vous coché L'option "S'Enregistrer pour COM interop" dans les propriétés de votre projet. Properties -> Build -> faites Défiler vers le bas -> Enregistrer le pour COM interop

les captures d'écran suivantes montrent où vous trouvez cette option.

Screenshot Project Properties Build

  1. toutes les interfaces et classes qui devraient être disponibles besoin d'avoir un GUID

    namespace NamespaceOfYourProject
    {
        [Guid("add a GUID here")]
        public interface IInterface
        {
            void Connect();
    
            void Disconnect();
        }
    }
    
    namespace NamespaceOfYourProject
    {
         [Guid("add a GUID here")]
         public class ClassYouWantToUse: IInterface
         {
             private bool connected;
    
             public void Connect()
             {
                 //add code here
             }
    
             public void Disconnect()
             {
                 //add code here
             }
         }
    }
    

donc c'est à peu près ce que vous avez à faire avec votre code C#. Continuons avec le code C++.

C++

  1. tout d'abord nous avons besoin d'importer la bibliothèque C#.

après avoir compilé votre bibliothèque C# il devrait y avoir un .fichier tlb.

#import "path\to\the\file.tlb"

Si vous importez ce nouveau fichier créé à votre fichier.cpp vous pouvez utiliser votre objet comme variable locale.

#import "path\to\the\file.tlb"

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);

    NamespaceOfYourProject::IInterfacePtr yourClass(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));

    yourClass->Connect();

    CoUninitialize();
}
  1. en utilisant votre classe comme attribut.

vous remarquerez que la première étape ne fonctionne qu'avec une variable locale. Le code suivant montre comment l'utiliser comme un attribut. Liée à cette" question 1519390920".

vous aurez besoin du ComPtr, qui est situé dans atlcomcli.h. Inclure ce fichier dans votre fichier d'en-tête.

CPlusPlusClass.h

#include <atlcomcli.h> 
#import "path\to\the\file.tlb"

class CPlusPlusClass
{
public:
    CPlusPlusClass(void);
    ~CPlusPlusClass(void);
    void Connect(void);

private:
    CComPtr<NamespaceOfYourProject::IInterface> yourClass;
}

CPlusPlusClass.cpp

CPlusPlusClass::CPlusPlusClass(void)
{
    CoInitialize(NULL);

    yourClass.CoCreateInstance(__uuidof(NamespaceOfYourProject::ClassYouWantToUse));

}

CPlusPlusClass::~CPlusPlusClass(void)
{
    CoUninitialize();
}

void CPlusPlusClass::Connect(void)
{
    yourClass->Connect();
}

C'est ça! Amusez-vous avec vos classes C# en C++ avec COM.

13
répondu 0lli.rocks 2017-05-23 11:54:47

la meilleure façon que j'ai trouvée de faire ceci est de créer un PONT c++/cli qui connecte le code C# à votre C++natif. Je ne recommande pas D'utiliser des objets COM pour résoudre votre problème. Vous pouvez le faire avec 3 projets différents.

  • premier projet: c # bibliothèque
  • Deuxième Projet: C++/CLI pont (cette enveloppe le C# bibliothèque)
  • troisième projet: Application Native C++ qui utilise le deuxième projet

un bon visuel/tutoriel sur ce peut être trouvé ici , et le meilleur walkthrough complet que j'ai trouvé à faire ce peut être trouvé ici ! Entre ces deux liens et un peu de grit, vous devriez être capable de créer un PONT C++/CLI qui vous permet d'utiliser du C# code dans votre C++natif.

7
répondu jsmith 2015-01-14 23:08:09

j'ai trouvé quelque chose qui commence au moins à répondre à ma propre question. Les deux liens suivants ont des fichiers wmv de Microsoft qui démontrent l'utilisation d'une Classe C# dans le C++non géré.

ce premier utilise un objet COM et un régasme: http://msdn.microsoft.com/en-us/vstudio/bb892741 .

ce second utilise les fonctionnalités de C++ / CLI pour envelopper la Classe C#: http://msdn.microsoft.com/en-us/vstudio/bb892742 . J'ai été capable d'instancier une Classe c# à partir du code géré et de récupérer une chaîne de caractères comme dans la vidéo. Il a été très utile, mais il ne répond que 2 / 3rds de ma question car je veux instancier une classe avec un périmètre de chaîne dans une Classe c#. Comme preuve de concept, j'ai modifié le code présenté dans l'exemple pour la méthode suivante, et j'ai atteint cet objectif. Bien sûr, j'ai aussi ajouté un Modifié le {public string PickDate (nom de chaîne)} méthode pour faire quelque chose avec la chaîne de nom pour prouver à moi-même qu'il a travaillé.

wchar_t * DatePickerClient::pick(std::wstring nme)
{
    IntPtr temp(ref);// system int pointer from a native int
    String ^date;// tracking handle to a string (managed)
    String ^name;// tracking handle to a string (managed)
    name = gcnew String(nme.c_str());
    wchar_t *ret;// pointer to a c++ string
    GCHandle gch;// garbage collector handle
    DatePicker::DatePicker ^obj;// reference the c# object with tracking handle(^)
    gch = static_cast<GCHandle>(temp);// converted from the int pointer 
    obj = static_cast<DatePicker::DatePicker ^>(gch.Target);
    date = obj->PickDate(name);
    ret = new wchar_t[date->Length +1];
    interior_ptr<const wchar_t> p1 = PtrToStringChars(date);// clr pointer that acts like pointer
    pin_ptr<const wchar_t> p2 = p1;// pin the pointer to a location as clr pointers move around in memory but c++ does not know about that.
    wcscpy_s(ret, date->Length +1, p2);
    return ret;
}

une partie de ma question était: Qu'est-ce qui est mieux? De ce que j'ai lu dans de nombreux efforts de recherche, la réponse est que les objets COM sont considérés comme plus faciles à utiliser, et l'utilisation d'un wrapper à la place permet un plus grand contrôle. Dans certains cas, l'utilisation d'un wrapper peut (mais pas toujours) réduire la taille du thunk, car les objets COM ont automatiquement une empreinte de taille standard et les wrappers sont seulement aussi gros qu'ils doivent l'être.

Le thunk (comme je l'ai utilisé ci-dessus) se réfère à l'espace-temps et aux ressources utilisées entre C# et C++ dans le cas de L'objet COM, et entre C++/CLI et natif C++ dans le cas du codage-en utilisant un enveloppeur C++/CLI. Donc une autre partie de ma réponse devrait inclure un avertissement que traverser la frontière de thunk plus qu'il n'est absolument nécessaire est une mauvaise pratique, l'accès à la frontière de thunk à l'intérieur d'une boucle n'est pas recommandé, et qu'il est possible de mettre en place un wraper incorrectement de sorte qu'il Double thunks (franchit la frontière deux fois où un seul thunk est demandé) sans que le code semble incorrect pour un novice comme moi.

deux notes sur les wmv. Premièrement: certaines séquences sont réutilisées dans les deux, ne vous y trompez pas. Au début, elles semblent identiques, mais elles couvrent des sujets différents. Deuxièmement, il y a quelques traits de prime tels que le marshalling qui sont maintenant une partie du CLI qui ne sont pas couverts dans le wmv.

Edit:

Note il y a une conséquence pour vos installations, votre wrapper c++ ne sera pas trouvé par le CLR. Vous devrez confirmer que l'application c++ installe dans tout/chaque répertoire qui l'utilise, ou l'ajout de la bibliothèque (qui devra ensuite être nommé fortement) à la GAC au moment de l'installation. Cela signifie également qu'avec l'un ou l'autre cas dans les environnements de développement, vous devrez probablement copier la bibliothèque dans chaque répertoire où les applications l'appellent.

4
répondu amalgamate 2015-04-01 15:56:32

j'ai fait un tas de recherche et j'ai trouvé un article relativement récent de Microsoft détaillant comment il peut être fait (il ya beaucoup de Vieille infomration flottant autour). De l'article lui-même:

l'échantillon de code utilise les API d'hébergement CLR 4 pour héberger CLR dans un projet natif C++, charger et invoquer les assemblages .NET""

https://code.msdn.microsoft.com/CppHostCLR-e6581ee0

essentiellement, il décrit en deux étapes:

  1. Charger le CLR dans un processus de
  2. Chargez votre assemblage.
0
répondu gremwell 2016-10-16 23:02:43