Se vuoi semplici esportazioni in C, usa un progetto C non C ++. Le DLL C ++ si basano sulla modifica dei nomi per tutti gli ismi C ++ (spazi dei nomi, ecc ...). Puoi compilare il tuo codice come C andando nelle impostazioni del tuo progetto in C / C ++ -> Avanzate, c'è un'opzione "Compila come" che corrisponde alle opzioni del compilatore / TP e / TC.
Se vuoi ancora usare C ++ per scrivere gli interni della tua libreria ma esportare alcune funzioni non modificate per l'uso al di fuori di C ++, vedi la seconda sezione di seguito.
Esportazione / importazione di librerie DLL in VC ++
Quello che vuoi veramente fare è definire una macro condizionale in un'intestazione che sarà inclusa in tutti i file sorgente nel tuo progetto DLL:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Quindi su una funzione che vuoi esportare usi LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
Nel progetto di compilazione della libreria, crea una definizione, LIBRARY_EXPORTS
questo farà sì che le tue funzioni vengano esportate per la build della tua DLL.
Poiché LIBRARY_EXPORTS
non verrà definito in un progetto che utilizza la DLL, quando quel progetto include il file di intestazione della libreria verranno invece importate tutte le funzioni.
Se la tua libreria deve essere multipiattaforma puoi definire LIBRARY_API come nulla quando non su Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Quando si utilizza dllexport / dllimport non è necessario utilizzare file DEF, se si utilizzano file DEF non è necessario utilizzare dllexport / dllimport. I due metodi eseguono la stessa attività in modi diversi, credo che dllexport / dllimport sia il metodo consigliato tra i due.
Esportazione di funzioni non modificate da una DLL C ++ per LoadLibrary / PInvoke
Se hai bisogno di questo per usare LoadLibrary e GetProcAddress, o magari importare da un altro linguaggio (cioè PInvoke da .NET, o FFI in Python / R ecc.) Puoi usare extern "C"
inline con il tuo dllexport per dire al compilatore C ++ di non alterare i nomi. E poiché stiamo usando GetProcAddress invece di dllimport non abbiamo bisogno di eseguire la danza ifdef dall'alto, solo un semplice dllexport:
Il codice:
#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())
);
}
Ed ecco come appaiono le esportazioni 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)
Quindi questo codice funziona bene:
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
rimuoverà la decorazione che descrive i tipi di parametro della funzione, ma non la decorazione che descrive la convenzione di chiamata della funzione; b) per rimuovere tutte le decorazioni è necessario specificare il nome (non decorato) in un file DEF.