windows、macosx 动态 加载 动态库 类封装

目的

为了方便在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;
}

如有错误欢迎指正,感激不尽


所有图片均来自网络


   转载规则


《windows、macosx 动态 加载 动态库 类封装》 Smoking 采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
 上一篇
c++ 实现 事件监听通知中心 c++ 实现 事件监听通知中心
目的监听通知具体实现内容:当一个发送一个通知之后,所有监听这个事件的接口都收到通知执行某个任务这里我使用libuv实现多线程执行任务,可以使用线程池替换实现,也可以使用单线程看具体使用场景 代码#include <map> #incl
2019-06-27
下一篇 
《系统之美》-作者:[美] 德内拉·梅多斯 《系统之美》-作者:[美] 德内拉·梅多斯
这本书是一本系统思维的入门经典,因为概念和科普性很强,所以阅读是有难度的,不过作者加入了大量的案例向我们展示系统之美,让跟着作者的思路走有一种畅快淋漓的感觉。虽然偏社科人文多一些,但是不影响相关思想的理解和运用,想要运用好,就需要对这个世界
2019-06-27
  目录