Jeśli chcesz eksportować zwykłe C, użyj projektu C, a nie C ++. Biblioteki DLL C ++ polegają na manipulowaniu nazwami dla wszystkich isms C ++ (przestrzeni nazw itp.). Możesz skompilować swój kod jako C, przechodząc do ustawień projektu w C / C ++ -> Advanced, jest opcja „Kompiluj jako”, która odpowiada przełącznikom kompilatora / TP i / TC.
Jeśli nadal chcesz używać C ++ do pisania wewnętrznych elementów swojej biblioteki, ale eksportujesz niektóre niezarządzane funkcje do użytku poza C ++, zobacz drugą sekcję poniżej.
Eksportowanie / importowanie bibliotek DLL w VC ++
To, co naprawdę chcesz zrobić, to zdefiniować warunkowe makro w nagłówku, które zostanie uwzględnione we wszystkich plikach źródłowych w projekcie DLL:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Następnie na funkcji, którą chcesz wyeksportować, używasz LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
W projekcie kompilacji biblioteki utwórz definicję, LIBRARY_EXPORTS
która spowoduje wyeksportowanie funkcji do kompilacji biblioteki DLL.
Ponieważ LIBRARY_EXPORTS
nie zostanie zdefiniowany w projekcie korzystającym z biblioteki DLL, gdy ten projekt zawiera plik nagłówkowy biblioteki, zamiast tego zostaną zaimportowane wszystkie funkcje.
Jeśli twoja biblioteka ma być wieloplatformowa, możesz zdefiniować LIBRARY_API jako nic, gdy nie jest w systemie Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Podczas korzystania z dllexport / dllimport nie musisz używać plików DEF, jeśli używasz plików DEF, nie musisz używać dllexport / dllimport. Te dwie metody wykonują to samo zadanie na różne sposoby, uważam, że dllexport / dllimport jest zalecaną metodą spośród dwóch.
Eksportowanie niezarządzanych funkcji z biblioteki C ++ DLL dla LoadLibrary / PInvoke
Jeśli potrzebujesz tego do korzystania z LoadLibrary i GetProcAddress, lub może importując z innego języka (np. PInvoke z .NET lub FFI w Python / R itp.), Możesz użyć extern "C"
wbudowanego portu dllexport, aby poinformować kompilator C ++, aby nie zmieniał nazw. A ponieważ używamy GetProcAddress zamiast dllimport, nie musimy wykonywać tańca ifdef z góry, wystarczy prosty dllexport:
Kod:
#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())
);
}
A oto jak wygląda eksport z 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)
Więc ten kod działa dobrze:
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
usunie dekorację opisującą typy parametrów funkcji, ale nie dekorację opisującą konwencję wywoływania funkcji; b) aby usunąć całą dekorację, należy określić (niezdekorowaną) nazwę w pliku DEF.