2010-04-14 8 views
10

J'ai une DLL non managée avec une classe "MyClass" dedans. Maintenant, existe-t-il un moyen de créer une instance de cette classe en code C#? Pour appeler son constructeur? J'ai essayé mais le studio visuel signale une erreur avec un message que cette zone de mémoire est corrompue ou quelque chose.Créer un objet C++ non géré dans C#

Merci à l'avance

+0

Pouvez-vous poster ce que vous avez essayé? – SwDevMan81

+0

et le message d'erreur? – Asher

+0

1) static void Main (chaîne [] arguments) { IntPtr p = new IntPtr(); Program.CreateObserv (réf. P); } [DllImport (@ "C: \ mm_2008 \ liba.dll", EntryPoint = "?? 0CRls @ FLD @@ QAE @ ABV01 @@ Z", SetLastError = true, CallingConvention = CallingConvention.ThisCall)] interne externe extern void CreateObserv (ref IntPtr p); ce code déclenche une AccessViolationException: AccessViolationException a tenté de lire ou d'écrire la mémoire protégée ... – Evgeny007

Répondre

19

C# ne peut pas créer une instance de classe exportée à partir dll natif. Vous avez deux options:

  1. Créer un wrapper C++/CLI. C'est la bibliothèque de classes .NET qui peut être ajoutée en tant que référence à tout autre projet .NET. En interne, la classe C++/CLI fonctionne avec la classe non managée, en liant la DLL native aux règles C++ standard. Pour le client .NET, cette classe C++/CLI ressemble à la classe .NET.

  2. Écrire encapsuleur C pour la classe C++, qui peut être utilisé par le client .NET avec PInvoke. Par exemple, plus simplifié C++ Classe:

 

    class MyClass() 
    { 
    public: 
     MyClass(int n){data=n;} 
     ~MyClass(){} 
     int GetData(){return data;} 
    private: 
     int data; 
    }; 

C wrapper API pour cette classe:

 

    void* CreateInstance() 
    { 
     MyClass* p = new MyClass(); 
     return p; 
    } 

    void ReleaseInstance(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     delete p; 
    } 

    int GetData(void* pInstance) 
    { 
     MyClass* p = (MyClass*)pInstance; 
     return p->GetData(); 
    } 

    // Write wrapper function for every MyClass public method. 
    // First parameter of every wrapper function should be class instance. 

CreateInstance, ReleaseInstance et GetData peut être déclaré dans le client C# en utilisant PInvoke et appelé directement . Le paramètre void * doit être déclaré comme IntPtr dans la déclaration PInvoke.

+1

Vous manquez un extern "C" dans les fonctions d'encapsuleur. – Danvil

+0

Danvil - c'est ce que j'ai écrit dans la note de question. En tout cas, merci, je me sens vraiment mieux maintenant. –

+0

@Alex Et s'il existe une hiérarchie de classes dans la DLL C++ native ... ?? – rsjethani

2

Vous ne pouvez pas utiliser de code C++ non masqué directement en C#. L'interopérabilité peut être faite en utilisant PInvoke. Il y a a lot of issues related to this topic, en particulier lors de l'appel de fonctions qui ont des pointeurs comme arguments.

La procédure de base va comme ceci:

C# partie

namespace MyNamespace { 
    public class Test { 
    [DllImport("TheNameOfThe.dll")] 
    public static extern void CreateMyClassInstance(); 

    public void CallIt() { 
     CreateMyClassInstance(); // calls the unmanged function via PInvoke 
    } 
    } 
} 

C++ partie

class MyClass { 
    public: MyClass() { /** Constructor */ } 
}; 

MyClass* staticObject; 

extern "C" void CreateMyObjectInstance() { 
    staticObject = new MyClass(); // constructor is called 
} 
+0

Merci à tout le monde, j'ai détesté l'admettre mais il semble qu'il n'y ait pas d'autre moyen que d'écrire un emballage. – Evgeny007

+0

L'autre option est d'écrire C++ géré en utilisant compilateur/crl flag. Ensuite, vous pouvez mélanger du code managé et non managé dans la même DLL puis des méthodes simples d'appel gérées dans votre code C#. Il va produire du code sam IL comme vous envelopperiez les méthodes natives dans votre code. Introduction rapide http://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-minutes –

2

La solution est de créer C++/wrapper CLI comme:

#include "DllExportClass.h" 

public ref class ManagedOperationHelper 
{ 
    public: 

    double Sum(double add1, double add2) 
    { 
     CDllExportClass obj; 
     double ret=obj.Sum(add1, add2); 
     return ret; 
    } 

    double Mult(double mult1, double mult2) 
    { 
     CDllExportClass obj; 
     double ret=obj.Mult(mult1, mult2); 
     return ret; 
    } 
}; 

où CDllExportClass est la classe exportée du code natif. Ci-dessus est le .h du C++/CLI. Prenez soin de laisser trouver la lib à cette DLL. Placez la DLL et la bibliothèque dans le même répertoire et compilez le code C++/CLI. Dans le répertoire de code géré, placez la DLL native et la DLL C++/CLI. Dans le projet géré, mettez la référence du projet C++/CLI. Instancié dans le code maged la classe C++/CLI comme:

ManagedOperationHelper obj = new ManagedOperationHelper(); 
double ret=obj.Sum(10, 20); 

C'est tout.

Questions connexes