หากคุณต้องการเอ็กซ์พอร์ต C ธรรมดาให้ใช้โปรเจ็กต์ C ไม่ใช่ C ++ C ++ DLL ขึ้นอยู่กับ name-mangling สำหรับ C ++ isms ทั้งหมด (เนมสเปซและอื่น ๆ ... ) คุณสามารถคอมไพล์โค้ดของคุณเป็น C ได้โดยเข้าไปที่การตั้งค่าโปรเจ็กต์ของคุณภายใต้ C / C ++ -> ขั้นสูงมีตัวเลือก "คอมไพล์เป็น" ซึ่งสอดคล้องกับสวิตช์คอมไพเลอร์ / TP และ / TC
หากคุณยังต้องการใช้ C ++ เพื่อเขียนภายในของ lib ของคุณ แต่ส่งออกฟังก์ชันบางอย่างที่ไม่มีการเชื่อมต่อเพื่อใช้ภายนอก C ++ โปรดดูส่วนที่สองด้านล่าง
การส่งออก / นำเข้า DLL Libs ใน VC ++
สิ่งที่คุณต้องการทำจริงๆคือกำหนดมาโครเงื่อนไขในส่วนหัวที่จะรวมอยู่ในไฟล์ต้นฉบับทั้งหมดในโครงการ DLL ของคุณ:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
จากนั้นในฟังก์ชันที่คุณต้องการส่งออกคุณใช้LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
ในโครงการสร้างไลบรารีของคุณให้สร้างการกำหนดLIBRARY_EXPORTS
สิ่งนี้จะทำให้ฟังก์ชันของคุณถูกส่งออกสำหรับบิลด์ DLL ของคุณ
เนื่องจากLIBRARY_EXPORTS
จะไม่ถูกกำหนดไว้ในโปรเจ็กต์ที่ใช้ DLL เมื่อโปรเจ็กต์นั้นรวมไฟล์ส่วนหัวของไลบรารีของคุณฟังก์ชันทั้งหมดจะถูกนำเข้าแทน
หากไลบรารีของคุณเป็นแบบข้ามแพลตฟอร์มคุณสามารถกำหนด LIBRARY_API เป็นอะไรก็ได้เมื่อไม่ได้อยู่บน Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
เมื่อใช้ dllexport / dllimport คุณไม่จำเป็นต้องใช้ไฟล์ DEF หากคุณใช้ไฟล์ DEF คุณไม่จำเป็นต้องใช้ dllexport / dllimport ทั้งสองวิธีนี้ทำงานได้หลายวิธีเหมือนกันฉันเชื่อว่า dllexport / dllimport เป็นวิธีที่แนะนำจากทั้งสองวิธี
การเอ็กซ์พอร์ตฟังก์ชันที่ไม่มีการเชื่อมจาก C ++ DLL สำหรับ LoadLibrary / PInvoke
หากคุณต้องการสิ่งนี้เพื่อใช้ LoadLibrary และ GetProcAddress หรืออาจนำเข้าจากภาษาอื่น (เช่น PInvoke จาก. NET หรือ FFI ใน Python / R เป็นต้น) คุณสามารถใช้extern "C"
อินไลน์กับ dllexport ของคุณเพื่อบอกคอมไพเลอร์ C ++ ไม่ให้ยุ่งเกี่ยวกับชื่อ และเนื่องจากเราใช้ GetProcAddress แทน dllimport เราจึงไม่จำเป็นต้องเต้น ifdef จากด้านบนเพียง dllexport ง่ายๆ:
รหัส:
#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())
);
}
และนี่คือลักษณะของการส่งออกด้วย 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)
ดังนั้นรหัสนี้จึงทำงานได้ดี:
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
จะลบการตกแต่งที่อธิบายประเภทพารามิเตอร์ของฟังก์ชันออก แต่ไม่ใช่การตกแต่งที่อธิบายหลักการเรียกของฟังก์ชัน b) ในการลบการตกแต่งทั้งหมดคุณต้องระบุชื่อ (ไม่ได้ตกแต่ง) ในไฟล์ DEF