[Windows] DLLの関数export記述をx86,x64で統一する

MSDNのDLLの基本説明は以下の記事にある。
Developing DLLs
http://msdn.microsoft.com/ja-jp/library/bb687850(en-us).aspx

DLLを作成する場合にexportされる関数の記述方法が3通りある。

  1. DEFファイルのEXPORTSキーワードに続けて関数を並べ、DLLプロジェクトはこのDEFファイルを参照。
  2.  __declspec(dllexport)宣言を関数定義に書く。
  3.  #pragma でlinkerにオプションを指定する。

手元のソースコードで

#pragma comment(linker, "/EXPORT:FillListbox=_FillListbox@4")

というやり方でx86アーキテクチャ用に動いていた。この記述方法はWiXのチュートリアルに紹介されていたCustomAction用DLLの作り方にあったものだ。
これを64bit用にリコンパイルすると、LINK2001 (symbol undefined* シンボルが未定義です)となってリンクできなくなった。
今のやり方の#pragmaの使用方法ではx86アーキテクチャでしか使えないらしいので、MSDNで紹介されている方法に変更する。

#if _MSC_VER > 1200 // Later than Visual Studio 6.0
#define EXPORT comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
#else // Cannot use this way of exporting functions.
#define EXPORT
#endif // else need to use DEF file or __declspec(dllexport)

と定義する。このEXPORTを#pragmaのlinkerへの指示として関数の先頭に記述する。

double WINAPI my_Cpp_export(double x)
{
#pragma EXPORT
     // Modify x and return it.
     return x * 2.0;
}

関数の内容は掲載ページにあったもので手元のものではない。これでx64でもリンクできるようになった。
MSDNの説明によると、コンパイラに、/EP, /P (プリプロセッサへの指令オプション)があるとこの方法は使えない。
MSDNを検索してみるとdllのexport関連のポストや記事はかなり多い。やはり、生半可な理解でたまたま動いているだけのソースコードが状況が少し変わったことで動かなくなったりする例は多いらしい。

以下では、関数名の修飾に関しての説明がコメントにある。
DLLからのexport関数
http://social.msdn.microsoft.com/Forums/ja-JP/vcgeneralja/thread/e6f937db-e496-461a-b206-29ddab40af93/

そもそもなぜ修飾名が必要かというと、同じ関数名で引数の違うものを区別するため。これができないとC++のoverloadingができないからだ。
Description of C++ name decoration
http://support.microsoft.com/kb/126845/en-us

この修飾はいろいろな変化があるらしく以下のエントリでは長い例が挙げられている。
64 Bit Dll export function problem
http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c4218e3d-0dd0-4cfd-a92a-08c18d5840f2

C#で書かれたmanagedなDLL関数の場合だと思うのだが、decorated name(修飾された名前)が
‘?testFunction@@YAHXZ’.
のようになるのでそれをdumpbinで確認して使う、という。正しい対応ではない気がするが、これでも動けばいい、と割り切って使うのだろう。
32bit版を64bit版にリコンパイルしたときに発生するリンクエラーについて(自分と同じ間違い)は以下の記事。
Re-compile a 32 bit Visual C++ dll to be 64 bit – error LNK2001
http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/2db3bcf5-7d8a-46d4-a30d-54ec4b472b33

ここに書かれているように64bitでは修飾名が32bitの場合とは違う、ということも今回調べて知った。
本にもなったThe Old new thingのblogでもChenが何度かこの話を書いている。
Why can’t I GetProcAddress a function I dllexport’ed?
http://blogs.msdn.com/b/oldnewthing/archive/2004/01/12/57833.aspx
If undecorated names are given in the DLL export table, why does link /dump /exports show me decorated names?
http://blogs.msdn.com/b/oldnewthing/archive/2011/05/13/10164020.aspx

広告
%d人のブロガーが「いいね」をつけました。