web-dev-qa-db-ja.com

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

DLLで.defファイルを使用する意味がわかりません。

DLLコード(つまり、明示的な__declspec(dllexport))内で明示的なエクスポートを使用する必要性を置き換えるようですが、これらを使用しないと、リンカーを作成するlibファイルを生成できません後でDLLを使用するときに問題が発生します。

では、クライアントアプリケーションとリンクするときに.defをどのように使用しますか?ヘッダーまたは.libファイルを使用する必要性を置き換えますか?

22
cweston

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

リファレンスページ を参照してください。

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

20
Nick

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

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

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

void foo(int i);

呼び出し規約と.defファイルの使用法に注意しないと、「_ foo @ 4」としてエクスポートされる可能性があります。

シンボルテーブル内のエクスポートされた関数名をそのような名前の装飾なしに保つことは、実行時に明示的にDLL)をロードおよびフックする一部としてGetProcAddress()呼び出しを行うときに、非常に便利です。実行時に上記の関数foo()へのポインター(それがエクスポートされたと仮定)、理想的には単に呼び出したいだけです:

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

もちろん、いくつかの適切なエラーケースチェックがあります!

DLL)をビルドするときに、関数宣言で.defファイルと__stdcall、__ declspec(dllexport)、およびextern "C"を使用すると、上記のクライアント側コードが広範囲で機能することが保証されます。コンパイラとコンパイラ設定の。

24
Duncan Fletcher

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

lib /machine:i386 /def:sqlite3.def

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

10
cweston

.DEFファイルは16ビットウィンドウでより一般的であり、通常、エクスポートするシンボルを指定する唯一の方法でした。

さらに、名前ではなく序数(@ 1、@ 2など)でエクスポートを指定する手段を提供しました。シンボルを検索するこの方法は、ビデオドライバーなど、パフォーマンスが非常に重要な場合に使用されました。

4
Ferruccio

DLLはあまり使用していませんが、エクスポートされたC++関数の場合は「__declspec(dllexport)」を使用し、エクスポートされたC関数の場合は.defファイルを作成する必要があることを理解しています。これはおそらく、C++関数がオーバーロードをサポートしているが、C関数はサポートしていないためです。

3
Hosam Aly

私の理解では、.defファイルは実際にどのすべてのAPIをエクスポートする必要があるかを指定していません。エクスポートされたAPIとその序数が含まれているだけです。特定のAPIを実際にエクスポートする場合は、APIの定義で__declspec(dllexport)を指定し、宣言で__declspec(dllimport)を指定する必要があります。

Defファイルの利点は、すでに実現されているdllとのバックワードの互換性を維持するのに役立つことです。つまり、APIの序数を維持します。 dllに新しいAPIを追加すると、リンカーは.defファイルを調べて、古いapiの序数がそのままになるようにnewapiの序数を生成するとします。

したがって、クライアントコードが最新のdllを使用している場合、既存のAPIを壊すことはありません。

3
chappar