1

これは多くの場所で部分的に議論されていますが、それでも私にはうまくいきません.

Delphi ソースからコンパイルされた dll があります。これは、1 つの関数を 2 つの名前でエクスポートし、次を使用して dll を検査します。

>> dumpbin /EXPORTS MyLibrary.dll

次の出力が得られます。

...
17    3 00070A88 MyFunction
...
46   24 00070A88 _MyFunction@48
...

そこで、次の内容で MyLibrary.def というファイルを作成しました。

EXPORTS
MyFunction
_MyFunction@48

そして、を使用してインポートライブラリを生成しました

>> lib /def:MyLibrary.def /OUT:MyLibrary.lib /MACHINE:x86

dumpbin を使用して新しい lib ファイルを調べると、次のように表示されます。

...
_MyFunction
...
__MyFunction@48
...

そのため、どういうわけか、lib アプリケーションは関数名の前にアンダースコアを 1 つ追加しました。(どうして?)

次に、この関数を C++ プログラムで使用して、Microsoft Visual Studio C++ 2010 Express (lib ファイルを使用) でコンパイルします。

// MyLibrary.h
# define DllImport(Type) __declspec (dllimport) Type __stdcall

extern "C" DllImport(void)MyFunction(...);
// main.cpp
#import "MyLibrary.h"

...
MyFunction(....);
...

私が知る限り、これは機能するはずですが、次のリンカーエラーが発生します。

... error LNK2001: Unresolved external sympol "__imp__MyFunction@48".

なぜこれがうまくいかないのかわかりません(全体がどのように機能するのか本当にわかりません...)が、さらに2つのことを試しました。

  1. MyLibrary.h と main.h の関数の名前を MyFunction から _MyFunction に変更しました
    • 結果:うまくいきました!しかし、なぜ?何かが明らかに間違っているので、私はこれに頼りたくありません。  
  2. 関数の名前を MyFunction に戻し、def-File のアンダースコアを削除し、lib ファイルを再度生成してコンパイルを試みました
    • 結果: コンパイルは成功しますが、プログラムを開始すると、

MyApp - Entry Point Not Found
---------------------------
The procedure entry point MyFunction@48 could not be located
in the dynamic link library MyLibrary.dll. 

lib ツールとリンカーの内部動作をより深く理解する必要があると思いますが、これに関する情報はこれまでのところ見つかりませんでした。

4

1 に答える 1

4

KB131313libでは、このユーティリティを使用する際に直面する問題について説明しています。

.DEF ファイルを使用して、ソース コードまたはオブジェクト モジュールを持たない .DLL からインポート ライブラリを作成できるのは、.DLL が C インターフェイス経由で関数をエクスポートする場合のみです。具体的には、関数は C 呼び出し規則を使用するように宣言されている必要があります。

関数名からわかるように、関数は cdecl ではなく stdcall を使用します@。それにもかかわらず、KB記事では代わりに何をすべきかを説明しています:

  1. C++ の場合と同じように関数を宣言しますが、 importではなくexport 用です。

    ほとんどの場合、すでにそれを行っています。呼び出し規約の権利はありますが@48、最後の は、48 バイト分のパラメーターが必要であることを意味します。関数は、そのデータがスタックにプッシュされることを期待し、それが返される前に、関数はそれだけ多くポップします。宣言でのの使用は...それと互換性がありません。

    特定の引数リストが実際にどうあるべきかわからない場合は、先に進んで 12 個intのパラメーターを定義するだけで、少なくともスタック構造は正しくなります。(しかし、リストが実際にどうあるべきかわからない場合は、いずれにせよ運命にかなり近づいています。)

  2. C++ でダミーの実装を作成します。

    実装は空にすることができます。唯一の要件は、コードがコンパイルおよびリンクされることです。

  3. そのダミー コードから独自のバージョンのMyLibrary.dllをコンパイルします。

    元の DLL と互換性があることを確認してください。これを実行dumpbinして、元の DLL で見た関数名のバージョンが少なくとも 1 つエクスポートされることを確認します。(両方は必要ありません。プログラムは名前の 1 つだけを使用します。dumpbin出力が示すように、両方の名前はバイナリ内の同じ場所に移動するため、プログラムが最終的にどちらの名前を使用するかは問題ではありません。 .)

  4. DLL を破棄し、LIB ファイルのみを保持します。

  5. lib ファイルを使用して、実際の DLL とリンクします。

それでもリンカが を見つけられないと文句を言う場合は、宣言から__imp_MyFunction@48その部分を削除します。dllimportこれにより、プレフィックスが削除され__imp_、名前が Delphi の名前に似たものになります。


他のすべてが失敗した場合は、ロード時間の代わりに実行時の動的リンクを使用できます。関数のポインター型を宣言し、and を使用LoadLibraryGetProcAddressてアクセスします。

于 2012-08-29T13:07:35.937 に答える