如何从共享库中调用函数?
-
22-09-2019 - |
题
从共享库 / DLL调用函数的最简单,最安全的方法是什么?我最有兴趣在Linux上这样做,但是如果有一种独立于平台的方式,那会更好。
有人可以提供示例代码以显示如何进行以下工作,用户编译了自己的版本 foo
进入共享库?
// function prototype, implementation loaded at runtime:
std::string foo(const std::string);
int main(int argc, char** argv) {
LoadLibrary(argv[1]); // loads library implementing foo
std::cout << "Result: " << foo("test");
return 0;
}
顺便说一句,我知道如何编译共享lib(foo.so
),我只需要知道一种在运行时加载它的简便方法。
解决方案
笔记: 您正在围绕库呼叫传递C ++对象(在这种情况下为STL字符串)。有 没有标准C ++ 阿比 在这个级别, ,因此要么尝试避免将C ++对象传递到周围,要么确保您的库和程序都使用相同的编译器构建(理想情况下是同一机器上的相同编译器,以避免任何与配置有关的惊喜。)
不要忘记 声明您的导出方法 extern "C"
在您的库代码中。
上面说过,这里是 一些代码实施您要实现的目标:
typedef std::string (*foo_t)(const std::string);
foo_t foo = NULL;
...
# ifdef _WIN32
HMODULE hDLL = ::LoadLibrary(szMyLib);
if (!hDll) { /*error*/ }
foo = (foo_t)::GetProcAddress(hDLL, "foo");
# else
void *pLib = ::dlopen(szMyLib, RTLD_LAZY);
if (!pLib) { /*error*/ }
foo = (foo_t)::dlsym(pLib, "foo");
# endif
if (!foo) { /*error*/ }
...
foo("bar");
...
# ifdef _WIN32
::FreeLibrary(hDLL);
# else
::dlclose(pLib);
# endif
你可以 进一步摘要:
#ifdef _WIN32
#include <windows.h>
typedef HANDLE my_lib_t;
#else
#include <dlfcn.h>
typedef void* my_lib_t;
#endif
my_lib_t MyLoadLib(const char* szMyLib) {
# ifdef _WIN32
return ::LoadLibraryA(szMyLib);
# else //_WIN32
return ::dlopen(szMyLib, RTLD_LAZY);
# endif //_WIN32
}
void MyUnloadLib(my_lib_t hMyLib) {
# ifdef _WIN32
return ::FreeLibrary(hMyLib);
# else //_WIN32
return ::dlclose(hMyLib);
# endif //_WIN32
}
void* MyLoadProc(my_lib_t hMyLib, const char* szMyProc) {
# ifdef _WIN32
return ::GetProcAddress(hMyLib, szMyProc);
# else //_WIN32
return ::dlsym(hMyLib, szMyProc);
# endif //_WIN32
}
typedef std::string (*foo_t)(const std::string);
typedef int (*bar_t)(int);
my_lib_t hMyLib = NULL;
foo_t foo = NULL;
bar_t bar = NULL;
...
if (!(hMyLib = ::MyLoadLib(szMyLib)) { /*error*/ }
if (!(foo = (foo_t)::MyLoadProc(hMyLib, "foo")) { /*error*/ }
if (!(bar = (bar_t)::MyLoadProc(hMyLib, "bar")) { /*error*/ }
...
foo("bar");
bar(7);
...
::MyUnloadLib(hMyLib);
其他提示
载荷 是用于加载DLL的Windows功能。您可以检查是否存在符号 getProcaddress. 。在Linux/Unix上您想要 dlopen/dlsym. 。为了在跨平台中执行此操作,您可以编写一个函数,该函数使用预处理器调用这些方法中的任何一种,因此,类似:
int loadlibrary(char* library)
{
#ifdef _WIN32
/* do windows code */
#endif
#ifdef _LINUX
/* do linux code */
#endif
}
这是实现此类事情的一种方法。您也可以通过在您自己的源树中包含不同的标头来实现特定平台实现功能。这可能是一种更好的方法。无论哪种情况,这个想法都是从基础API中抽象。
在Linux上您需要使用 dlsym. 。请参阅页面末尾的示例。在窗口上: getProcaddress.
不隶属于 StackOverflow