質問

私の C/C++ 開発のほとんどにはモノリシック モジュール ファイルが含まれており、クラスはまったく含まれていないため、通常、 DLL アクセス可能な機能がある場合は、標準を使用してエクスポートするだけです __declspec(dllexport) 指令。次に、次の方法で動的にアクセスします。 LoadLibrary() またはコンパイル時にヘッダーと lib ファイルを使用します。

クラス全体 (およびそのすべてのパブリック メソッドとプロパティ) をエクスポートしたい場合、どうすればよいでしょうか?

実行時にそのクラスを動的にロードすることは可能ですか?可能であれば、どのようにすればよいですか?

コンパイル時のリンクのためにヘッダーとライブラリを使用するにはどうすればよいでしょうか?

役に立ちましたか?

解決

遅延バインディングについてはどうですか?LoadLibrary()およびgetProcAddress()でロードするように?私は実行時にライブラリをロードできることを使用していますが、ここでそれを行うことができれば素晴らしいことです。

したがって、DLL をロードするには 2 つの方法があります。1 つ目は、DLL から 1 つ以上のシンボル (クラス名など) を参照し、適切なインポート .LIB を指定して、リンカーにすべてを理解させることです。

2 つ目は、LoadLibrary を介して DLL を明示的にロードすることです。

C レベル関数のエクスポートでは、どちらのアプローチでも問題なく機能します。リンカーに処理させるか、前述したように GetProcAddress を呼び出すことができます。

しかし、輸出となると、 クラス, 、通常は最初のアプローチのみが使用されます。つまり、暗黙的に DLL にリンクします。この場合、DLL はアプリケーションの開始時にロードされますが、DLL が見つからない場合、アプリケーションはロードに失敗します。

DLL で定義されたクラスにリンクし、プログラム開始後のいつかの時点でその DLL を動的にロードしたい場合は、次の 2 つのオプションがあります。

  1. 特別なファクトリ関数を使用してクラスのオブジェクトを作成します。この関数は内部で (ほんの少しの) アセンブラを使用して、新しく作成されたオブジェクトを適切なオフセットに「接続」する必要があります。これは、明らかに、DLL がロードされた後の実行時に行う必要があります。このアプローチの適切な説明は次のとおりです。 ここ.

  2. 使う 遅延ロード DLL.

全てを考慮に入れると...おそらく、暗黙的リンクを使用する方がよいでしょう。その場合は、上記のプリプロセッサ手法を使用することをお勧めします。実際、Visual Studio で新しい DLL を作成し、「シンボルのエクスポート」オプションを選択すると、これらのマクロが自動的に作成されます。

幸運を...

他のヒント

DLL とその DLL を使用するモジュールをビルドするときに、一方と他方を区別するために使用できるある種の #define を用意し、クラス ヘッダー ファイルで次のようなことを実行できます。

#if defined( BUILD_DLL )
    #define IMPORT_EXPORT __declspec(dllexport)
#else
    #define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
    ...
};

編集:crashmstr が私に負けました!

いくつかのマクロを使用してコードにインポートまたはエクスポートのマークを付けます

#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif

#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif

次に、ヘッダー ファイルでクラスを宣言します。

class DLL MyClassToExport { ... }

それから #define ISDLL 図書館で、そして USEDLL クラスを使用する場所にヘッダー ファイルをインクルードする前に。

作業するために何か別のことをする必要があるかどうかはわかりません LoadLibrary

DLL から C++ クラスをエクスポートする簡単な例を追加します。

以下の例では、dll と exe がどのように相互作用するかについて簡単に概要を示しているだけですが (自明のことです)、製品コードに変更するにはさらに多くのことを追加する必要があります。

完全なサンプル例は 2 つの部分に分かれています

A..dll ライブラリ (MyDLL.dll) の作成

B..dll ライブラリを使用するアプリケーション (アプリケーション) を作成します。

A..dll プロジェクト ファイル (MyDLL.dll):

1.dllヘッダー.h

#ifdef  MYDLL_EXPORTS 
#define DLLCALL __declspec(dllexport)   /* Should be enabled before compiling 
                                           .dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport)  /* Should be enabled in Application side
                                          for using already created .dll*/
#endif

// Interface Class
class ImyMath {
public:
    virtual ~ImyMath() {;}
    virtual int Add(int a, int b) = 0;
    virtual int Subtract(int a, int b) = 0;
};

// Concrete Class
class MyMath: public ImyMath {
public:
    MyMath() {}
    int Add(int a, int b);
    int Subtract(int a, int b);
    int a,b;
};

//  Factory function that will return the new object instance. (Only function
//  should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
    DLLCALL ImyMath* _cdecl CreateMathObject();
};

// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();

2.dllSrc.cpp

#include "dllHeader.h"

// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
    return new MyMath();
}

int MyMath::Add(int a, int b) {
    return a+b;
}

int MyMath::Subtract(int a, int b) {
    return a-b;
}

B.すでに作成されている .dll ファイルをロードしてリンクするアプリケーション プロジェクト:

 #include <iostream>
#include <windows.h>
#include "dllHeader.h"

int main()
{
    HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"

    if (hDLL == NULL) {
        std::cout << "Failed to load library.\n";
    }
    else {
        CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
        ImyMath* pMath = pEntryFunction();
        if (pMath) {
            std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
            std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
        }
        FreeLibrary(hDLL);
    }
    std::cin.get();
    return 0;
}

最近、私はまったく同じ質問を自分自身に問いかけ、その結果をまとめました ブログ投稿で. 。役に立つかもしれません。

DLL からの C++ クラスのエクスポートと、それらのクラスの動的ロードについて説明します。 LoadLibrary, 、メモリ管理、名前のマングリング、呼び出し規約など、それに関するいくつかの問題について説明します。

エクスポートするクラスに vtable を配置したい場合は、インターフェイスを返す関数をエクスポートし、クラスを .dll に実装してから、それを .def ファイルに配置します。宣言のトリックを行う必要があるかもしれませんが、それほど難しいことではありません。

COMと同じように。:)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top