salida - DLL no administrados en C++
errores en dev c++ (4)
Lista de verificación para exportar funciones:
- ¿La convención de llamadas es adecuada para la persona que llama? (esto determina cómo se pasan los parámetros y los resultados, y quién es responsable de limpiar la pila). Debe indicar su convención de llamadas explícitamente.
- ¿Bajo qué nombre se exportará el símbolo? C ++ generalmente necesita decorar ("mangle") los nombres de los símbolos, por ejemplo, para distinguir entre diferentes sobrecargas.
- Dile al vinculador que haga que la función sea visible como DLL Export
En MSVC:
-
__stdcall
(que es la convención de llamadas__stdcall
) es la convención de llamadas típica para los símbolos exportados, con el respaldo de la mayoría de los clientes, supongo. - Extern "C" le permite exportar el símbolo estilo C sin nombre mangling
- utilice
__declspec(dllexport)
para marcar un símbolo para exportar, o enlace un archivo .def separado donde se enumeran los símbolos que se exportarán. Con un archivo .def también puede exportar por ordinal solamente (no por nombre), y cambiar el nombre del símbolo que se exporta.
He estado leyendo muchos tutoriales / artículos sobre DLL no administradas en C ++. Por mi vida, sin embargo, no puedo entender el concepto. Me confunde fácilmente el aparente desacuerdo sobre si necesita un archivo de cabecera, cómo exportarlo, si necesito un archivo .lib y qué es lo que tiene.
Entonces, supongamos que solo tengo una función como esta:
public int calculateSquare(int num)
{
return num*num;
}
Ignorando el código real, ¿qué necesito para hacer esta simple función, por sí misma, en una DLL a la que puedo llamar? ¿Acabo de agregar __dllexport o lo que sea a la primera línea o necesito un encabezado? Estoy perplejo por todo esto.
Necesita exportar la función usando __declspec( dllexport )
o agregando la función a un archivo de definición de módulo (.def). Luego compile el proyecto como una DLL.
En el lado del cliente, tienes dos opciones. Utilice una biblioteca de importación (.lib) que se genera al compilar la DLL. Simplemente vincular con su proyecto de cliente con esta biblioteca le dará acceso a las funciones exportadas desde la DLL. Y necesita un archivo de encabezado, porque el compilador necesita saber la firma de su función, que devuelve int y toma un int. Para recapitular, debe vincular con una biblioteca de importación (.lib) y un archivo de encabezado que contiene el encabezado de su función.
Otra forma es cargar la DLL dinámicamente usando la llamada de WinAPI
LoadLibrary
y luego GetProcAddress
para obtener un puntero a la función. El puntero a la función debe tener el tipo correcto, de modo que el compilador pueda darle los parámetros correctos y se use la convención de llamada correcta.
No puedo enfatizar esto lo suficiente, el compilador de C ++ no ve los archivos de encabezado, después de que el preprocesador haya terminado, solo hay un gran archivo fuente (también llamado unidad de compilación). Así que, estrictamente, no necesita un encabezado para exportar esta función desde un dll. Lo que necesita es alguna forma de compilación condicional para exportar la función en el dll que está compilando e importarla en el código del cliente.
Por lo general, esto se hace con una combinación de macros y archivos de encabezado. Usted crea una macro llamada MYIMPORTEXPORT y mediante el uso de declaraciones condicionales macro puede hacer que funcione como __declspec (dllexport) en el dll, y __declspec (dllimport) en el código del cliente.
en el archivo MYIMPORTEXPORT.h
#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif
en el archivo MyHeader.h
#include <MyImportExport.h>
MYIMPORTEXPORT public int calculateSquare(int num)
{
return num*num;
}
en el archivo dll .cpp
#define SOME_CONDITION
#include <MyHeader.h>
en el archivo .cpp de código de cliente
#include <MyHeader.h>
Por supuesto, también debe indicarle al vinculador que está creando un dll con la opción / DLL .
El proceso de compilación también creará un archivo .lib, se trata de una lib estática, llamada el apéndice en este caso, que el código del cliente debe vincular como si estuviera enlazando a una lib propia estática. Automáticamente, el dll se cargará cuando se ejecute el código del cliente. Por supuesto, el sistema operativo necesita encontrar el dll a través de su mecanismo de búsqueda, lo que significa que no puede colocar el dll en ningún lugar, sino en una ubicación específica. Aquí hay más sobre eso.
Una herramienta muy práctica para ver si exportó la función correcta de la dll, y si el código del cliente está importando correctamente es dumpbin . Ejecútelo con / EXPORTS y / IMPORTS respectivamente.
La respuesta de QBziZ es correcta. Ver archivos DLL no administrados en C ++
Para completarlo: en C ++, si necesita usar un símbolo, debe decirle al compilador que existe, y con frecuencia, su prototipo .
En otros idiomas, el compilador simplemente explorará la biblioteca por sí mismo y encontrará el símbolo, et voilà .
En C ++, debe decirle al compilador.
Ver un encabezado C / C ++ como una tabla de contenido de libros
La mejor manera es colocar en algún lugar común el código necesario. La "interfaz", si quieres. Esto generalmente se hace en un archivo de encabezado, llamado encabezado porque generalmente no es un archivo fuente independiente. El encabezado es solo un archivo cuyo objetivo es ser incluido (es decir, copiar / pegar por el preprocesador) en verdaderos archivos de origen.
En esencia, parece que tienes que declarar dos veces un símbolo (función, clase, lo que sea). Lo cual es casi una herejía en comparación con otros idiomas.
Debería verlo como un libro, con una tabla de resumen o un índice. En la tabla, tienes todos los capítulos. En el texto, tienes los capítulos y su contenido.
Y a veces, simplemente estás feliz de que tengas la lista de capítulos.
En C ++, este es el encabezado.
¿Qué pasa con la DLL?
Entonces, de vuelta al problema DLL: el objetivo de una DLL es exportar símbolos que usará su código.
Entonces, de una manera C ++, ambos deben exportar el código en compilación (es decir, en Windows, use __declspec, por ejemplo) y "publicar" una tabla de lo que se exporta (es decir, tienen encabezados "públicos" que contienen las declaraciones exportadas) .