スポンサーリンク

動的ライブラリをロードする機能をクロスプラットフォームで書いてみた

windowsのLoadLibrary、Linux/MacOSのdlopenをラップしたクラスを作成。

最近Mac miniを買ったので、MacOSでのビルドも確認できるようになった。

ModuleLoader.hpp

#include <functional>
#include <string>


#if defined(_WIN32) || defined(_WIN64)
 
#include <Windows.h>

#elif defined(__APPLE__) && defined(__MACH__)
#include <dlfcn.h>

#elif defined(__linux__)

 
#include <dlfcn.h>

#else
#error "Unknown platform" #endif class ModuleLoader { #if defined(_WIN32) || defined(_WIN64)
    using ModuleType = HMODULE;
    using FuncType = FARPROC;

    ModuleType _ModuleLoad(const char* filename) {
        return LoadLibraryA(filename);
    }
    ModuleType _ModuleLoad(const wchar_t* filename) {
        return LoadLibraryW(filename);
    }
    ModuleType _ModuleLoad(const char16_t* filename) {
        return LoadLibraryW( (const wchar_t*)filename);
    }
    FuncType _GetFunction(const char* filename) {
        return GetProcAddress(_module, filename);
    }
    void _FileErrorCheck() {
        if (_module == nullptr) {
            DWORD dwError = GetLastError();
            LPSTR lpMsgBuf;
            FormatMessageA(
                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dwError,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPSTR)&lpMsgBuf,
                0,
                NULL
            );

            _latest_error = lpMsgBuf;

            // メモリを解放
            LocalFree(lpMsgBuf);

            _load_success = false;
        }
        else {
            _latest_error.clear();
            _load_success = true;
        }
    }

    void _ModuleUnloader() {
        FreeLibrary(_module);
    }

#elif defined(__APPLE__) && defined(__MACH__)
 
    using ModuleType = void*;
    using FuncType = void*;

    ModuleType _ModuleLoad(const char* filename) {
        dlerror();
        return dlopen(filename, RTLD_LAZY);
    }
    void _FileErrorCheck() {
        if (_module == nullptr) {
            const char* error_msg = dlerror();
            if (error_msg) {
                _latest_error = error_msg;
            }
        }
    }

    FuncType _GetFunction(const char* function_name) {
        return dlsym(_module, function_name);
    }
    void _ModuleUnloader() {
        dlclose(_module);
    }

#elif defined(__linux__)

 
    using ModuleType = void*;
    using FuncType = void*;

    ModuleType _ModuleLoad(const char* filename) {
        dlerror();
        return dlopen(filename, RTLD_LAZY);
    }
    void _FileErrorCheck() {
        if (_module == nullptr) {
            const char* error_msg = dlerror();
            if (error_msg) {
                _latest_error = error_msg;
            }
        }
    }

    FuncType _GetFunction(const char* function_name) {
        return dlsym(_module, function_name);
    }
    void _ModuleUnloader() {
        dlclose(_module);
    }

#else
#error "Unknown platform" #endif std::string _latest_error; ModuleType _module = nullptr; bool _load_success = false; public:
    template<typename CharType>
    ModuleLoader(const CharType* module_name) {
        _latest_error.clear();
        _module = _ModuleLoad(module_name);
        _FileErrorCheck();
    }

    template<typename Function>
    Function* GetFunction(const char* function_name) {
        auto func = _GetFunction(function_name);

        if(func == nullptr) {
            _latest_error = "Function \"" + std::string(function_name) + "\" is not found";
            return nullptr;
        }

        return reinterpret_cast<Function*>(func);
    }

    const std::string& GetErrorMessage() const {
        return _latest_error;
    }
    bool IsLoadSuccess() const {
        return _load_success;
    }
    ~ModuleLoader() {
        _ModuleUnloader();
    }
};

a.cpp

#include <iostream>

#include "ModuleLoader.hpp"

int main() {
    //ModuleLoader loader("MyDLL.dll");
    ModuleLoader loader("mylib.so");

    if (loader.IsLoadSuccess() == false) {
        std::cout << loader.GetErrorMessage() << std::endl;

        std::function<int(int, int)> add_func = loader.GetFunction<int(int, int)>("add");

        if (add_func == nullptr) {
            std::cout << loader.GetErrorMessage() << std::endl;
        }
        else {
            int result = add_func(3, 5);
            std::cout << "result::: " << result << std::endl;
        }
    }
    return 0;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: