Pregunta

Estoy escribiendo una DLL C/C++ y quiero exportar ciertas funciones que hice antes usando un archivo .def como este

LIBRARY "MyLib"
EXPORTS
  Foo
  Bar

con el código definido así, por ejemplo:

int Foo(int a);
void Bar(int foo);

Sin embargo, ¿qué pasa si quiero declarar un método sobrecargado de Foo() como:

int Foo(int a, int b);

Como el archivo def solo tiene el nombre de la función y no el prototipo completo, no veo cómo manejaría las funciones sobrecargadas.¿Utiliza simplemente una entrada y luego especifica qué versión sobrecargada desea al pasar el puntero de función con el prototipo adecuado a LoadLibrary()?

Editar:Para ser claros, esto es en Windows usando Visual Studio 2005.

Editar:Marqué el método no def (__declspec) como respuesta... Sé que esto en realidad no resuelve el problema usando archivos def como quería, pero parece que probablemente no haya una solución (oficial) usando archivos def.Sin embargo, dejaremos la pregunta abierta, en caso de que alguien sepa algo, no tenemos funciones y archivos def sobrecargados.

¿Fue útil?

Solución

En el código mismo, marque las funciones que desea exportar usando __declspec(dllexport).Por ejemplo:

#define DllExport __declspec(dllexport)

int DllExport  Foo( int a ) {
  // implementation
}
int DllExport Foo( int a, int b ) {
  // implementation
}

Si hace esto, no necesita enumerar las funciones en el archivo .def.

Alternativamente, es posible que pueda utilizar un valor de parámetro predeterminado, como:

int Foo( int a, int b = -1 )

Esto supone que existe un valor para b que puede utilizar para indicar que no se utiliza.Si -1 es un valor legal para b, o si no hay o no debería haber un valor predeterminado, esto no funcionará.

Editar (Adam Haile):Se corrigió para usar __declspec ya que __dllspec no era correcto para poder marcar esto como la respuesta oficial... estaba lo suficientemente cerca.

Editar (Graeme):Vaya, ¡gracias por corregir mi error tipográfico!

Otros consejos

La sobrecarga de funciones es una característica de C++ que se basa en la manipulación de nombres (los nombres de funciones crípticos en los mensajes de error del vinculador).

Al escribir los nombres alterados en el archivo def, puedo vincular y ejecutar mi proyecto de prueba:

LIBRARY "TestDLL"
EXPORTS
    ?Foo@@YAXH@Z
    ?Foo@@YAXHH@Z

parece funcionar para

void Foo( int x );
void Foo( int x, int y );

Así que copie los nombres de las funciones de C++ del mensaje de error y escríbalos en su archivo def.Sin embargo, la verdadera pregunta es:¿Por qué desea utilizar un archivo def y no utilizar __declspec(dllexport)?

Los nombres destrozados no son portátiles, los probé con VC++ 2008.

Tuve un problema similar, así que quería publicar sobre esto también.

  1. Usualmente usando

    extern "C" __declspec(dllexport) void Foo();
    

    exportar el nombre de una función está bien.Va a generalmente Exportar el nombre sin resultar sin la necesidad de un archivo .def.Sin embargo, hay algunas excepciones como funciones __stdcall y nombres de funciones sobrecargadas.

  2. Si declara una función para usar la convención __stdcall (como se hace para muchas funciones de API) entonces

    extern "C" __declspec(dllexport) void __stdcall Foo();
    

    Exportará un nombre destrozado como _foo@4.En este caso, es posible que deba mapear explícitamente el nombre exportado a un nombre destrozado interno.

A.Cómo exportar un nombre destrozado.En un archivo .def agregue

----
EXPORTS
    ; Explicit exports can go here

    Foo
-----

Esto intentará encontrar la "mejor coincidencia" para una función interna Foo y exportarla.En el caso anterior, donde solo hay un foo, esto creará el mapeo

Foo = _Foo@4

como se puede ver a través de dumpbin /EXPORTS

Si ha sobrecargado un nombre de función, es posible que deba decir explícitamente qué función desea en el archivo .def especificando un nombre destrozado usando la sintaxis EntryName [= internalName].p.ej.

----
EXPORTS
    ; Explicit exports can go here

    Foo=_Foo@4
-----

B.Una alternativa a los archivos .def es que puede exportar nombres "en su lugar" usando #pragma.

#pragma comment(linker, "/export:Foo=_Foo@4")

C.Una tercera alternativa es declarar sólo una versión de Foo como "C" externa para exportarla sin modificar.Ver aquí para detalles.

No existe una forma oficial de hacer lo que desea, porque la interfaz dll es una API de C.

El compilador en sí usa nombres alterados como solución alternativa, por lo que debes usar la alteración de nombres cuando no quieras cambiar demasiado en tu código.

No existe una forma independiente del idioma o la versión de exportar una función sobrecargada, ya que la convención de manipulación puede cambiar con cada versión del compilador.

Ésta es una de las razones por las que la mayoría de las funciones de WinXX tienen nombres divertidos como *Ex o *2.

La definición de Systax para EXPORTACIONES es:

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

nombre de entrada es el nombre de la función o variable que desea exportar.Esto es requerido.Si el nombre que exporta es diferente del nombre en la DLL, especifique el nombre de la exportación en la DLL con nombre interno.

Por ejemplo, si su DLL exporta una función, func1() y desea que se use como func2(), deberá especificar:

EXPORTS
func2=func1

Simplemente vea los nombres destrozados (usando Dependency Walker) y especifique el nombre de su propia función.

Fuente: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

Editar:Esto funciona para DLL dinámicas, donde necesitamos usar GetProcAddress() para recuperar explícitamente funciones en DLL.

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