Nếu bạn muốn xuất C thuần túy, hãy sử dụng dự án C không phải C ++. C ++ DLL dựa vào việc phân bổ tên cho tất cả các isms C ++ (không gian tên, v.v ...). Bạn có thể biên dịch mã của mình dưới dạng C bằng cách vào cài đặt dự án của bạn trong C / C ++ -> Nâng cao, có một tùy chọn "Biên dịch dưới dạng" tương ứng với các công tắc trình biên dịch / TP và / TC.
Nếu bạn vẫn muốn sử dụng C ++ để viết nội dung bên trong lib của mình nhưng xuất một số hàm không bị nhầm lẫn để sử dụng bên ngoài C ++, hãy xem phần thứ hai bên dưới.
Xuất / Nhập DLL Libs trong VC ++
Điều bạn thực sự muốn làm là xác định macro có điều kiện trong tiêu đề sẽ được bao gồm trong tất cả các tệp nguồn trong dự án DLL của bạn:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
Sau đó, trên một hàm mà bạn muốn xuất, bạn sử dụng LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
Trong dự án xây dựng thư viện của bạn, hãy tạo một xác định LIBRARY_EXPORTS
điều này sẽ khiến các chức năng của bạn được xuất cho bản dựng DLL của bạn.
Từ LIBRARY_EXPORTS
sẽ không được xác định trong một dự án sử dụng DLL, khi dự án đó bao gồm tệp tiêu đề của thư viện của bạn, tất cả các chức năng sẽ được nhập thay thế.
Nếu thư viện của bạn là đa nền tảng, bạn có thể xác định LIBRARY_API là không có gì khi không có trên Windows:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
Khi sử dụng dllexport / dllimport bạn không cần sử dụng tệp DEF, nếu sử dụng tệp DEF bạn không cần sử dụng dllexport / dllimport. Hai phương pháp hoàn thành cùng một nhiệm vụ theo những cách khác nhau, tôi tin rằng dllexport / dllimport là phương pháp được đề xuất trong số hai phương pháp.
Xuất các hàm không bị nhầm lẫn từ C ++ DLL cho LoadLibrary / PInvoke
Nếu bạn cần điều này để sử dụng LoadLibrary và GetProcAddress hoặc có thể nhập từ một ngôn ngữ khác (tức là PInvoke từ .NET hoặc FFI trong Python / R, v.v.), bạn có thể sử dụng extern "C"
nội tuyến với dllexport của mình để yêu cầu trình biên dịch C ++ không làm sai tên. Và vì chúng tôi đang sử dụng GetProcAddress thay vì dllimport, chúng tôi không cần thực hiện điệu nhảy ifdef từ trên xuống, chỉ cần một dllexport đơn giản:
Mật mã:
#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())
);
}
Và đây là những gì xuất khẩu trông như thế nào với 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)
Vì vậy, mã này hoạt động tốt:
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
sẽ loại bỏ trang trí mô tả các loại tham số của hàm, nhưng không xóa trang trí mô tả quy ước gọi của hàm; b) để loại bỏ tất cả trang trí, bạn cần chỉ định tên (không trang trí) trong tệp DEF.