Win32APIではLoadLibraryを使用してdllを動的ロードできるが、クロスプラットフォームのライブラリのdynaloを使用してみる。dynaloはヘッダオンリーなのでその点はよい。
https://github.com/maddouri/dynalo
プラグイン機能を作りたくて探していてdynaloを見つけたのだが、正直以下の理由により個人的意見としては他の手を探したい。今記事のストックが無くて困っているので書いておく。
Windowsでは内部でWin32APIのLoadLibraryを使用しているが、実はLoadLibraryはマクロで、実体はLoadLibraryW,LoadLibraryAのいずれかであり、これはUNICODEマクロで切り替えられている。
プロジェクトをUNICODEでビルドすると、LoadLibraryWが有効化されるが、dynaloのコンストラクタがstd::stringをとるため、型の違いで以下のエラーが出る。
dynalo-master\include\dynalo\detail\windows\dynalo.hpp(36,24): error C2665: 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string': オーバーロードされた関数ですべての引数の型を変換できませんでした dynalo-master\include\dynalo\detail\windows\dynalo.hpp(66,35): error C2664: 'HMODULE LoadLibraryW(LPCWSTR)': 引数 1 を 'const _Elem *' から 'LPCWSTR' へ変換できません。 dynalo-master\include\dynalo\detail\windows\dynalo.hpp(66,35): error C2664: with dynalo-master\include\dynalo\detail\windows\dynalo.hpp(66,35): error C2664: [ dynalo-master\include\dynalo\detail\windows\dynalo.hpp(66,35): error C2664: _Elem=char dynalo-master\include\dynalo\detail\windows\dynalo.hpp(66,35): error C2664: ]
要は中でWindows.hを読んでいるということなので、マルチバイトでビルドすればいけるが、ライブラリを使用するために文字セットの設定を変えるのは避けたい。とりあえず動作確認だけなら以下のようにUNICODEマクロを無効化すればいい。しかしほかのWin32APIの使用箇所との不整合が起こる気がする。
結論:プロジェクトがUNICODEなら他のライブラリを使うべき
// WindowsでUnicodeでビルドすると、UNICODEマクロが定義されるので、 // LoadLibrary関数がLoadLibraryWになる。そのため、UNICODEマクロをundefする。 #undef UNICODE #include "dynalo.hpp" #define UNICODE
特に何も考えずDLLを作成
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
extern "C" { __declspec(dllexport) int add(int a, int b) { return a + b; }
}
get_functionで関数を取得できる。
#include <iostream> #include <functional> // マルチバイト文字セットでビルドすること #include "dynalo.hpp" int main() { try { // DLLのロード dynalo::library mydll("MyDLL.dll"); // 関数の取得 std::function<int(int,int)> add_func = mydll.get_function<int(int, int)>("add"); // 関数を実行 int result = add_func(3, 5); std::cout << "result = " << result << std::endl; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }