utilizando una clase definida en un c ++ dll en código c #

Tengo un dll que fue escrito en c ++, necesito usar este dll en mi código c #. Después de buscar encontré que usar P / Invoke me daría acceso a la función que necesito, pero estas funciones están definidas en una clase y usan variables de miembros privados no estáticos. Entonces necesito poder crear una instancia de esta clase para usar las funciones correctamente. ¿Cómo puedo acceder a esta clase para poder crear una instancia? No he podido encontrar una manera de hacer esto.

Supongo que debería tener en cuenta que el c ++ dll no es mi código.

No hay forma de usar directamente una clase C ++ en el código C #. Puede usar PInvoke de forma indirecta para acceder a su tipo.

El patrón básico es que para cada función miembro en la clase Foo, cree una función asociada no miembro que llame a la función miembro.

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

Ahora se trata de invocar estos métodos en su código 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); 

La desventaja es que tendrá un intPtr incómodo para pasar, pero es una cuestión bastante simple crear una clase contenedora C # alrededor de este puntero para crear un modelo más útil.

Incluso si no posee este código, puede crear otra DLL que envuelva la DLL original y proporcione una pequeña capa de PInvoke.

Marshal C ++ Class y usa el PInvoke

C ++ Code, ClassName.h

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

C ++ Code, ClassName.cpp

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

Código C ++, archivo ClassNameCaller.h para la función de llamada

 #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 

Código C ++, archivo ClassNameCaller.cpp para la función de llamada

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

C # code

 [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; 

Aquí hay una muestra de cómo llamar al método de clase C ++ desde VB: para C # solo tiene que volver a escribir el progtwig de muestra en el Paso 4.

myfile.i

 %module learnaboutswig class A { public: void boringfunction(char *charstr); }; 

descargar swig desde swig.org

swig -c ++ -csharp myfile.i

mira la salida, mira si te va a funcionar.

Es posible que necesite escribir una DLL intermediaria (en C ++, tal vez) que maneje esto por usted y exponga la interfaz que necesita. Su DLL estaría a cargo de cargar la DLL de terceros, crear una instancia de este objeto C ++ y exponer sus funciones miembro según sea necesario a través de la API que diseñe. Luego usaría P / Invoke para acceder a su API y manipular limpiamente el objeto.

Nota: Para la API de su DLL, intente mantener los tipos de datos limitados a primitivas (long, int, char *, etc.) para evitar problemas de límite de módulo.

Estoy de acuerdo con JaredPar. Crear instancias de clases no administradas en código administrado no debería ser posible.

Otra cosa es: si pudieras recomstackr la DLL en C ++ administrado o crear un componente COM a partir de ella, sería mucho más fácil /

La forma en que lo he hecho es creando un envoltorio delgado de Managed C ++ alrededor de mi DLL no administrada de C ++. El contenedor gestionado contiene clases de “proxy” que envuelven el código no administrado y exponen la interfaz que necesita la aplicación .NET. Esto es un poco de trabajo doble, pero permite un funcionamiento sin interrupciones en entornos normales. Las cosas se vuelven más complicadas con las dependencias en algunas circunstancias (como ASP.NET) pero es probable que no te encuentres con eso.