人生初心者の雑記

すべてにおいてド素人な人がいろんなことを書くよ

DLLの作り方

暗黙リンク

fa11enprince.hatenablog.com

DLLは、vc++のプロジェクトのプロパティで設定できるライブラリディレクトリからは探されないので、DLLを使う実行ファイルのあるディレクトリにおくか、PATHを通さないといけない
https://msdn.microsoft.com/ja-jp/library/7d83bc18.aspx

暗黙リンクは、ビルド時に関数の中身のない.libファイルを実行ファイルに組み込み、実行時に.libに書いてある関数をDLLから探すという方法でDLLを使う。だから実行ファイルは使う関数のヘッダをインクルードしないといけないので、実行時に色んなDLLをとっかえひっかえ呼ぶということはできない(例えばDAWプラグインDLLは暗黙リンクではない)

明示リンク

作り方は暗黙リンクと一緒で、DLLを使う側で書くことは下の記事にかいてあるように、
プラグイン・プログラミング(2)



GetProcAddress()で装飾名で関数を指定するので、
明示リンクは装飾名がわからないといけない。装飾名の調べ方を今から書く

エクスポートした関数の修飾名の取得 VC++

DLLファイルをつくったプロジェクトファイルでプロジェクト->プロパティ->リンカー->デバッグ->マップファイルの作成(Yes)
にする

出来たmapファイルの最後のほうに

Exports

ordinal name

1 ?.....
2 ?.....


って感じで修飾名がかいてる。例えば、MyParser という名前空間の boost::variant parse_impl(std::string& ) という関数をエクスポートしたとき、nameはこんな感じになった

?parse_impl@MyParser@@YA?AV?$variant@NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$recursive_wrapper@U?$binary_operator@$0A@@MyParser@@@boost@@V?$recursive_wrapper@U?$binary_operator@$00@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$01@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$02@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$03@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$04@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$05@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$06@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$07@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$08@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$09@MyParser@@@4@V?$recursive_wrapper@U?$binary_operator@$0L@@MyParser@@@4@V?$recursive_wrapper@Ufunction@MyParser@@@4@V?$recursive_wrapper@Uarrow@MyParser@@@4@V?$recursive_wrapper@Utuple@MyParser@@@4@Uvariable@MyParser@@Uvoid_@0detail@4@Uvoid_@0detail@4@@boost@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z (class boost::variant,class std::allocator >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper >,class boost::recursive_wrapper,class boost::recursive_wrapper,class boost::recursive_wrapper,struct MyParser::variable,struct boost::detail::variant::void_,struct boost::detail::variant::void_> __cdecl MyParser::parse_impl(class std::basic_string,class std::allocator > const &))

赤い部分が修飾名。boost使った関数だからめっちゃ長いけど、ふつうはこんな長くならんだろ
後半の括弧にかこまれているのは実際の型の名前。

だからDLLを使う側でGetProcAddress(ハンドル,?parse_impl@MyParser@@...(くっそ長い文字列))
ってかいても、一応通るがめんどい。修飾名を短くしたい。

修飾名を短くするにはDEFファイルってのをつかって自分で設定する

プロジェクトに右クリックで新規ファイルを追加
検索窓に
def
っていれると
Module Definition File
って出るから加える

こんな風に書きました。

LIBRARY "DLLTest"

EXPORTS
parse_impl @1

これでビルドすると、mapファイルがちょっと変わって

...
?parse_impl@MyParser@@...(くっそ長い文字列)
exported name: parse_impl

って感じになる。

参考
ぼやきごと/2013-08-27/VC++:C++名前空間内の関数をDLLエクスポートして使う - ルーチェ's Homepage

この記事では呼び出し規約を_stdcallにしてるけど、特に変えなくてもできた。


正常に起動できませんでした
DLLのパスが通ってない
DLLを呼ぶプログラムと DLLのプログラムのランタイムライブラリの種類が違う
MTD,MT,MTD DLLなど