C++DLLダイナミックリンクライブラリの作成手順と実装方法

4490 ワード

この例では、DLLダイナミックリンクライブラリをC++で記述する手順と実装方法について説明します.皆さんの参考にしてください.具体的には以下の通りです.
C++プログラムを書く場合、クライアントプログラム呼び出しのためにclassをDLLと書くことがよくあります.このようなDLLはclass全体を導出することもできるし,このclassのある方法を導出することもできる.
一、class全体をエクスポートする
クラスのヘッダファイルにclassとクラス名の間に_を付けるだけで簡単です.declspec(dllexport)は、クライアント呼び出しプログラムで使用されるクラスに提供される別のヘッダファイルにclassとクラス名の間に_を追加します.declspec(dllimport).クライアント・プログラムとDLLプログラムがクラスのヘッダ・ファイルを共通に使用できるようにするには、通常、クラスのヘッダ・ファイルでマクロおよびプリコンパイル命令を使用して処理される.以下DLTest.h:

#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif
Class DLL_TEST_API CDLLTest
{
   Public:
     CDLLTest();
     ~CDLLTest();
     int Add(int a, int b);
};


DLLTest.cppは以下の通りである.

#define DLL_TEST_API  _declspec(dllexport)
#include "DLLTest.h"


このようにDLLコンパイル時にDLL_TEST_APIは_として定義されるdeclspec(dllexport)は、クライアント・プログラムのコンパイル時に_として定義されます.declspec(dllimport).
二、このクラスをエクスポートする方法の一つまたはいくつか
この場合、_declspec(dllexport)は、DLTestなどのメンバー関数の名前に配置されます.h:

#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif
Class CDLLTest
{
   Public:
      CDLLTest();
         ~CDLLTest();
      int DLL_TEST_API Add(int a, int b);
};


ただし、それだけではクライアントプログラムincludeというヘッダファイルの後、DLTestというクラスの1つのオブジェクトを定義した後(静的にDLLをリンクする)、クライアントプログラムがリンクできなくなり、コンストラクタとコンストラクタが解析できないことを示唆するので、コンストラクタとコンストラクタの前にDLL_を付ける必要があるTEST_APIマクロでいいです.
もちろんここでもう一つの問題は、クラスの関数がエクスポートされると名前が変わり、関数の名前にextern「C」、例えばextern「C」DLL_を加えることができます.TEST_API int Add(int a ,int b);しかし、これはCとC++が呼び出されたときの名前変更の問題を解決するだけで、信頼できる方法はモジュール定義ファイルdefを追加することであり、このファイルではエクスポート関数の名前を定義し、後でサンプルを見ることができます.
DLLの作成が完了すると、クライアントプログラムがどのようにDLLを呼び出すか、静的にDLLを呼び出すか、動的にDLLを呼び出すかしか残っていません.
一、静態方式呼び出しDLL
この方法は簡単ですDLTest.hヘッダファイルとDLTest.lib,DLLTest.dllファイルをクライアントプログラムの現在のディレクトリにコピーし、#includeでクライアントプログラムに導入し、#pragma comment(lib,“DLTest.lib”)でlibライブラリを導入するか、クライアントプログラムのエンジニアリング属性にそのlibファイルの導入を追加します.
その後、クライアント・プログラムでローカルのclassを使用するようにDLLを使用できます.たとえば、次のようにします.

CDLLTest dllTest;
dllTest.Add(1,2);


二、ダイナミック方式呼び出しDLL
このDLLを動的に呼び出すには、このclassを変更する必要があります.
まず、DLTest.cppファイルにグローバル関数を追加します.このclassのインスタンスを返すことができます.これにより、クライアントプログラムがこのグローバル関数を呼び出した後、classのインスタンスを得ることで、classのインスタンスメソッドを呼び出すことができます.

extern "C" _declspec(dllexport) CDLLTest* GetInstance()
{
   return new CDLLTest;
}


注意:extern"C"はcとc++コンパイラの互換性の問題を解決しただけで、他のコンパイラとの互換性が必要な場合は、信頼できる方法を1つ追加します.defファイル、ファイルの内容は以下の通りです.

LIBRARY "DLLTest"
EXPORTS
GetInstance = GetInstance


これにより、DLLを指定した関数のエクスポート後の名前は変更されません.
これにより、クライアントプログラムは、classのインスタンスをこの関数で取得することができる.次のようになります.
まず、関数ポインタのタイプを定義する必要があります.

typedef CDllTestBase* (*pfGetInst)();
// :CDllTestBase      。
HMOUDLE hMod = LoadLibrary( _T("DLLTest.DLL") );
if(hMod)
{
  pfGetInst pfGetInstance = (pfGetInst)GetProcAddress("GetInstance");
  if( p )
  {
   //             
    CDllTestBase * pInst = pfGetInstance ();
   if( NULL != pInst )
   {
    pInst->Add( 1,2);
   }
      if( NULL != pInst )
   {
    //    
    delete pInst;
   }
  }
}


もちろん、ここではincludeというDLLのヘッダファイルDLTestBaseが必要です.h,先に書いたヘッダファイルDLTest.hはクライアントプログラムの現在のディレクトリに直接コピーし、includeが入ってくると、接続をコンパイルする際に通過できません.このヘッダファイルを修正する必要があります.まず1つ追加します.hファイルDLTestBase.h,このファイルではクライアントプログラムで呼び出す必要がある関数を純虚関数と命名し,CDLLTestクラスをCDLLTestBaseクラス,DLTestBaseから継承する.h以下:

Class CDLLTestBase
{
  Public:
    Virtual ~CDLLTestBase(){};//     ,      
     Virtual int Add(int a, int b) = 0;
}


DLLTest.h修正後は以下の通りである.

#include "DLLTestBase.h"
Class CDLLTest : public CDLLTestBase
{
  Public:
    CDLLTest();
    ~CDLLTest();
    int Add(int a, int b);
};


注意:ここでDLTestBaseでは、クライアント・プログラムでベース・クラス・ポインタを使用して派生クラス・オブジェクトを解放できるように、仮想構造関数を提供する必要があります.
DLTestBaseをhクライアントプログラムの現在のディレクトリにコピーし、クライアントプログラムで#include“DLTestBase.h”を呼び出すと、上記のようにクライアントプログラムでDLLを呼び出す方法があります.
本文で述べたことは皆さんのVC++プログラム設計に役立つことを望んでいます.