8

私は、C++ のアンマネージ DLL に関する多くのチュートリアル/記事を読んできました。しかし、私の人生では、その概念を理解できないようです。ヘッダファイルが必要かどうか、それをエクスポートする方法、.lib ファイルが必要かどうか、そして何が必要かについて意見の相違があるように見えるので、私は簡単に混乱します。

したがって、次のような関数があると仮定しましょう。

public int calculateSquare(int num)
{
    return num*num;
}

実際のコードは無視して、この単純な関数をそれ自体で呼び出すことができる DLL にするために必要なものは何ですか? 最初の行に __dllexport などを追加するだけですか、それともヘッダーが必要ですか? 私はこれらすべてに困惑しています。

4

4 に答える 4

15

私はこれを十分に強調することはできません。C++ コンパイラはヘッダー ファイルを認識しません。プリプロセッサが完了すると、1 つの大きなソース ファイル (コンパイル ユニットとも呼ばれます) しかありません。したがって、厳密には、この関数を dll からエクスポートするためのヘッダーは必要ありません。必要なのは、コンパイルしている dll の関数をエクスポートし、クライアント コードにインポートするための条件付きコンパイルの形式です。

通常、これはマクロとヘッダー ファイルの組み合わせで行われます。MYIMPORTEXPORT というマクロを作成し、マクロ条件ステートメントを使用して、dll の __declspec ( dllexport ) やクライアント コードの __declspec ( dllimport ) のように機能させます。

ファイル MYIMPORTEXPORT.h 内

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif

ファイル MyHeader.h 内

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

dll .cpp ファイル内

#define SOME_CONDITION

#include <MyHeader.h>

クライアント コード .cpp ファイル内

#include <MyHeader.h>

もちろん、/DLL オプションを使用して dll をビルドしていることをリンカーに通知する必要もあります。

ビルド プロセスでは .lib ファイルも作成されます。これは静的ライブラリ (この場合はスタブと呼ばれます) であり、実際の静的ライブラリにリンクしているかのようにクライアント コードがリンクする必要があります。クライアント コードが実行されると、自動的に dll が読み込まれます。もちろん、dll はそのルックアップ メカニズムを通じて OS によって検出される必要があります。つまり、dll を特定の場所に配置することはできません。詳細はこちらです。

dll から正しい関数をエクスポートしたかどうか、およびクライアント コードが正しくインポートしているかどうかを確認するための非常に便利なツールはdumpbinです。/EXPORTS と /IMPORTS をそれぞれ指定して実行します。

于 2008-10-25T07:27:17.857 に答える
6

QBziZ の答えで十分です。C++ のアンマネージ DLL を参照してください。

それを完了するには: C++ では、シンボルを使用する必要がある場合、コンパイラにその存在を伝え、多くの場合、そのプロトタイプを伝える必要があります

の言語では、コンパイラはライブラリを独自に探索し、シンボルを見つけるだけです。

C++ では、コンパイラに通知する必要があります。

C/C++ ヘッダーを本の目次として見る

最善の方法は、必要なコードを共通の場所に配置することです。必要に応じて「インターフェース」。これは通常、header と呼ばれるヘッダー ファイルで行われます。これは、通常、独立したソース ファイルではないためです。ヘッダーは、真のソース ファイルにインクルード (つまり、プリプロセッサによってコピー/貼り付け) されることを目的としたファイルにすぎません。

実際には、シンボル (関数、クラスなど) を 2 回宣言する必要があるようです。他の言語と比較すると、これはほとんど異端です。

要約表または索引を備えた本として表示する必要があります。表には、すべての章があります。テキストには、章とその内容があります。

また、チャプター リストがあるだけで満足する場合もあります。

C++ では、これはヘッダーです。

DLLはどうですか?

DLL の問題に戻りましょう。DLL の目的は、コードが使用するシンボルをエクスポートすることです。

したがって、C++ の方法では、コンパイル時にコードをエクスポートする (つまり、Windows では、たとえば __declspec を使用する) 必要があり、エクスポートされるもののテーブルを "公開" する必要があります (つまり、エクスポートされた宣言を含む "パブリック" ヘッダーを用意します)。 .

于 2008-10-25T08:55:56.383 に答える
1

関数をエクスポートするためのチェックリスト:

  • 呼び出し規約は呼び出し元に適していますか? (これにより、パラメーターと結果がどのように渡されるか、およびスタックのクリーンアップの責任者が決まります)。呼び出し規約を明示的に述べる必要があります。
  • シンボルはどの名前でエクスポートされますか? C++ は通常、たとえば異なるオーバーロードを区別するために、シンボルの名前をデコレート (「マングル」) する必要があります。
  • 関数を DLL エクスポートとして表示するようにリンカーに指示します。

MSVC の場合:

  • __stdcall(パスカル呼び出し規約) は、エクスポートされたシンボルの典型的な呼び出し規約です。ほとんどのクライアントでサポートされていると思います。
  • extern "C" を使用すると、名前を変更せずに C スタイルのシンボルをエクスポートできます
  • エクスポートするシンボルをマークするために使用__declspec(dllexport)するか、エクスポートするシンボルがリストされている別の .def ファイルをリンクします。.def ファイルを使用すると、(名前ではなく) 序数のみでエクスポートし、エクスポートするシンボルの名前を変更することもできます。
于 2008-10-25T09:42:19.600 に答える
0

__declspec( dllexport )関数をモジュール定義ファイル (.def) に追加するか、関数を使用してエクスポートする必要があります。次に、プロジェクトを DLL としてコンパイルします。

クライアント側には、2 つのオプションがあります。DLL のコンパイル時に生成されるインポート ライブラリ (.lib) を使用します。このライブラリを使用してクライアント プロジェクトにリンクするだけで、DLL からエクスポートされた関数にアクセスできます。また、コンパイラは関数のシグネチャを知る必要があるため、ヘッダー ファイルが必要です。関数は int を返し、int を受け取ります。要約すると、インポート ライブラリ (.lib) と、関数のヘッダーを含むヘッダー ファイルをリンクする必要があります。

もう 1 つの方法は、WinAPIcallLoadLibraryを使用して DLL を動的にロードGetProcAddressし、関数へのポインターを取得することです。関数へのポインターは、正しい型を持っている必要があります。これにより、コンパイラーは関数に正しいパラメーターを与え、正しい呼び出し規約が使用されます。

于 2008-10-25T07:29:40.223 に答える