Si desea exportaciones simples de C, use un proyecto de C, no C ++. Las DLL de C ++ se basan en la manipulación de nombres para todos los ismos de C ++ (espacios de nombres, etc.). Puede compilar su código como C yendo a la configuración de su proyecto en C / C ++ -> Avanzado, hay una opción "Compilar como" que corresponde a los modificadores del compilador / TP y / TC.
Si aún desea usar C ++ para escribir los componentes internos de su lib pero exportar algunas funciones sin alterar para usarlas fuera de C ++, consulte la segunda sección a continuación.
Exportación / importación de bibliotecas DLL en VC ++
Lo que realmente quiere hacer es definir una macro condicional en un encabezado que se incluirá en todos los archivos fuente en su proyecto DLL:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Luego, en una función que desea exportar, usa LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
En el proyecto de construcción de su biblioteca, cree una definición, LIBRARY_EXPORTS
esto hará que sus funciones se exporten para su construcción DLL.
Dado LIBRARY_EXPORTS
que no se definirá en un proyecto que consume la DLL, cuando ese proyecto incluya el archivo de encabezado de su biblioteca, todas las funciones se importarán en su lugar.
Si su biblioteca va a ser multiplataforma, puede definir LIBRARY_API como nada cuando no está en Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Cuando utilice dllexport / dllimport, no es necesario utilizar archivos DEF, si utiliza archivos DEF, no es necesario utilizar dllexport / dllimport. Los dos métodos realizan la misma tarea de diferentes maneras, creo que dllexport / dllimport es el método recomendado de los dos.
Exportación de funciones no manipuladas desde una DLL de C ++ para LoadLibrary / PInvoke
Si necesita esto para usar LoadLibrary y GetProcAddress, o tal vez para importar desde otro idioma (es decir, PInvoke desde .NET, o FFI en Python / R, etc.) puede usar en extern "C"
línea con su dllexport para decirle al compilador C ++ que no altere los nombres. Y dado que estamos usando GetProcAddress en lugar de dllimport, no necesitamos hacer el baile ifdef desde arriba, solo un simple dllexport:
El código:
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT int getEngineVersion() {
return 1;
}
EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
K.getGraphicsServer().addGraphicsDriver(
auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
);
}
Y así es como se ven las exportaciones con Dumpbin / export:
Dump of file opengl_plugin.dll
File Type: DLL
Section contains the following exports for opengl_plugin.dll
00000000 characteristics
49866068 time date stamp Sun Feb 01 19:54:32 2009
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
2 1 00011028 registerPlugin = @ILT+35(_registerPlugin)
Entonces este código funciona bien:
m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");
m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
::GetProcAddress(m_hDLL, "registerPlugin")
);
extern C
eliminará la decoración que describe los tipos de parámetros de la función, pero no la decoración que describe la convención de llamada de la función; b) para eliminar toda la decoración, debe especificar el nombre (sin decoración) en un archivo DEF.