Pregunta

Me gustaría un ejemplo sencillo de exportar una función de una DLL de C ++ ventanas.

Me gustaría ver el encabezado, el archivo CPP, y el archivo de definición (si es absolutamente necesario).

Me gustaría que el nombre sea exportado a sin decorar . Me gustaría utilizar la convención de llamada estándar de la mayoría (__stdcall?). Me gustaría que el uso __ declspec (dllexport) y no tener que utilizar 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 el enlazador añadió guiones y / o números de cuentas de bytes (?) Al nombre.

estoy bien con no apoyar dllimport y dllexport usando la misma cabecera. No quiero ninguna información sobre la exportación de métodos de clase C ++, simplemente c-estilo funciones globales.

Actualizar

No incluye la convención de llamada (y usando extern "C") me da los nombres de exportación como me gusta, pero ¿qué significa eso? Es lo predeterminado convención de llamada que estoy recibiendo lo PInvoke (NET), declarar (VB6) y GetProcAddress esperaría? (Supongo que para GetProcAddress que dependerá de la función de la persona que llama puntero creado).

Quiero que este archivo DLL para ser utilizado sin un archivo de cabecera, así que realmente no necesita el un montón de las #defines de lujo para hacer la cabecera utilizable por una persona que llama.

estoy bien con una respuesta es que tengo que usar un archivo DEF.

¿Fue útil?

Solución

Si desea exportaciones C normal, utilice un proyecto C no C ++. C ++ DLL se basan en el nombre-mangling para todos los ismos ++ C (espacios de nombres, etc ...). Puede compilar el código de C por parte de entrar en la configuración del proyecto en virtud de C / C ++ -> Avanzado, hay una opción "Compilar Como", que cooresponds a los modificadores del compilador / TP y / TC

.

exportación / importación de DLL Liberaciones en VC ++

Lo que realmente quiere hacer es definir una macro condicional en un encabezado que se incluye en todos los archivos de código fuente en su proyecto DLL:

#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif

A continuación, en una función que desea exportar utiliza LIBRARY_API:

LIBRARY_API int GetCoolInteger();

En su proyecto de construcción de la biblioteca crear un LIBRARY_EXPORTS definir esto hará que sus funciones a ser exportados para su construcción DLL.

Desde LIBRARY_EXPORTS no se definirá en un proyecto que consume el DLL, cuando ese proyecto incluye el archivo de cabecera de la biblioteca de todas las funciones serán importados en su lugar.

Si la biblioteca es ser multiplataforma puede definir como LIBRARY_API nada cuando no 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 se utiliza dllexport / dllimport que no es necesario utilizar archivos DEF, si utiliza archivos DEF que no es necesario utilizar dllexport / dllimport. Los dos métodos de realizar la misma tarea de diferentes maneras, creo que dllexport / dllimport es el método recomendado de los dos.

Exportación de funciones unmangled de un C ++ DLL para LoadLibrary / PInvoke

Si necesita esto para usar LoadLibrary y GetProcAddress, o tal vez haciendo PInvoke de .NET se puede utilizar en línea con su extern "C" dllexport. Y ya que estamos utilizando en lugar de GetProcAddress dllimport que no es necesario hacer la danza ifdef desde arriba, sólo 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 aquí es lo que las exportaciones se ven como con dumpbin / exportación:

  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)

Así que 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")
);

Otros consejos

Para C ++:

Yo sólo se enfrentó al mismo problema y creo que vale la pena mencionar el problema se produce cuando se utilizan tanto __stdcall (o WINAPI) y extern "C":

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

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

a obtener un nombre de símbolo sin decorar:

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

Sin embargo, el _stdcall (= WINAPI macro, que cambia la convención de llamada) también decora nombres de modo que si utilizamos tanto obtenemos:

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

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

  

Tenga en cuenta que este solamente se produce para la arquitectura x86, porque   la convención __stdcall se ignora en x64 ( MSDN : en x64 arquitecturas, por convención, los argumentos se pasan en registros cuando sea posible, y los argumentos posteriores se pasan en la pila .).

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


dos soluciones

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

  2. la forma más sencilla: definir la macro (ver MSDN ):

  

comentario #define exportación (enlazador, "/ exportación:" __FUNCTION__ "="   __FUNCDNAME __)

y luego incluir la 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 para ambos objetivos x86 y x64 preservando al mismo tiempo la convención __stdcall para x86. El __declspec(dllexport) no es es necesario en este caso.

Yo tenía exactamente el mismo problema, mi solución era utilizar 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

Creo _naked podría conseguir lo que quieres, sino que también evita que el compilador genera el código de gestión de la pila para la función. extern "C" hace que la decoración nombre de estilo C. Quite eso y que debe deshacerse de sus _ del. El enlazador no añade los guiones, el compilador hace. stdcall hace que el tamaño de la pila argumento para ser anexada.

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

La gran pregunta es ¿por qué quieres hacer eso? ¿Qué hay de malo en los nombres alterados?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top