カンテラの光の下で

dNaga392's memorandom

【QLibrary】DLL内の関数を呼び出す

今回は関数の定義されたDLLの作成と、DLLの関数の呼び出しについて。

QtライブラリのDLL読み込みクラスは、QLibraryとQPluginLoaderがありますが、
今回は QLibrary を使用して読み込みます。

やりたいことはだいたい以下の感じ。

// アプリケーションと同じフォルダに SharedLib.dll があると仮定する。
QLibrary myLib("SharedLib"); // 読み込み

// 関数シンボルの定義。定義のフォーマットは以下のとおり。
//   typedef 戻り値の型 (*定義型)( 入力値の型1, 入力値の型2, ... );
// 今回、読み込む関数は int addNumber( int, int ) なので次のようになる。
typedef int (*MyPrototype)(int,int);

// 関数シンボルのアドレスを取得する(失敗の場合は0)。
MyPrototype myFunction = (MyPrototype) myLib.resolve("addNumbers");

// 呼び出し関数を実行。
int result = myFunction(3,2);
qDebug() << result; // "5"

// アンロード。loadを呼び出してない場合、resolveでloadされているため。
myLib.unload();

実際には、これにアドレスの取得失敗した場合の処理が追加されることになります。

参考というかほぼ以下のページのコピペなんで、リンク先を見て実行すればおおよそ理解できると思います。

Call Symbol From Shared Object File (DLL) with QLibrary

ただし、当該記事は2つ注意することがあります(というか自分がハマったことです)。

まず、main.cpp の20行目で 結果値に 2 が加算されています。 そのため、デバック出力では 7 が表示されます。

次に、記事のソースでは main.cpp の最後のreturnが QCoreApplication クラスの実行になっているため、コンソールから実行した場合、アプリを終了する手立てがありません(厳密にはCtrl+Cなどいくつか方法がありますが)。
そこで、コンソールから実行する場合は、最後のreturn 文を return 0; としておくとよいです。

この他、覚えておきたいこととして1点。

ライブラリのソースを見ると、Q_DECL_EXPORT は Win 環境の場合、__declspec(dllexport) が定義されています。 そのため、 Sharedlib.cpp の __declspec(dllexport) は Q_DECL_EXPORT で置換しても問題なさそうです。

c++ - Delayed DLL load in QT - Stack Overflow

あとは量も多くないので、ドキュメントを一読することをオススメします(呼び出す関数は extern "C" とすること。などが記載されてます)。

以上