Se você deseja exportações simples de C, use um projeto C, não C ++. DLLs C ++ contam com a modificação de nomes para todos os isms C ++ (namespaces etc ...). Você pode compilar seu código como C acessando as configurações do projeto em C / C ++ -> Avançado, há uma opção "Compilar como" que corresponde às opções do compilador / TP e / TC.
Se você ainda deseja usar C ++ para escrever o interno de sua biblioteca, mas exportar algumas funções não fragmentadas para uso fora de C ++, consulte a segunda seção abaixo.
Exportando / importando bibliotecas DLL em VC ++
O que você realmente deseja fazer é definir uma macro condicional em um cabeçalho que será incluído em todos os arquivos de origem em seu projeto DLL:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Então, em uma função que você deseja exportar, use LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
Em seu projeto de construção de biblioteca, crie um define que LIBRARY_EXPORTS
fará com que suas funções sejam exportadas para sua construção de DLL.
Desde a LIBRARY_EXPORTS
não será definido em um projeto que consuma a DLL, quando esse projeto incluir o arquivo de cabeçalho de sua biblioteca, todas as funções serão importadas.
Se sua biblioteca deve ser multiplataforma, você pode definir LIBRARY_API como nada quando não estiver no Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Ao usar dllexport / dllimport, você não precisa usar arquivos DEF; se usar arquivos DEF, não precisa usar dllexport / dllimport. Os dois métodos realizam a mesma tarefa de maneiras diferentes, acredito que dllexport / dllimport é o método recomendado dos dois.
Exportar funções não fragmentadas de uma DLL C ++ para LoadLibrary / PInvoke
Se você precisar disso para usar LoadLibrary e GetProcAddress, ou talvez importar de outra linguagem (ou seja, PInvoke de .NET ou FFI em Python / R etc), você pode usar extern "C"
inline com seu dllexport para dizer ao compilador C ++ para não destruir os nomes. E como estamos usando GetProcAddress em vez de dllimport, não precisamos fazer a dança ifdef de cima, apenas um dllexport simples:
O 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())
);
}
E aqui está a aparência das exportações com 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)
Portanto, este código funciona bem:
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
irá remover a decoração que descreve os tipos de parâmetros da função, mas não a decoração que descreve a convenção de chamada da função; b) para remover toda a decoração, você precisa especificar o nome (não decorado) em um arquivo DEF.