目的

为了方便在windows平台或者mac、osx平台上调用动态库,封装一个C++基础模板类,实现动态库加载,函数获取以及直接调用,直接调用时只要传入函数名成和参数即可

因为要兼容windows 和mac 平台我们定义两个宏做编译区分
defined(OS_WIN)
defined(OS_MACOSX)

关键知识点

windows 加载动态库使用到的函数 LoadLibraryExW,GetProcAddress,FreeLibrary
macosx 加载动态库使用到的函数 dlopen,GetProcAddress,dlclose
可变参数模板函数
std::result_of<std::function(Args…)>::type
std::forward(args)…

代码

三个文件shared_library.h shared_library.cc shared_library.mm

头文件

class  SharedLibrary
{
public:
    SharedLibrary();
    ~SharedLibrary();
public:
    //加载动态库dll或者dylib
    bool Load(std::string str_utf8_dllfilepath);
    //获取动态库中的函数指针
    //通过函数模板适应所以函数类型
    template <typename T>
    T* GetFunction(const std::string _funcName)
    {

        T* _funcPtr = nullptr;
#if defined(OS_WIN)
        //windows 中通过GetProcAddress 获取函数地址
        auto _ptr = GetProcAddress((HMODULE)libraryHandle_, _funcName.c_str());
        _funcPtr = (T*)_ptr;
#endif
#if defined(OS_MACOSX)
        //Mac dlsym 获取函数地址
        auto _ptr = (T*)dlsym(libraryHandle_, _funcName.c_str());
        _funcPtr = (T*)_ptr;
        const char *dlsym_error = dlerror();
        if (dlsym_error)
        {
            throw std::runtime_error(dlsym_error);
        }
#endif
        return _funcPtr;
    }
    //主动释放动态库
    void Free();
    //调用动态中的函数
    //这里使用可变参数模板,因为不同函数的参数不一样
    //std::result_of<std::function<T>(Args...)>::type 自动获取函数返回值类型
    template <typename T, typename... Args>
    typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const std::string funcName, Args&&... args)
    {
        //通过函数名称获取函数地址
        auto f = GetFunction<T>(funcName);
        if (f == nullptr)
        {
            std::string s = "can not find this function " + funcName;
        	throw std::runtime_error(s.c_str());
        }
        //使用完美转发,然后运行函数
        return f(std::forward<Args>(args)...);
    }		
private:
    //用于保存动态库加载之后的指针
    void* libraryHandle_;
    
};

windows实现

#include "shared_library.h"
#include <locale>
#include <codecvt>
#include <windows.h>
SharedLibrary::SharedLibrary()
{
    libraryHandle_ = nullptr;
}
SharedLibrary::~SharedLibrary()
{
    Free();
}
bool SharedLibrary::Load(std::string str_utf8_dllfilepath)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    std::wstring strpath = conv.from_bytes(str_utf8_dllfilepath);
    //转换成unicode编码加载路径,避免windows 平台 ascii路径存在的诸多问题
    //windows加载动态库使用LoadLibraryExW
    libraryHandle_ = LoadLibraryExW(strpath.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
    if (libraryHandle_ == nullptr)
    {
        return false;
    }
    return true;
}

void SharedLibrary::Free()
{
    if (libraryHandle_ != nullptr)
    {
        ::FreeLibrary((HMODULE)libraryHandle_);
        libraryHandle_ = nullptr;
    }
}

macosx 实现

#include "shared_library.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
SharedLibrary::SharedLibrary()
{
    libraryHandle_ = nullptr;
}
SharedLibrary::~SharedLibrary()
{
    Free();
}
bool SharedLibrary::Load(std::string str_utf8_dllfilepath)
{
    //macosx 加载dylib使用的方式和linux一样
    libraryHandle_ = dlopen(str_utf8_dllfilepath.c_str(), RTLD_LOCAL|RTLD_LAZY);
    if (!libraryHandle_ )
    {
        printf("error msg:%s",dlerror());
        return false;
    }
    return true;
}

void SharedLibrary::Free()
{
    if (libraryHandle_ != nullptr)
    {
        //macosx 释放dylib使用的方式和linux一样
        dlclose(libraryHandle_);
        libraryHandle_ = nullptr;
    }
}

调用示例

std::string dllfilepath = u8"";
#if defined(OS_WIN)  
    dllfilepath = _dllpath + u8"\\xxx.dll";
#elif defined(OS_MACOSX)  
    dllfilepath = _dllpath + u8"//xxx.dylib";
auto ptr_shared_library_ = new SharedLibrary();
if(ptr_shared_library_->Load(dllfilepath) == false)
{
    return false;
}

//传入函数名称和参数执行函数然后返回结果
auto _ptr = ptr_shared_library_->ExcecuteFunc<char*(int,int)>("func",1111,11111);
if (_ptr == nullptr)
{
    return false;
}
如有错误欢迎指正,感激不尽

所有图片均来自网络

更多推荐