windows - tag files and folders
Una advertencia con la construcción de 64 bits dll (2)
En general, no es una buena práctica especificar exportaciones dos veces para la misma función. Si ya tiene __declspec(dllexport)
entonces no necesita especificar la exportación en un archivo .def también. Por el contrario, si tiene la exportación enumerada en un archivo .def, entonces no hay necesidad de un __declspec(dllexport)
.
Creo que el motivo de la advertencia es que en compilaciones x86, __declspec(dllexport)
está exportando el nombre decorado con un guión bajo __declspec(dllexport)
, pero el compilador de 64 bits no decora los nombres con un guión bajo inicial, lo que lleva al duplicado. Para verificar esto, podría ver la DLL de 32 bits en Dependency Walker y debería ver dos funciones exportadas, "foo" y "_foo".
dll exportar encabezado
extern "C"
void _declspec(dllexport) __stdcall foo();
archivo .def
EXPORTS
foo @1
Cuando construyo el dll mediante la configuración de compilación de 64 bits, cumplo con esta advertencia.
advertencia LNK4197: exportar ''foo'' especificado varias veces; usando la primera especificación
Pero si construyo el dll mediante la configuración de compilación de 32 bits, la advertencia nunca ocurre.
¿Cuál es el problema? Cuál es la diferencia.
En el encabezado dll para la interfaz, generalmente usamos esta técnica,
#ifdef EXPORT_DLL
#define BASICAPI _declspec(dllexport)
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
Pero si también existe un archivo def, siempre cumpliremos con la advertencia cuando construyamos un dll de 64 bits.
Entonces, ¿deberíamos escribir los códigos de esta manera?
#ifdef EXPORT_DLL
#define BASICAPI
#else
#define BASICAPI _declspec(dllimport)
#endif //_EXPORT_DLL
Funciona bien. Pero no es familiar para mí.
Dame tus opiniones
__declspec(dllexport)
y archivos .def son dos formas diferentes de exportar símbolos desde un dll. No necesita ambos y debería omitirlos. El método __declspec
es mucho más versátil para los programas de c ++ ya que exporta nombres con c ++ Mangling, lo que permite exportar funciones sobrecargadas, pero a la inversa hace que los nombres sean más difíciles de importar a través de GetProcAddress.
Además, usar una macro genérica como EXPORT_DLL
es peligroso, ya que significa que no se puede construir un dll, que usa otro dll, sin que el archivo dll intente exportar todos los símbolos de ambos dlls.
DevStudio crea automáticamente un símbolo en los proyectos dll: <PROJECT>_EXPORTS
lo que hace que crear una macro EXPORT sea fácil y seguro:
#ifdef EXPORT
#undef EXPORT
#endif
#ifdef PROJECTNAMEHERE_EXPORTS
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXTERN_C EXPORT void __stdcall Function1(void);
EXTERN_C EXPORT void __cdecl Function2(...);
EXPORT void Function3(void);
Las funciones 1 y 2 se pueden obtener con GetProcAddress como _Function1@0
y Function2
respectivamente. La función 3 se exportará a través de un nombre destrozado específico del compilador que se verá algo así como: @Function3@@UAG_DB@Z
Este nombre es diferente para cada sobrecarga de la función, que es cómo permite que funcione la sobrecarga.
Es importante saber el nombre que __declspec
de __declspec
como archivos .def no importa y solo exportaría Function1
, Function2
y Function3
.