2010-04-14 24 views
10

Tengo un dll no administrado con una clase "MyClass" en él. ¿Hay alguna manera de crear una instancia de esta clase en el código C#? Para llamar a su constructor? Lo intenté pero el estudio visual informa un error con un mensaje de que esta área de memoria está dañada o algo así.Crear un objeto C++ no administrado en C#

Gracias de antemano

+0

¿Puedes publicar lo que has intentado? – SwDevMan81

+0

y el mensaje de error? – Asher

+0

1) vacío estático Principal (cadena [] args) { IntPtr p = new IntPtr(); Program.CreateObserv (ref p); } [DllImport (@ "C: \ mm_2008 \ liba.dll", EntryPoint = "?? 0CRls @ FLD @@ QAE @ ABV01 @@ Z", SetLastError = true, CallingConvention = CallingConvention.ThisCall)] extern interno estático void CreateObserv (ref IntPtr p); este código arroja una excepción AccessViolationException: accessviolationexception intentó leer o escribir en la memoria protegida ... – Evgeny007

Respuesta

19

C# no se puede crear instancia de clase exportado de DLL nativa. Tiene dos opciones:

  1. Crear C++/CLI wrapper. Esta es .NET Class Library que se puede agregar como referencia a cualquier otro proyecto .NET. Internamente, la clase C++/CLI funciona con clase no administrada, vinculándose a Dll nativo según las reglas estándar de C++. Para el cliente .NET, esta clase C++/CLI se parece a la clase .NET.

  2. Escriba C wrapper para la clase C++, que puede ser utilizado por el cliente .NET con PInvoke. Por ejemplo, la sobre-simplificado clase C++:

 

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

C envoltorio de API para esta clase:

 

    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 y GetData pueden declararse en C# cliente utilizando PInvoke, y llamó directamente . el parámetro void * debe declararse como IntPtr en la declaración PInvoke.

+1

Extrañas una "C" externa en las funciones de contenedor. – Danvil

+0

Danvil: esto es lo que escribí en la nota de pregunta. De todos modos, gracias, realmente me siento mejor ahora. –

+0

@Alex ¿Qué pasa si hay una jerarquía de clases en el dominio nativo de C++ ... ?? – rsjethani

2

No puede usar código C++ no mandado directamente en C#. La interoperabilidad se puede hacer usando PInvoke. Hay a lot of issues related to this topic, especialmente cuando se llaman funciones que tienen punteros como argumentos.

El procedimiento básico dice así:

C# parte

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

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

C++ parte

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

MyClass* staticObject; 

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

gracias a todos, odiaba admitirlo pero parece que no hay otra manera que escribir un envoltorio. – Evgeny007

+0

Otra opción es escribir C++ administrado usando el indicador compilador/crl. Luego puede mezclar el código no administrado y administrado en el mismo dll y luego los métodos administrados de llamada simple en su código C#. Producirá el código SAM IL ya que ajustaría los métodos nativos en su código. Introducción rápida http://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-minutes –

2

La solución es crear C++/envoltura CLI como:

#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; 
    } 
}; 

donde CDllExportClass es la clase exportada desde el código nativo. Arriba está el .h de C++/CLI. Tenga cuidado de dejar encontrar la lib a este dll. Coloque el dll y la lib en el mismo directorio y compile el código C++/CLI. En el directorio del código administrado, coloque el dll nativo y el dll de C++/CLI. En el proyecto administrado, ponga la referencia del proyecto C++/CLI. Instanciate en el código maged la clase C++/CLI como:

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

Es todo.

Cuestiones relacionadas