2010-09-16 18 views

Respuesta

19

Fundamentalmente, hay tres formas correctas de hacerlo:

  • Utilice C++/CLI. Esta es la forma óptima si esta DLL va a ser utilizada solo por .NET.
  • Utilice una API compatible con "extern "C"", como la API de Windows. Este es el más portátil, pero no es tan conveniente para quienes llaman como el uso de un modelo de clase para representar sus objetos.
    • Esta es la mejor opción si realmente desea escribir en ANSI C (no en C++).
    • Por este camino, usted escribe sus funciones como extern "C" returntype __stdcall __declspec(dllexport) func(params) { ... }
    • También debe utilizar un modelo de memoria "Caller-ofrece-el-buffer", en lugar de devolver un búfer asignado dentro de su biblioteca. En los casos en que necesita asignar memoria para el estado interno, la persona que llama debe verlo como un identificador opaco y debe proporcionar funciones de acceso para que la persona que llama pueda extraer datos. Bajo ninguna circunstancia se debe esperar que la persona que llama desasigne la memoria asignada dentro de su biblioteca, sin embargo, está bien que la persona que llama pida a la biblioteca que realice la desasignación.
  • Use COM o una API tipo COM. Aquí regresa (a menudo a través de un parámetro) un puntero a una interfaz, que es una clase con funciones virtuales puras, sin funciones no virtuales y sin datos.
    • La implementación está en clases concretas derivadas de esta interfaz abstracta, pueden tener datos y funciones auxiliares en abundancia, ya que eso no afecta a la interfaz binaria.
    • Esto es mucho más trabajo en la biblioteca pero extremadamente portátil y fácil de usar para el consumidor.

Y hay una cosa que absolutamente no se debe hacer:

  • uso __declspec(dllexport) en clases de C++.

EDIT: también quiero explicar algunas buenas prácticas para la opción n. ° 2, que maximizará la portabilidad y hará que las partes nativas de C/C++ se puedan utilizar también desde aplicaciones no administradas.

Usted puede hacer que más fácil con una macro, la forma habitual de hacerlo es:

En el archivo de cabecera, todas las declaraciones de funciones parecen

MYPROJECTAPI(returntype) PublicFunc(params); 

En su proyecto, la definición es

#define MYPROJECTAPI(returntype) \ 
        extern "C" returntype __stdcall __declspec(dllexport) 

En los proyectos de consumo

#define MYPROJECTAPI(returntype) \ 
        extern "C" returntype __stdcall __declspec(dllimport) 

y luego puede definir la macro de manera diferente para otros compiladores como gcc que no usan __declspec.

La solución completa se vería así (en el archivo de cabecera pública myproject.h):

#if _WIN32 
# if BUILDMYPROJECT 
# define MYPROJECTAPI(returntype) \ 
     extern "C" returntype __stdcall __declspec(dllexport) 
# else 
# define MYPROJECTAPI(returntype) \ 
     extern "C" returntype __stdcall __declspec(dllimport) 
# endif 
#else 
# define MYPROJECTAPI(returntype) extern "C" returntype 
#endif 

y luego su proyecto de Visual C++ causaría BUILDMYPROJECT que definirse en la construcción de MyProject.dll

+0

¿cómo se puede crear un proyecto de C++/CLI con visual studio 2010? –

+0

Archivo -> Nuevo -> Proyecto, luego Visual C++ -> CLR -> Biblioteca de clases –

+0

No se compila. Tengo el siguiente error: error TRK0005: Error al localizar: "CL.exe". –

1
+0

Esto no ayuda con el proceso de escritura de DLL * en absoluto *, que es de lo que se trata la pregunta. –

+0

Ok. Tengo entendido que estaba pidiendo una forma de comunicarse con C/C++ dll desde .NET. La capa P/Invoke funciona. – Adi

+0

La forma en que analizo la pregunta es "¿Cómo hago eso [escribir una DLL que sería interoperable]?" –

4

En pocas palabras:

(1) Crear un nuevo proyecto de biblioteca de C++/CLI.

(2) Escriba su código. Para las clases que necesitan ser accesible desde su proyecto de C#, asegúrese de crearlas como clases CLR:

public ref class R {/*...*/};  // CLR class 
public value class V {/*...*/};  // CLR struct 
public interface class I {/*...*/}; // CLR interface 

(3) Compilar el proyecto y añadir una referencia a él en su proyecto de C#.

+0

¿cómo se puede crear un proyecto de biblioteca C++/CLI con visual studio 2010? –

+0

@tinmaru: no tengo VS 2010 instalado ahora, pero de acuerdo con MSDN (http://msdn.microsoft.com/en-us/library/0fyc0azh.aspx), debe haber una "CLR/Class Library "plantilla de proyecto disponible. – Heinzi

1

A continuación se muestra un ejemplo para una aplicación donde tuve que hacer precisamente eso. En mi caso, necesitaba una DLL para envolver llamadas a funciones que solo estaban disponibles en .lib. La parte clave es extern "C" __declspec (dllexport) en la declaración. Eso es básicamente todo lo que necesitas. El resto simplemente estaba usando dllimport en la aplicación C# y obteniendo la clasificación correcta.

extern "C" __declspec (dllexport) LONG EstablishContext(DWORD dwScope, 
                LPCVOID pvReserved1, 
                LPCVOID pvReserved2, 
                LPSCARDCONTEXT phContext) 
{ 
    return SCardEstablishContext(dwScope, pvReserved1, pvReserved2, phContext); 
} 
+0

No te olvides de '__stdcall' (o de forma equivalente, utiliza la macro' WINAPI'). Esto simplificará considerablemente las declaraciones de p/invoke. –

Cuestiones relacionadas