winapi visual-c++ dll name-decoration

winapi - Exportación de funciones desde una DLL con dllexport



visual-c++ name-decoration (4)

Me gustaría un ejemplo simple de exportar una función desde una DLL de Windows C ++.

Me gustaría ver el encabezado, el archivo cpp y el archivo def (si es absolutamente necesario).

Me gustaría que el nombre exportado no esté decorado . Me gustaría utilizar la convención de llamadas más estándar (__stdcall?). Me gustaría utilizar __declspec (dllexport) y no tener que usar un archivo DEF.

Por ejemplo:

//header extern "C" { __declspec(dllexport) int __stdcall foo(long bar); } //cpp int __stdcall foo(long bar) { return 0; }

Estoy tratando de evitar que el enlazador agregue guiones bajos y / o números (¿conteo de bytes?) Al nombre.

Estoy de acuerdo con no admitir dllimport y dllexport usando el mismo encabezado. No quiero información sobre la exportación de métodos de clase C ++, solo funciones globales de estilo c.

ACTUALIZAR

Al no incluir la convención de llamadas (y usar extern "C") me da los nombres de las exportaciones como me gusta, pero ¿qué significa eso? Es cualquiera que sea la convención de llamadas predeterminada que obtengo, ¿qué pinvoke (.NET), declare (vb6) y GetProcAddress esperarían? (Supongo que para GetProcAddress dependerá del puntero de función que creó el llamador).

Quiero que esta DLL se use sin un archivo de encabezado, así que realmente no necesito muchas de las #defines para hacer que la persona que llama pueda utilizar el encabezado.

Estoy de acuerdo con una respuesta que es que tengo que usar un archivo DEF.


Creo que _naked podría obtener lo que quieres, pero también evita que el compilador genere el código de administración de la pila para la función. Extern "C" causa la decoración del nombre de estilo C. Quítate eso y eso debería deshacerte de tu _''s. El vinculador no agrega los guiones bajos, el compilador sí. stdcall hace que se anexe el tamaño de la pila del argumento.

Para obtener más información, consulte: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

La pregunta más importante es por qué quieres hacer eso? ¿Qué pasa con los nombres destrozados?


Si desea exportar C simple, use un proyecto C no C ++. Las DLL de C ++ se basan en la creació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 al compilador conmuta / TP y / TC.

Exportación / importación de DLL Libs 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, utiliza LIBRARY_API :

LIBRARY_API int GetCoolInteger();

En el proyecto de compilación de su biblioteca, cree una definición LIBRARY_EXPORTS esto hará que sus funciones se exporten para su compilación de DLL.

Como LIBRARY_EXPORTS no se definirá en un proyecto que consuma la DLL, cuando ese proyecto incluya el archivo de encabezado de la biblioteca, todas las funciones se importarán.

Si su biblioteca debe 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

Al usar dllexport / dllimport no necesita usar archivos DEF, si usa archivos DEF no necesita usar dllexport / dllimport. Los dos métodos realizan la misma tarea de diferentes maneras, creo que dllexport / dllimport es el método recomendado entre los dos.

Exportación de funciones no registradas desde una DLL C ++ para LoadLibrary / PInvoke

Si necesita esto para usar LoadLibrary y GetProcAddress, o tal vez hacer PInvoke desde .NET, puede usar extern "C" línea con su dllexport. Y como usamos GetProcAddress en lugar de dllimport, no necesitamos hacer el baile ifdef desde arriba, solo un dllexport simple:

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 / exports:

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") );


Tenía exactamente el mismo problema, mi solución era usar el archivo de definición de módulo (.def) en lugar de __declspec(dllexport) para definir las exportaciones ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). No tengo idea de por qué esto funciona, pero lo hace


Para C ++:

Acabo de enfrentar el mismo problema y creo que vale la pena mencionar que surge un problema cuando uno usa ambos __stdcall (o WINAPI ) y extern "C" :

Como sabes, la extern "C" elimina la decoración de modo que en lugar de:

__declspec(dllexport) int Test(void) --> dumpbin : ?Test@@YaHXZ

obtienes un nombre de símbolo sin decorar:

extern "C" __declspec(dllexport) int Test(void) --> dumpbin : Test

Sin embargo, _stdcall (= macro WINAPI, que cambia la convención de llamadas) también decora los nombres de modo que si usamos ambos obtenemos:

extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0

y el beneficio de la extern "C" se pierde porque el símbolo está decorado (con _ @ bytes)

Tenga en cuenta que esto solo ocurre para la arquitectura x86 porque la convención __stdcall se ignora en x64 ( msdn : en arquitecturas x64, por convención, los argumentos se pasan en registros cuando es posible, y los argumentos subsiguientes se pasan en la pila ).

Esto es particularmente complicado si se dirige a plataformas x86 y x64.

Dos soluciones

  1. Use un archivo de definición. Pero esto te obliga a mantener el estado del archivo def.

  2. la forma más simple: definir la macro (ver msdn ):

#define comentario de EXPORT (linker, "/ EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)

y luego incluir el siguiente pragma en el cuerpo de la función:

#pragma EXPORT

Ejemplo completo:

int WINAPI Test(void) { #pragma EXPORT return 1; }

Esto exportará la función sin decorar tanto para objetivos x86 como x64 conservando la convención __stdcall para x86. El __declspec(dllexport) no es necesario en este caso.