windowsのLoadLibrary、Linux/MacOSのdlopenをラップしたクラスを作成。
最近Mac miniを買ったので、MacOSでのビルドも確認できるようになった。
#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(); }
};
#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; }