.def ファイル C/C++ DLL

__declspec(dllexport) と .def ファイルの両方を一緒に使用すると、移植可能な DLL (つまり、別のコンパイラまたは別のコンパイラ設定でコンパイルされたコードから呼び出すことができる DLL) を作成するのに役立つことがわかりました。

関数宣言に __declspec(dllexport) を配置するだけで、これらの関数が DLL によって (少なくとも Windows では) 「エクスポート」され、DLL の外部から呼び出すことができます。

ただし、エクスポートされたすべての関数をリストする .def ファイルをビルドに追加すると、(たとえば) Microsoft コンパイラがエクスポートされた関数名に先頭のアンダースコアと末尾のパラメーター幅情報を追加するのを防ぐことができます (少なくとも __stdcall と組み合わせた場合)。ポータビリティにも役立ちます)。例えば。関数宣言

void foo(int i);

呼び出し規則と .def ファイルの使用に注意しないと、"[email protected]" としてエクスポートされる可能性があります。

シンボル テーブル内のエクスポートされた関数名をそのような名前装飾から解放しておくことは、実行時に明示的に DLL をロードおよびフックする一環として GetProcAddress() 呼び出しを行う場合に非常に便利です。つまり、実行時に上記の関数 foo() へのポインターを取得するには (エクスポートされていると仮定します)、理想的には次のように呼び出します:

HANDLE dllHandle = LoadLibrary("mydll.dll");
void* fooFcnPtr = GetProcAddress(dllHandle, "foo");

もちろん、いくつかの適切なエラーケースチェック付きです!

DLL をビルドするときに関数宣言で .def ファイルに加えて __stdcall、__declspec(dllexport)、および extern "C" を使用すると、上記のクライアント側コードがさまざまなコンパイラおよびコンパイラ設定で確実に機能します。


私の理解では、.def ファイルは __declspec(dllexport) 構文の代替手段を提供し、エクスポートされた関数の序数を明示的に指定できるという追加の利点があります。これは、一部の関数を序数のみでエクスポートする場合に役立ちます。これにより、関数自体に関する情報があまり明らかになりません (例:OS 内部 DLL のエクスポート関数の多くは序数のみ)。

参照ページを参照してください。

.def ファイル内の名前は、バイナリ内の名前と一致する必要があることに注意してください。そのため、'extern "C" { ... }' で C または C++ を使用する場合、名前はマングルされません。それ以外の場合は、DLL の生成に使用される特定のバージョンのコンパイラに対応する正しいマングル名を使用する必要があります。 __declspec() 関数は、これをすべて自動的に行います。


まだ興味がある人のために... dll と def ファイルにリンクできるようにするには、lib ファイルも必要です。 Windows では、これは「LIB」ツールを使用して定義から作成できます。これを行うコマンド ラインの方法の例については、以下を参照してください。

lib /machine:i386 /def:sqlite3.def

これが他の人に役立つことを願っています。