Jika Anda menginginkan ekspor C biasa, gunakan proyek C, bukan C ++. DLL C ++ mengandalkan pengaturan nama untuk semua isme C ++ (ruang nama, dll ...). Anda dapat mengkompilasi kode Anda sebagai C dengan masuk ke pengaturan proyek Anda di bawah C / C ++ -> Advanced, ada opsi "Compile As" yang sesuai dengan switch compiler / TP dan / TC.
Jika Anda masih ingin menggunakan C ++ untuk menulis internal lib tetapi mengekspor beberapa fungsi yang tidak diubah ukurannya untuk digunakan di luar C ++, lihat bagian kedua di bawah.
Mengekspor / Mengimpor Libs DLL di VC ++
Apa yang benar-benar ingin Anda lakukan adalah menentukan makro bersyarat di header yang akan disertakan di semua file sumber di proyek DLL Anda:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Kemudian pada fungsi yang ingin Anda ekspor Anda gunakan LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
Dalam proyek pembangunan perpustakaan Anda membuat mendefinisikan LIBRARY_EXPORTS
ini akan menyebabkan fungsi Anda akan diekspor untuk membangun DLL Anda.
Karena LIBRARY_EXPORTS
tidak akan ditentukan dalam proyek yang menggunakan DLL, ketika proyek itu menyertakan file header perpustakaan Anda, semua fungsi akan diimpor sebagai gantinya.
Jika perpustakaan Anda akan lintas platform, Anda dapat mendefinisikan LIBRARY_API sebagai tidak ada ketika tidak di Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Saat menggunakan dllexport / dllimport anda tidak perlu menggunakan file DEF, jika menggunakan file DEF anda tidak perlu menggunakan file dllexport / dllimport. Kedua metode menyelesaikan tugas yang sama dengan cara yang berbeda, saya percaya bahwa dllexport / dllimport adalah metode yang disarankan dari keduanya.
Mengekspor fungsi yang tidak diubah dari C ++ DLL untuk LoadLibrary / PInvoke
Jika Anda memerlukan ini untuk menggunakan LoadLibrary dan GetProcAddress, atau mungkin mengimpor dari bahasa lain (misalnya PInvoke dari .NET, atau FFI dengan Python / R dll), Anda dapat menggunakan extern "C"
inline dengan dllexport Anda untuk memberi tahu compiler C ++ agar tidak merusak nama. Dan karena kita menggunakan GetProcAddress daripada dllimport, kita tidak perlu melakukan tarian ifdef dari atas, cukup dllexport sederhana:
Kode:
#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())
);
}
Dan inilah tampilan ekspor dengan Dumpbin / ekspor:
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)
Jadi kode ini berfungsi dengan baik:
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
akan menghapus dekorasi yang menjelaskan jenis parameter fungsi, tetapi bukan dekorasi yang menjelaskan konvensi pemanggilan fungsi; b) untuk menghapus semua dekorasi Anda perlu menentukan nama (tanpa dekorasi) dalam file DEF.