ダイナミックリンクライブラリ(DLL)の生成と使用

1.ダイナミックリンクライブラリ(DLL)の概要

DLL連絡する前に、それは、ブラックボックスのように、我々は直接実行することはできません非常に神秘的であるとは思いません、あなたがメッセージを受信できません。彼らは、実行可能プログラムが含まれているか、特定のジョブを行うために他のDLL関数の呼び出し、他のモジュールでのみDLL関数の呼び出し、DLLだけな役割を再生することができ、スタンドアロンのファイルの一部です。 
実際のプログラミングでは、我々は、ダイナミックリンクライブラリ内の関数の機能を達成することができ、その後、他のプログラムの呼び出しに利用可能となります。Windows API関数のすべてと同様にKernel32.dll、User32.dllの、GDI32.DLLなどなどに、DLLに含まれています。だから、何が良いは、DLLしていますか?

1.1静的および動的ライブラリ

静的ライブラリ:機能とデータがコンパイルされたとき、静的ライブラリの場合には、バイナリファイル(通常は拡張子.LIB)にコンパイルされた実行可能ファイルにリンクされ、リンカーは、静的ライブラリーから、これらの機能とデータをコピーし、そして他のモジュールおよびアプリケーションは、最終的な実行可能ファイル(.exeファイル)を作成するために結合されます。製品が唯一の実行可能ファイルを解放する必要が解放されたときに使用される静的ライブラリを公開する必要はありません。
DLL:インポートライブラリ(.libファイル、非必須)および.dllファイル:動的ライブラリを使用する場合、多くの場合、2つのファイルを提供しています。ここでは、ファイルの拡張子は、動的ライブラリーに由来関数や変数のシンボル名が含まれているダイナミックリンクライブラリ、そのインポートライブラリファイルに対して、.LIBですが、根本的に異なるがありますが紹介し、静的ライブラリだ、と。 DLLファイルは、実際の動的なライブラリ関数やデータが含まれています。

1.2ダイナミックリンクライブラリを使用する利点

たとえば、私たちはその後、VBで書かれたプログラムでそれを呼び出す、VC ++でDLLを書くことができます:あなたはプログラミング言語の多様性を使用することができます。
製品の機能強化:あなたが製品の性能を向上させる目的を達成するため、新しいDLLのDLLを開発することによって、元の製品を置き換えることができます。例えば、我々はインターフェイスプラグイン機能のインターフェイスDLLを置き換えることによって達成することができ、動的に変更インタフェースプログラム、にユーザーを可能に蹴る製品の多くを参照してください。
二次開発プラットフォームを提供します。ユーザーは、2番目の開発を達成するために、完全に他のアプリケーションに、その内部に実装され、単一のコールDLL関数を利用することができます。
メモリを保存:複数のアプリケーションが一度だけメモリに同じDLL、DLLのページを使用する場合は、すべてのアプリケーションは、このようにメモリを節約、そのページを共有することができます。

2. DLLの作成

DLLの作成主に二つの方法があります:まず、DLLを作成する__declspec(dllexport)を使用して、第二は、モジュール定義(.def)ファイルを使用してDLLを作成することです。

DLLを作成するために2.1を使用__declspec(のdllexport)

まず、ビジュアルC ++、名前のDLL1のVSでWin32プロジェクトを作成します。空のDLLプロジェクトを作成するには、すなわち、追加オプションで空のプロジェクトを選択し、アプリケーションタイプでDLLを選択します。 

                    
 
そして、C ++ソースファイルプロジェクトに追加:Dll1.cppを、私が達成したいと仮定すると、以下のようにコードがあり、加算と減算です。

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

__declspec(dllexport) int subtract(int a, int b){
    return a - b;
}

__ declspec(のdllexport):dllファイルエクスポート機能を作成するには、関数をエクスポートする各識別子のニーズの前に追加する必要があります。 
ビルドコマンドを使用してDLL1は、ダイナミックリンクライブラリを生成し、それがDLL1 / Debugディレクトリ、ファイル内の.dllファイルと.libファイルが生成されます、これら二つの文書は、必要なダイナミックリンクライブラリです。 

                    
 
今、あなたは、このDLLファイルを持っていることをあなたはそれを他のプログラムに加算および減算機能にアクセスすることができ、DLLではないでしょうか?それは注意しなければならない、このです:アプリケーションがDLL内の機能にアクセスするために望んでいる場合、この関数は機能を輸出されている必要があります。 
そこにDLL関数を導き出すかを確認するには、Visual Studioは、コマンドラインツールを提供します。DUMPBIN。

DLLエクスポートされた関数を検証する2.2 DUMPBINコマンド

まず、VSのインストールディレクトリへのコマンドラインを入力しVCVARS32.BATという名前のバッチプログラムを実行します(VS2013のために、ファイルは\ VC \ binディレクトリの下のバットである)、ファイルの役割を作成するために使用されます環境情報のVC ++を使用。(コマンドラインインターフェイスにVCVARS32.BATファイルを実行すると、環境情報ファイルの設定は、現在のコマンドライン・ウィンドウに反映することに注意してください。) 
次にDUMPBINのコマンドを入力して、リストに次のコマンドを使用します。 

                    
 
あなたは、ディレクトリDll1.dllファイルで提供DLLのエクスポート機能を見てみたいので、コマンドラインで次のコマンドを入力します。

dumpbin -exports Dll1.dll

                    

画像では、エクスポートされた関数名を追加しているあなたは、私たちは2つの機能を引き出すことがわかりますが、エクスポートされた関数の名前が変だった上に「?@@ YAHHH @ Z追加」 、 名前は?」エクスポート機能があるSubtrctを引きます@ @ YAHHH @ Z」。これは、独自のルールに従い、関数の名前を指定してコンパイルとリンクされているため、C ++、タンパ、と呼ばれるプロセスである「名前の符号化。」これは、DLL異なる言語の問題を呼び出し、異なるコンパイラにつながることができます。そこで我々は、コンパイル時にダイナミックリンクライブラリファイルは、エクスポートされた関数の名前は変更しないことを願っています。 
これを達成するために、プラス修飾子は、再定義された派生機能することができます。extern「C」、など

extern "C" __declspec(dllexport) int add(int a, int b){
//...
}

しかし、このアプローチは、名前のC ++やC言語関数間の相互通話の問題を解決することができます。この問題を解決するために、モジュール定義(.def)ファイルで実現することができます。

2.3モジュール定義(.def)ファイルの作成DLL

コードは、最も原始的な方法で書かれているので、DLLファイルはdefを使用して作成され、その後、必要に__declspec(のdllexport)がありません。

int add(int a, int b){
    return a + b;
}

int subtract(int a, int b){
    return a - b;
}

同时为工程创建一个后缀名为.def的文件,并添加进工程,编辑其内容为:

LIBRARY Dll1

EXPORTS
add
subtract

其中LIBRARY语句用于指定动态链接库的名称,该名称与生成的动态链接库名称一定要匹配。EXPORTS语句用于表明dll将要导出的函数,以及为这些导出函数指定的符号名。 
将该模块定义文件链接到工程中,方法为工程属性页面>链接器>输入>模块定义文件中写入“Dll1.def”。 

                    
 
然后重新Build Solution,并用dumpbin工具查看现在dll导出的函数,可以发现函数的名字改编问题得到了解决! 

                    
以上就是创建dll的两种方法,个人比较提倡使用模块定义(.def)文件创建dll,代码简洁的同时还没有名字改编的问题。 
接下来我们来看看如何使用创建好的dll。

3. dll的使用

dll的使用也有两种方法,一是隐式链接的方式加载dll,二是显示加载方式加载dll。

3.1 隐式链接方式加载dll

为了更好地展示dll的使用,我首先创建了一个基于MFC的对话框程序,然后为其添加两个按钮。 
                     
将生成好的Dll1.dll和Dll1.lib复制到对话框程序所在的文件夹,然后在CXXXDlg.h中注册动态链接库的引入库文件。因为.lib文件包含了Dll1.dll中导出函数的符号名,相当于告诉对话框程序相关函数应该去dll中调用。

#pragma comment(lib,"Dll1.lib")

然后在CXXXDlg.cpp中声明外部函数:

_declspec(dllimport) int add(int a, int b);
_declspec(dllimport) int subtract(int a, int b);

这样我们就可以使用这两个函数了。为两个按钮添加事件响应程序,并添加如下代码:

void CXXXDlg::OnBtnAdd()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format(_T("5 + 3 = %d"), add(5, 3));
    MessageBox(str);
}

运行程序发现可以通过dll的导出函数来实现加法功能了。说明dll可以使用。 

             
3.2 显示加载方式加载dll

另一种是通过LoadLiabrary函数显示加载dll。代码如下。需要注意的是这时候我们不再需要注册.lib文件,也不需要声明外部函数。只要在需要使用的地方调用dll文件即可。

void CXXXDlg::OnBtnSubtract()
{
    // TODO: Add your control notification handler code here
    HINSTANCE hInst;
    hInst = LoadLibrary(L"Dll1.dll");
    typedef int(*SUBPROC)(int a, int b);
    SUBPROC Sub = (SUBPROC)GetProcAddress(hInst, "subtract");
    CString str;
    str.Format(_T("5-3=%d"), Sub(5, 3));
    FreeLibrary(hInst);       //LoadLibrary后要记得FreeLibrary
    MessageBox(str);
}

                    

3.3 两种加载方式对比

通过以上的例子,可以看到隐式链接和动态加载两种加载dll的方式各有优点。

隐式链接方式实现简单,一开始就把dll加载进来,在需要调用的时候直接调用即可。但是如果程序要访问十多个dll,如果都采用隐式链接方式加载他们的话,在该程序启动时,这些dll都需要被加载到内存中,并映射到调用进程的地址空间,这样将加大程序的启动时间。而且一般来说,在程序运行过程中只是在某个条件满足的情况下才需要访问某个dll中的函数,如在上述例子中,我只有在点击按钮时才需要访问dll,其他情况下并不需要访问。这样如果所有dll都被加载到内存中,资源浪费是比较严重的。
显示加载的方法则可以解决上述问题,dll只有在需要用到的时候才会被加载到内存中。另外,其实采用隐式链接方式访问dll时,在程序启动时也是通过调用LoadLibrary函数加载该进程需要的动态链接库的。
————————————————
版权声明:本文为CSDN博主「Elaine_Bao」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/elaine_bao/article/details/51784864

发布了12 篇原创文章 · 获赞 49 · 访问量 1万+

おすすめ

転載: blog.csdn.net/qq_36570733/article/details/104516798