Düz C dışa aktarımı istiyorsanız, C ++ değil bir C projesi kullanın. C ++ DLL'ler, tüm C ++ isms (ad alanları vb.) İçin adların karıştırılmasına dayanır. C / C ++ -> Advanced altındaki proje ayarlarınıza giderek kodunuzu C olarak derleyebilirsiniz, derleyici anahtarları / TP ve / TC'ye karşılık gelen bir "Compile As" seçeneği vardır.
Hala kütüphanenizin iç kısımlarını yazmak için C ++ kullanmak, ancak bazı işlevleri yönetilmeyen C ++ dışında kullanmak istiyorsanız, aşağıdaki ikinci bölüme bakın.
VC ++ 'da DLL Kitaplıklarını Dışa / İçe Aktarma
Gerçekten yapmak istediğiniz şey, DLL projenizdeki tüm kaynak dosyalara dahil edilecek bir başlıkta koşullu bir makro tanımlamaktır:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Ardından dışa aktarılmasını istediğiniz bir işlevde kullanırsınız LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
Kitaplık oluşturma projenizde bir tanım oluşturun, LIBRARY_EXPORTS
bu, işlevlerinizin DLL yapınız için dışa aktarılmasına neden olacaktır.
Yana LIBRARY_EXPORTS
bu proje fonksiyonları yerine ithal edilecek tüm kitaplığınızın başlık dosyası içerir DLL tüketen bir proje, tanımlanan edilmeyecektir.
Kitaplığınız çapraz platform olacaksa, LIBRARY_API'yi Windows'ta değilken hiçbir şey olarak tanımlayabilirsiniz:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Dllexport / dllimport kullanırken DEF dosyalarını kullanmanıza gerek yoktur, eğer DEF dosyalarını kullanırsanız dllexport / dllimport kullanmanıza gerek yoktur. İki yöntem aynı görevi farklı şekillerde yerine getirir, dllexport / dllimport'un ikisinden önerilen yöntem olduğuna inanıyorum.
LoadLibrary / PInvoke için bir C ++ DLL dosyasından yönetilmeyen işlevleri dışa aktarma
LoadLibrary ve GetProcAddress'i kullanmak için buna ihtiyacınız varsa veya belki başka bir dilden (örn. .NET'ten PInvoke veya Python / R'de FFI vb.) İçe aktarmaya ihtiyacınız varsa extern "C"
, C ++ derleyicisine adları karıştırmamasını söylemek için dllexport'unuzla satır içi kullanabilirsiniz . Ve dllimport yerine GetProcAddress kullandığımız için, yukarıdan ifdef dansını yapmamıza gerek yok, sadece basit bir 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())
);
}
Ve işte Dumpbin / dışa aktarımla ihracatın nasıl göründüğü:
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)
Yani bu kod iyi çalışıyor:
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
işlevin parametre türlerini tanımlayan dekorasyonu kaldıracak, ancak işlevin çağırma kuralını tanımlayan dekorasyonu kaldırmayacaktır; b) tüm dekorasyonu kaldırmak için bir DEF dosyasında (bezemesiz) adı belirtmeniz gerekir.