web-dev-qa-db-fra.com

en utilisant une classe définie dans une dll c ++ en 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'avais besoin, mais ces fonctions sont définies avec dans une classe et utilisent des variables de membre privé 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 afin de pouvoir créer une instance? Je n'ai pas réussi à trouver un moyen de le faire.

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

63
Dan Vogel

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

Le modèle 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; }

Il s'agit maintenant de PInvoquer 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 à transmettre, mais il est assez simple de créer une classe wrapper 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 un autre DLL qui enveloppe l'original DLL et fournit une petite couche PInvoke).

83
JaredPar

Marshal C++ Class et utilisez le PInvoke

Code C++, ClassName.h

class __declspec(dllexport) CClassName
{
 public:
    CClassName();
    ~CClassName();
    void function();

};

Code C++, ClassName.cpp

CClassName::CClassName()
{
}

CClassName::~CClassName()
{
}

void CClassName::function()
{
    std::cout << "Bla bla bla" << std::endl;

}

Code C++, fichier ClassNameCaller.h pour la fonction appelant

#include "ClassName.h"      

#ifdef __cplusplus
extern "C" {
#endif

extern __declspec(dllexport) CClassName* CreateClassName();

extern __declspec(dllexport) void DisposeClassName(CClassName* a_pObject);

extern __declspec(dllexport) void function(CClassName* a_pObject);


#ifdef __cplusplus
}
#endif

Code C++, fichier ClassNameCaller.cpp pour la fonction appelant

#include "ClassNameCaller.h"


CClassName* CreateClassName()
{
    return new CClassName();
}

void DisposeClassName(CClassName* a_pObject)
{
    if(a_pObject!= NULL)
    {
        delete a_pObject;
        a_pObject= NULL;
    }
}

void function(CClassName* a_pObject)
{
    if(a_pObject!= NULL)
    {
        a_pObject->function();
    }
}

Code C #

[DllImport("ClassNameDll.dll")]
static public extern IntPtr CreateClassName();

[DllImport("ClassNameDll.dll")]
static public extern void DisposeClassName(IntPtr pClassNameObject);

[DllImport("ClassNameDll.dll")]
static public extern void CallFunction(IntPtr pClassNameObject);

//use the functions
IntPtr pClassName = CreateClassName();

CallFunction(pClassName);

DisposeClassName(pClassName);

pClassName = IntPtr.Zero; 
18
Amir Twito

Ici est un exemple comment appeler la méthode de classe C++ à partir de VB - pour C #, il vous suffit de réécrire l'exemple de programme à l'étape 4.

4
Dmitry Khalatov

myfile.i

%module learnaboutswig

class A

{

public:

    void boringfunction(char *charstr);
};

télécharger swig depuis swig.org

swig -c ++ -csharp monfichier.i

regardez la sortie, voyez si cela fonctionnera pour vous.

3
astronought

Pour ce faire, j'ai créé un wrapper C++ managé fin autour de ma DLL C++ non managée. Le wrapper managé contient des classes "proxy" qui enveloppent le code non managé exposant l'interface dont l'application .NET a besoin. C'est un peu un double travail, mais cela permet un fonctionnement assez transparent dans des environnements normaux. Les choses deviennent plus compliquées avec les dépendances dans certaines circonstances (comme ASP.NET) mais vous ne rencontrerez probablement pas cela.

2
Joris Timmermans

Vous devrez peut-être écrire un intermédiaire DLL (en C++, peut-être) qui gère cela pour vous et expose l'interface dont vous avez besoin. Votre DLL serait en charge) 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. Vous utiliseriez alors 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 primitives (long, int, char *, etc.) pour éviter les problèmes de limites de module.

2
Brian

Je suis d'accord avec JaredPar. La création d'instances de classes non managées dans du code managé ne devrait pas être possible.

Une autre chose est - si vous pouviez recompiler le DLL en C++ managé ou en faire un composant COM, ce serait beaucoup plus facile /

2
badbadboy