C++VSでdllを作成、呼び出す

21292 ワード

1.dllの利点
コード多重化はソフトウェア開発の効率を高める重要な方法である.一般的に、一部のコードが汎用性を有する限り、それを相対的に独立した機能モジュールとして構築し、その後のプロジェクトで繰り返し使用することができる.比較的一般的な例は、各種アプリケーションフレームワーク、ATL、MFCなどであり、いずれもソースコードとして公開されている.この多重化は「ソースレベル」であるため、ソースコードがプログラマーに完全に露出しているため、「ホワイトボックス多重化」と呼ばれる.「ホワイトボックス多重化」のデメリットが多く、まとめて4つあります.ソースコードが露出しました.複数のコピーにより、ストレージの浪費が発生します.プログラマの「通常」コードと名前の競合が発生しやすい.機能モジュールの更新は比較的困難で、問題のモジュール化の実現に不利である.実際,以上の4点を要約すると,「露出したソースコード」が「コードの深刻な結合」をもたらす.これらの不足を補うために,「バイナリレベル」のコード多重化を提案した.バイナリレベルのコード多重化を用いてソースコードをある程度非表示にすることは,コード結合現象の緩和に一定の役割を果たす.このような多重化は「ブラックボックス多重化」と呼ばれる.説明:「ブラックボックス多重化」を実現する方法はdllだけでなく、静的リンクライブラリ、さらに高度なCOMコンポーネントです.
2.dllの作成
参照プログラム原文:http://msdn.microsoft.com/zh-cn/library/ms235636.aspx「Win 32プロジェクト」を新規作成し、アプリケーションタイプを「DLL」と選択し、その他のデフォルト.ヘッダファイルtestdll.hを追加
//testdll.h
#ifdef TESTDLL_EXPORTS  
#define TESTDLL_API __declspec(dllexport)   
#else  
#define TESTDLL_API __declspec(dllimport)   
#endif  
namespace MathFuncs  
{  
    // This class is exported from the testdll.dll  
    class MyMathFuncs  
    {  
    public:   
        // Returns a + b  
        static TESTDLL_API double Add(double a, double b);

        // Returns a - b  
        static TESTDLL_API double Subtract(double a, double b);

        // Returns a * b  
        static TESTDLL_API double Multiply(double a, double b);

        // Returns a / b  
        // Throws const std::invalid_argument& if b is 0  
        static TESTDLL_API double Divide(double a, double b);
    };  
}

シンボルTEstdLL_が定義されている場合EXPORTS,TEstdLL_APIが_に設定されているdeclspec(dllexport)修飾子、This modifier enables the function to be exported by the DLL so that it can be used by other applications.定義されていない場合TEstdLL_APIが_に設定されているdeclspec(dllimport),This modifier enables the compiler to optimize the importing of the function from the DLL for use in other applications.DLLプロジェクトが生成されると、TEstdLL_EXPORTSのデフォルトは定義されているので、デフォルトは_declspec(dllexport)修飾子.cppファイルの追加
// testdll.cpp :    DLL          。
#include "stdafx.h"
#include "testdll.h"  
#include <stdexcept>  
using namespace std;  

namespace MathFuncs  
{  
    double MyMathFuncs::Add(double a, double b)  
    {  
        return a + b;  
    }  

    double MyMathFuncs::Subtract(double a, double b)  
    {  
        return a - b;  
    }  

    double MyMathFuncs::Multiply(double a, double b)  
    {  
        return a * b;  
    }  

    double MyMathFuncs::Divide(double a, double b)  
    {  
        if (b == 0)  
        {  
            throw invalid_argument("b cannot be zero!");  
        }  
        return a / b;  
    }  
}

コンパイルすると対応するdllファイルが生成され、対応するlibファイルも生成されます.注意:a.DLLで関数をエクスポートする宣言には、関数宣言に__を付ける2つの方法があります.declspec(dllexport);モジュール定義(.def)ファイル宣言を使用します.詳細は、http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792099.html b.Cファイルでdllを作成する場合、またはCコンパイラでdllを作成したい場合は、extern「C」フラグを使用することをお勧めします.extern「C」の簡単な解析を参照してください.
3.dllの呼び出し
アプリケーションがDLLを使用するには、暗黙的なリンク(呼び出し)と明示的なリンクの2つの方法があります.DLLを使用する前に、DLL内の関数の構造情報を知る必要があります.VSはVCbinディレクトリの下にDumpbinという名前を提供した.Exceのウィジェットで、DLLファイルの関数構造を表示できます.2つの比較詳細は、http://blog.sina.com.cn/s/blog_53004b4901009h3b.html暗黙リンクは静的ロード方式を採用し、比較的簡単で、必要である.h、.lib、.dll三条件セット.コンソールアプリケーションまたは空のアイテムを新規作成します.プロジェクト->プロパティ->構成プロパティ->VC++ディレクトリ->ヘッダファイルtestdllを「含むディレクトリ」に追加する.hが存在するディレクトリ項目->属性->構成属性->VC++ディレクトリ->ヘッダファイルtestdllをライブラリディレクトリに追加する.libが存在するディレクトリ・アイテム->プロパティ->構成プロパティ->リンク->入力->追加依存項目にtestdll.libを追加(複数のlibがある場合はスペースで区切られる)cppファイルを追加
//mydll.cpp
#include <iostream>  
#include "testdll.h"  
using namespace std;  

int main()  
{  
    double a = 7.4;  
    int b = 99;  

    cout << "a + b = " <<  
        MathFuncs::MyMathFuncs::Add(a, b) << endl;  
    cout << "a - b = " <<  
        MathFuncs::MyMathFuncs::Subtract(a, b) << endl;  
    cout << "a * b = " <<  
        MathFuncs::MyMathFuncs::Multiply(a, b) << endl;  
    cout << "a / b = " <<  
        MathFuncs::MyMathFuncs::Divide(a, b) << endl;  

    try  
    {  
        cout << "a / 0 = " <<  
            MathFuncs::MyMathFuncs::Divide(a, 0) << endl;   
    }  
    catch (const invalid_argument &e)   
    {  
        cout << "Caught exception: " << e.what() << endl;   
    }  
    return 0;  
}

コンパイルは通過しましたが、プログラムの実行はエラーで、testdllも必要です.dllは、現在のプロジェクトで生成された実行可能ファイルが存在するディレクトリにコピーされます.明示的なリンクは、アプリケーションが実行中にいつでもDLLファイルをロードしたり、いつでもDLLファイルをアンインストールしたりすることができます.これは暗黙的なリンクではできないので、明示的なリンクはより柔軟性が高く、解釈言語に適しています.新規プロジェクト、特別な構成を必要とせず、cppファイルを追加
/*
 *  :  
 *  :    DLL
 *  :2013-6-5
*/
#include<Windows.h> //      
#include<iostream>
using namespace std;

int main()  
{  
    typedef double (*pAdd)(double a, double b);
    typedef double (*pSubtract)(double a, double b);
 
    HMODULE hDLL = LoadLibrary("testdll.dll"); //  dll   
    if(hDLL != NULL)  
    {  
        pAdd fp1 = pAdd(GetProcAddress(hDLL, MAKEINTRESOURCE(1))); //  dll       
        if(fp1 != NULL)  
        {   
            cout<<fp1(2.5, 5.5)<<endl; 
        }  
        else  
        {  
            cout<<"Cannot Find Function "<<"add"<<endl;  
        }  
        pSubtract fp2 = pSubtract(GetProcAddress(hDLL, "?Subtract@MyMathFuncs@MathFuncs@@SANNN@Z")); //  dll    "?..."   ,C++           
        if(fp2 != NULL)  
        {  
            cout<<fp2(5.5, 2.5)<<endl;  
        }  
        else  
        {  
            cout<<"Cannot Find Function "<<"Subtract"<<endl;  
        }  
        FreeLibrary(hDLL);  
    }  
    else  
    {  
        std::cout<<"Cannot Find "<<"testdll"<<std::endl;  
    }  
    return 1;  
}

明示的に呼び出される問題:DLLファイルでは、dllエンジニアリングで関数名がDLLをコンパイルして生成する過程で変化し(C++コンパイラ)、DLLファイルで変化した文字を「name表示」と呼ぶ.GetProcAddressの2番目のパラメータは、DLLファイルの関数の順序によって得ることができる、またはDLLファイルの「name表記」を直接使用することができる、この表記はDumpbinによって行うことができる.exeウィジェット表示.C++コンパイラの下で、関数名をもっと規範化したい場合(元の工事と同じ)、具体的な方法はhttp://blog.csdn.net/btwsmile/article/details/6676802を参照してください.もちろん、関数名をより規範化するには、dllの作成中にCコンパイラを使用して関数をコンパイルすることが最も一般的です.これにより、DLLファイルの関数名と元のdllエンジニアリングの関数名が一致します.
4.より一般的な明示的な呼び出し
上記の最後の問題を解決するために、extern「C」を使用してdllエンジニアリングの関数にC接続を確立することができます.簡単な例のエンジニアリングは以下の通りです.DLLで作成したプロジェクトでcppファイルを追加
/*
 *  :  
 *  :  dll,  C  ——C      dll    "name  "  addfun
 *  :2013-6-5
*/
// cdll.cpp :    DLL          。
//
#include "stdafx.h"

#ifdef __cplusplus         // if used by C++ code
extern "C" {                  // we need to export the C interface
#endif

__declspec(dllexport) int addfun(int a, int b)
{
        return a+b;
}

#ifdef __cplusplus
}
#endif

コンパイルするとDLLファイルが生成されます.dll呼び出しエンジニアリングでcppファイルを追加する
/*
 *  :  
 *  :    dll
 *  :2013-6-5
*/
#include <windows.h>
#include <iostream>
using namespace std;

void main()
{
    typedef int(*FUNA)(int,int);
    HMODULE hMod = LoadLibrary("cdll.dll");//dll  
    if (hMod)
    {
        FUNA addfun = (FUNA)GetProcAddress(hMod, TEXT("addfun"));//           
        if (addfun != NULL)
        {
            cout<<addfun(5, 4)<<endl;
        }
        else
        {
            cout<<"ERROR on GetProcAddress"<<endl;
        }
        FreeLibrary(hMod);
    }
    else
        cout<<"ERROR on LoadLibrary"<<endl;
}

実行するとdllの関数を呼び出すことができます.さらに、上記dllファイルを暗黙的に呼び出すと、利用する.dll、.libファイル、呼び出し関数は
//    
#include <iostream>
#pragma comment(lib,"cdll.lib")
using namespace std;

extern "C" _declspec(dllimport) int addfun(int a,int b);
//  addfun  ,     .h     
//dll   C         extern "C"   dll  extern "C"
//   :_declspec(dllimport) int addfun(int a,int b);
void main()
{
    cout<<addfun(5,4)<<endl;
}