リンクライブラリのダイナミックリンクライブラリの詳細


windowsでは、リンクライブラリは2つのタイプに分かれています。スタティックリンクライブラリ.libとダイナミックリンクライブラリ.dll。ダイナミックリンクライブラリは、使用されるときに、通常はライブラリとして提供されます。Libは、主にDllによって導出された関数と記号名を提供しています。リンクするときに、dllに対応する関数マップを見つけることができます。静的リンクライブラリと動的リンクライブラリの役割は似ていますが、他のプログラムに呼び出しを提供するリソースです。ここで、動的リンクライブラリの呼び出し方法は、暗黙的呼び出し(静的導入呼び出し)と表示呼び出し(動的導入呼び出し)に分けられている。 コンパイル環境:Microsoft Visual Stdio 2010--------------------------------------------DLLは記号例を導出して、まず一つのdll 1.dllとdll 1.lib
 
// DLL1 ,dll1.cpp
// _declspec(dllexport)
_declspec(dllexport) int add(int a, int b)
{
return a + b;
}
を生成して、マイクロソフトのdependsツールを利用してdl 1.dllを調べて、導き出す記号は下記の通りである:http://www.cnblogs.com/monotone/ この中の各フィールドの意味:Ordinal(記号番号、後にGetProcAddressを使う時、参照する数値)、Hit(これは私もよく分かりません。よく分かりません。分かりません。これは関数導出後の記号名です。)、EntryPoint(これは関数DLLのアドレスです。)。ここで関数の名前がこのようになったのは、使用されているコンパイラがデフォルトではC++でコンパイルされているため、C++はリロードをサポートしているので、関数名に追加の記号を追加して、同じ名前のリロード関数と区別してDLLに識別子で位置決めする必要があるからです。ここでは簡単なテストができます。新しいコンソールテストプロジェクトDllTestは以下の通りです。
 
// DllTest ,DllTest.cpp
#include <iostream>
using namespace std;
int main(void)
{
// extern int add(int a, int b);
// _declspec(dllimport) , , 。
_declspec(dllimport) int add(int a, int b);
cout << add(1,2) << endl;
getchar();
return 0;
}
はリンクをコンパイルして、リンクエラーerror LNK 2019:unresoved external smbol“___u u”をヒントとします。declspec(dlimport)int cdecl add(int,int)「(u_imp_add@YAHHH@Z)referenced in function_メイン、明らかなコンパイラはコンパイルする時、add関数も名前を変えました。そして上のdependsで見たのと同じです。この記号の定義が見つからないという意味です。コードを追加した後、次のようになります。
 
// DllTest ,DllTest.cpp
#include <iostream>
using namespace std;
#pragma comment(lib, "../debug/dll1.lib") // dll1.lib,
int main(void)
{
// extern int add(int a, int b);
// _declspec(dllimport) , , 。
_declspec(dllimport) int add(int a, int b);
cout << add(1,2) << endl;
getchar();
return 0;
}
コンパイル実行後、Dependsツールを使ってDllTest.exeに対してその依存性の入力情報を調べます。image DllTest.exeは、dll 1.libを介して、dll 1.dllに対する依存性を導入していることがわかる。DLLが提供するヘッダファイルは通常、一つのファイルを得ると、どの関数の呼び出しが提供されているかが分かりません。私たちはdependsツールを利用してdllから導出された関数と番号を調べることができますので、もちろん他の方法で具体的にどのように使うかを知ることができるかもしれませんが、内部の具体的な実現の詳細は分かりません。)したがって、使用を容易にするためには、通常は、Dolに対するhファイルを提供し、クライアントに提供する方法や説明などの情報を表明する。クライアントは、このヘッダファイルを使用して、使用するインターフェースを導入する。しかし、これらの関数の声明が多く出されないように、クライアントが直接にhファイルにすべてのインターフェースを導入します。Dllコンパイルの場合は、エクスポートとして使用します。方法は以下の通りです。
 
// DLL1 ,dll1.h
#ifndef DLL1_API
#define DLL1_API _declspec(dllimport)
#endif
// , , DLL1_API , DLL1_API _declspec(dllimport), 。
// ( , ), , 。
DLL1_API int add(int a, int b);
 
// DLL1 ,dll1.cpp
#define DLL1_API _declspec(dllexport)
// , , DLL1_API , DLL1_API _declspec(dllexport) , 。
#include "dll1.h"
// , 。
int add(int a, int b)
{
return a + b;
}
に対応しています。TestDllプロジェクトに含まれています。hファイルの後、もう申明しなくてもいいです。
 
// DllTest ,DllTest.cpp
#include <iostream>
using namespace std;
#include "../dll1/dll1.h" // ,
#pragma comment(lib, "../debug/dll1.lib") // dll1.lib,
int main(void)
{
cout << add(1,2) << endl;
getchar();
return 0;
}
以上は、なぜいつもdllを引用する時には頭一つのファイルがあり、しかも頭文書の中には多くの咻ifndefなどがあるかを基本的に説明しました。------------------------------------------------------------------------------------------------ダイナミックリンクライブラリのエクスポートクラスはもちろん、動的リンクライブラリもクラスを導出することができます。APIは、DLL 1_ではなくCSampleである。API class CSample。また、クラスの導出に注意しながら、そのすべてのメンバー関数も導出しましたが、クラスメンバー変数のアクセス権限の制限に従います。クラスのメンバー関数を個別に導出する場合(ステートメント方式は大域関数と同じ)、クライアントでクラスオブジェクトを実装し、エクスポートされたメンバー関数を呼び出しても、エクスポートされていないメンバー関数(publicであっても)は呼び出すことができない。----------------------------------------------------------------------------------------------改編された記号名は、記号をエクスポートする際に、C++は関数名を改編し、関数の再負荷をサポートします。使用しないC++コンパイラ(コンパイルされた記号名が異なるため)またはクライアントがCコンパイラで呼び出すと、LNK 2019のようなリンクエラーが発生し、シンボルが見つからないという問題があります。この問題はDLLの使用範囲を大きく制限している。解決方法1:extern「C」を使って事前に説明し、関数がCのようにリンクをコンパイルしていることを示します。C方式でコンパイルしてエクスポートした関数は、シンボル名を改編しないので、上記の問題を回避することができます。
 
// DLL1 ,dll1.h
#ifndef DLL1_API
#define DLL1_API extern "C" _declspec(dllimport)
#endif
// , , DLL1_API , DLL1_API _declspec(dllimport), 。
// ( , ), , 。
DLL1_API int add(int a, int b);
//class CSample
//{
//public:
// DLL1_API int substract(int a,int b);// , ,
//};
ここで注意したいのですが、hと.cppの両方にextern「C」を加えて、導入とエクスポートをCでコンパイルします。
 
// DLL1 ,dll1.cpp
#define DLL1_API extern "C" _declspec(dllexport)
// , , DLL1_API , DLL1_API _declspec(dllexport) , 。
#include "dll1.h"
// , 。
int add(int a, int b)
{
return a + b;
}
//
//int CSample::substract(int a,int b)
//{
// return a - b;
//}
はその後dependsで調べます。image エクスポートした関数記号名と関数宣言時は同じです。クライアントが使用する場合は、導入もextern「C」方式ですので、クライアントはリンクをコンパイルする際に、関数の元の名前の記号を使用します。Cコンパイルリンク方式を使用していますので、C++のクラスとメンバー関数の導出はこのような方法ではできません。また、私たちが関数宣言に標準コールを加えると、DLL 1_API int_stdcal add(int a,int b);なお、関数の定義にも_を加えます。stdcalそれでは、コンパイルした結果、dependsを使ってシンボルの名前を見ます。add@8ということは、記号名がまた変わったということです。解決方法2:モジュールを使ってファイル・defを定義し、このファイルのフォーマット仕様はMSDNを調べ、検索・defを見ればいいです。LIBREAYコマンドは、ライブラリファイルを導出するためにdefファイルを指定し、EXPORTSは関数シンボル名を指定するために使用される。つまり、defファイルは主にリード記号などの情報を制御するために使われます。
 
LIBRARY dll1
EXPORTS
add11=add
私はここでadd関数の別名をadd d 11としてあげます。注意しながら、hファイルでaddがadd d d d d d 11であると宣言する必要があります。defが提供された後、cppに提供されるコールの約束はすべて無効になります。defは生成されたシンボル名を指定しています。ここでは、defがDllのリード記号を制御しています。クライアントが使用する場合は、声明を提供し、リンクしてください。libファイルは、使用できます。VC 6.0以降のIDEは、リンクオプション(LINK)のinput-」module define fileで、defファイルを指定して、コンパイラがこれを使用します。備考:このブロックは呼出の約束と、externを入れない「C」について、まだ混乱しています。分かりましたら、またここに補足してください。このブロックに関するいい紹介資料を提供してください。----------------------------------------------------------------------------------------------------------------------------------リンク(動的なインポートリンク)を表示する前に、エクスポートされた関数に名前がないようにすると、クライアントはどうやって呼び出しますか?記号表のordinalを使っています。もちろん関数名を使って導入することもできます。ダイナミックインポートにはlibファイルと.hファイルは必要ありません。関数名がわかれば。
 
// DllTest ,DllTest.cpp
#include <iostream>
using namespace std;
#include <windows.h>
int main(void)
{
HMODULE hModule = ::LoadLibraryA("dll1.dll");
if(NULL != hModule)
{
typedef int (*ADDPROC)(int a, int b);
//ADDPROC add = (ADDPROC)::GetProcAddress(hModule, "add11"); //
ADDPROC add = (ADDPROC)::GetProcAddress(hModule, MAKEINTRESOURCEA(1)); // ordinal , , MSDN 。
if(NULL != add)
cout << add(1,1) << endl;
::FreeLibrary(hModule);
}
getchar();
return 0;
}
は、関数名によって動的に導入される場合、実際にはシンボル名、すなわち、dllが提供するシンボル名とユーザに提供する関数声明とが一致することを言及する価値がある。また、ダイナミックリンクライブラリを動的に導入する場合、必要な入力情報はexeでは確認できない。--------------------------------------------------------------------------------------------------------------------------後記はこんなに詳しくて長いブログを書くのは初めてです。後ろに書いている時はだんだん粗くなりました。あとで書くときは、自分でも何を書くか分かりません。これ以上広げていくと、増えていくものが多すぎるからです。また、一部の原因は後ろの内容をよく理解していないので、同時に使うことも少ないです。とにかく頭が混乱しています。ここではブログを書いている侠客たちに深い敬意を表します。最后に申明したいのは、これらは全部自分でビデオを参考にしてまとめたものです。専门ではなくて、正しくないところもあると思います。ご指导をお愿いします。