スポンサーリンク

VC++でdynaloを使用しDLLを動的ロードする

Win32APIではLoadLibraryを使用してdllを動的ロードできるが、クロスプラットフォームのライブラリのdynaloを使用してみる。dynaloはヘッダオンリーなのでその点はよい。

https://github.com/maddouri/dynalo

プラグイン機能を作りたくて探していてdynaloを見つけたのだが、正直以下の理由により個人的意見としては他の手を探したい。今記事のストックが無くて困っているので書いておく。

Windowsで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側

特に何も考えず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;
}

コメントを残す

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

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


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