[Windows] 64bit dllからのexport

コミュニティウェブサイトstackoverflow上で 64bit dllを作成するときのトピックスが上がっていた。
A warning with building 64bit dll
http://stackoverflow.com/questions/3572344/a-warning-with-building-64bit-dll
元のポストは
ソースコード中で

extern "C"
void _declspec(dllexport) __stdcall foo();</blockquote>

とexport宣言し、
なおかつ、
.defファイルにも

EXPORTS
foo @1

と書いたら以下のエラーが出るのでどうしたらいいでしょう、という質問。

warning LNK4197: export 'foo' specified multiple times; using first specification

2通りの方法でexportしているので重複があるという警告が出ている、というのが答えだ。
回答をみると知らなかったことが多い。
64bitコンパイラは修飾名の作り方が32bitと異なる(アンダースコアがない)。
これがwarningの直接の原因だ。32bitでは、fooに対してコンパイラは_fooという名前をexportするが、64bitの場合は、コンパイラもfooという名前をexportしているのでdefファイルと重複する。
2つ目の回答が詳しくて以下のソースコードがあるとき、

#ifdef EXPORT
#undef EXPORT
#endif
#ifdef PROJECTNAMEHERE_EXPORTS
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXTERN_C EXPORT void __stdcall Function1(void);
EXTERN_C EXPORT void __cdecl Function2(...);
EXPORT void Function3(void);

(PROJECT_EXPORTSがdefineされるかどうかのifdefはDevStudioがdllのときに定義するマクロらしい。dllではdefineされるので最初のEXPORTマクロが使われる。)
(原文)

Functions 1 & 2 can be gotten with GetProcAddress as _Function1@0 and Function2 respectively. Function3 is going to be exported via a compiler specific mangled name that will look something like: @Function3@@UAG_DB@Z. This name is different for each overload of the function, which is how it allows overloading to work.

要約すると、

stdcallはFunction1@0の形、cdeclはFunction2の形でGetProcAddress関数から呼び出せる。Function3の宣言だとコンパイラによりmangleされた名前、(たとえば @Function3@@UAG_DB@Z のような)がexportされる。これはoverloadされる関数ごとに違う名前になる。これによってoverloadingできるようになっている。

ということ。
defファイルだとコンパイル結果と連携せずに、書いたとおりにexportすることに注意が必要、とのこと。

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