动态链接库的使用有两种方式,一种是在编译的时候就把动态链接库的头文件包含起来,链接的时候,系统自动去查找需要的动态链接库;另一种是程序动态的去加载,windows下是使用LoadLibrary加载库文件,然后通过GetProcAddress获取函数指针;在linux下是使用dlopen加载库文件,然后通过dlsym获取函数指针。但是动态加载的方式,需要在调用的地方定义很多函数指针,使用起来不太方便,而且动态链接库改了接口,使用的地方也需要相应的修改。有没有更好的方法呢?当然有,可以利用可变参数模板来改善动态加载链接库的使用。
windows的实现:
class DllWrapper
{
public:
DllWrapper() : hModule(nullptr)
{}
~DllWrapper()
{
Unload();
}
bool Load(const std::string& dllPath)
{
hModule = LoadLibraryA(dllPath.c_str());
if(!hModule)
{
std::cout << "LoadLibray failed!" << std::endl;
return false;
}
return true;
}
bool Unload()
{
if(hModule == nullptr)
return true;
auto ret = FreeLibrary(hModule);
if(!ret)
return false;
hModule = nullptr;
return true;
}
template<typename T>
std::function<T> GetFunction(const std::string& FunName)
{
auto iterator = mFuncMap.find(FunName);
if(iterator == mFuncMap.end())
{
auto funAddress = GetProcAddressw(hModule, FunName.c_str());
if(!funAddress)
return nullptr;
mFuncMap.insert(std::make_paire(FunName, funAddress));
iterator = mFuncMap.find(FuncName.c_str());
}
return std::function<T>((T*)(iterator->second));
}
template<typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExecuteFun(const std::string& funName, Args&&... args)
{
auto fun = GetFunction<T>(funName);
if(fun == nullptr)
{
std::string error = "cannot find this function: " + funName;
throw std::exception(error.c_str());
}
return f(std::forward<Args>(args)...);
}
private:
HMODULE hModule;
std::map<std::string, FARPROC> mFuncMap;
};
Linux平台下只需要把平台相关的系统函数替换成dlopen,dlsym,dlclose就可以了。
#include<string>
#include<iostream>
#include<map>
#include<functional>
#include<dlfcn.h>
class DllWrapper
{
public:
DllWrapper() : hModule(nullptr)
{}
~DllWrapper()
{
Unload();
}
bool Load(const std::string& dllPath)
{
hModule = dlopen(dllPath.c_str(), RTLD_LAZY);
if(!hModule)
{
std::cout << "LoadLibray failed! error:" << dlerror() << std::endl;
return false;
}
return true;
}
bool Unload()
{
if(hModule == nullptr)
return true;
auto ret = dlclose(hModule);
if(!ret)
return false;
hModule = nullptr;
return true;
}
template<typename T>
std::function<T> GetFunction(const std::string& FunName)
{
auto iterator = mFuncMap.find(FunName);
if(iterator == mFuncMap.end())
{
auto funAddress = dlsym(hModule, FunName.c_str());
if(!funAddress)
return nullptr;
mFuncMap.insert(std::make_pair(FunName, funAddress));
iterator = mFuncMap.find(FunName.c_str());
}
return std::function<T>((T*)(iterator->second));
}
template<typename T, typename... Args>
typename std::result_of<std::function<T>(Args...)>::type ExecuteFun(const std::string& funName, Args&&... args)
{
auto fun = GetFunction<T>(funName);
if(fun == nullptr)
{
std::string error = "cannot find this function: " + funName;
throw std::exception(error.c_str());
}
return f(std::forward<Args>(args)...);
}
private:
void* hModule;
std::map<std::string, void *> mFuncMap;
};