記事のディレクトリ
言うまでも無く、おそらく利点、いわゆるブラックボックスの再利用、モジュラーソースコードように露出を回避しながら。ほんの数モジュールは、DLLが容易なプログラムの拡大に、完全な更新を必要とせずに交換することができる場合は、簡単に再利用、および更新ソフトウェアの更新のための一般的な機能ブロックを作ることができます。次のチュートリアルは、他のバージョンに似てVS2015に基づいています。記事の参照 リンク
1.DLL作成
-
プロジェクトを作成します。例えばMYDLLなどの任意の名前を、指定された新しいアプリケーション対のWin32に、概要次へをクリックし、アプリケーション設定アプリケーションタイプ選択DLL(D)のは、終了します。
-
ヘッダファイルを追加します。ではプロジェクト - 新しい項目の追加 - ** Visaul C ++ **ヘッダファイルを選択し、MyDll.hとしてファイル名を設定します。
-
ヘッダファイルに次のコードを追加します。
#ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport)//注意decl前面是两个下划线 #else #define MYDLL_API __declspec(dllimport) #endif namespace MyDllSpace { //导出类 class MyDllClass { private: double a; public: //导出的函数 MYDLL_API MyDllClass(); MYDLL_API MyDllClass(double a_); MYDLL_API double multiply(double b); MYDLL_API void display(); MYDLL_API static void conbine(MyDllClass m1, MyDllClass m2); }; }
注:このヘッダファイルは、DLLのソースファイルを含めることができますので、またその条件付きコンパイルの使用の初めに、党の使用を含む-ソース(#ifdefのMYDLL_EXPORTSを含むDLLファイル、定義VSために生成DLLプロジェクトのデフォルトは
DLL名称_EXPORTS
、このマクロ)、かつてのエクスポート機能を追加する__declspec(dllexport)
マクロを、消費者が含まれている場合、エクスポート機能が増加する前に、__declspec(dllimport)
マクロを -
ソースファイルに次のコードを追加します。
#include "MyDll.h" #include <iostream> MyDllSpace::MyDllClass::MyDllClass() { a = 0; } MyDllSpace::MyDllClass::MyDllClass(double a_) { a = a_; } MYDLL_API double MyDllSpace::MyDllClass::multiply(double b) { return a*b; } MYDLL_API void MyDllSpace::MyDllClass::display() { std::cout << "a=" << a << std::endl; } MYDLL_API void MyDllSpace::MyDllClass::conbine(MyDllClass m1, MyDllClass m2) { std::cout << "(" << m1.a << "," << m2.a << ")" << std::endl; }
注:ここでの機能はそれほどでは常にない、彼らのコードワードは、名前空間はこれらの定義を囲むMyDllSpace使用することができる、自動的に(もちろん、関数本体はまだ書かなければならない)ソースファイルで生成された定義関数の高速動作のためのヘッダファイルを介して行われ名前空間は、関数に定義された空間で定義されています
-
メニューバーをクリックして世代 - 世代ソリューション dllファイル生成のdllとlibファイルを見ることができ、プロジェクトのDebugディレクトリに完成作成します。
2.dll現在使用
-
クリックしてファイル - 新しい - プロジェクトを、このようUseMyDllなど任意の名前を、設定のWin32コンソールアプリケーションを、選択し、次のステップで決定したアプリケーションの設定で追加のオプションでプリコンパイル済みヘッダーの完全に選択を削除するには、チェックボックスを。
-
で、プロジェクトディレクトリに生成された前のステップのdll、libに、.hのヘッダファイルをコピーするために、ソリューションエクスプローラのプロジェクトに参加するために、既存のアイテムを追加します。
-
次のコードUseMyDll.cppファイルを追加します。
#include <iostream> #include "MyDll.h"//加入模块的头文件 using namespace std; int main() { double a = 8; MyDllSpace::MyDllClass c(4);//创建模块里的类实例 MyDllSpace::MyDllClass c2; c.display();//使用实例方法 cout << "8*4=" << c.multiply(a) << endl; MyDllSpace::MyDllClass::conbine(c, c2);//使用模块里的类的静态方法 system("pause");//暂停以便能看到输出 return 0; }
次のように出力されます。
注意:
- 新しいプロジェクトをするときに突出するように選択した場合、溶液に添加されたDLLソリューションの下に新しいプログラムでは、ある、あなたは、DLLへの参照を追加することができます-直接ソリューションエクスプローラで、参照を右クリックし、参照を追加し、dllが以前に作成した追加されます参照(これは公式のチュートリアルの使用中) - DLLなしで現在のフォルダに、プロジェクトに追加。我々はより一般的な場合には、コードの再利用は、自分のプロジェクトに依頼する必要があることを前提とするのでしかし、現実的ではありません。
- ヘッダファイルは見つかっ便宜のために、現在のプロジェクトに追加してはいけません。また、中にプロジェクト - 不動産 - C / C ++ - 一般的には、格納されたファイルヘッダーの下、追加のディレクトリを含むディレクトリを追加し、さらにはシステムディレクトリ内のファイルを向かうことができる、限り、あなたは、ヘッダーファイルをインクルードすることができますようとして求めることができます。また.LIBファイルがプロジェクトに必須ではないが、.LIBも、ライブラリに登録されたフォルダを追加し、追加の依存関係としての.libファイルを追加することができます。
3.のみDLL(明示的なリンク)
上記の方法は、独自のDLLを書くために使用するが、他の人が与えた場合にのみDLLは使用方法に関するその他の情報が含まれていませんか?ステップ1は、さらに、明示的なリンク、ないヘッダファイルとlibがあり、DLLは暗黙的なリンク(コール)と呼ばれています。明示的なリンクは常にまた、アンインストールはいつでも、インタプリタ言語に適した、より多くの柔軟性は、もちろん、また、いくつかのより多くのトラブルを使用することができ、プログラムの実行時にDLLロードすることができます。VSは、構造関数のDLLファイルを参照するにはVC \ binディレクトリにDUMPBIN.EXEプログラムを提供します。参考リンク。
-
ステップ1と同様にDLLプロジェクトを作成します
次のようにヘッダーコード:
//FuncOnlyDll.h #ifdef FUNCONLYDLL_EXPORTS #define FUNCONLYDLL_API __declspec(dllexport) #else #define FUNCONLYDLL_API __declspec(dllimport) #endif namespace Funcs { FUNCONLYDLL_API double minValue(double a, double b); FUNCONLYDLL_API double maxValue(double a, double b); FUNCONLYDLL_API double add(double a, double b); FUNCONLYDLL_API double subtract(double a, double b); }
次のようにソースコードは次のとおりです。
//FuncOnlyDll.cpp #include "FuncOnlyDll.h" FUNCONLYDLL_API double Funcs::minValue(double a, double b) { return a < b ? a : b; } FUNCONLYDLL_API double Funcs::maxValue(double a, double b) { return a > b ? a : b; } FUNCONLYDLL_API double Funcs::add(double a, double b) { return a + b; } FUNCONLYDLL_API double Funcs::subtract(double a, double b) { return a - b; }
メニューバーをクリックして世代 - 世代のソリューション、以下のようにDLLファイルは、DUMPBIN.EXEビューに構造のDLL関数を使用して生成された、開いているプロジェクトのディレクトリフォルダ:
可以看到有四个函数,但是显示的就像乱码,顶多只能看出每个函数叫啥,这样对于使用的用户来说是不友好的,因为看一堆乱码是无法知道这些函数是干啥的,有哪些参数和返回值,这样是无法使用的,我们可以在菜单栏项目-添加新项-Visaul C++-代码选择模块定义文件(.def),设置文件名,在添加的def文件中给出如下代码:
LIBRARY EXPORTS double_add_double_double=?add@Funcs@@YANNN@Z double_maxValue_double_double=?maxValue@Funcs@@YANNN@Z double_minValue_double_double=?minValue@Funcs@@YANNN@Z double_subtract_double_double=?subtract@Funcs@@YANNN@Z
其中后面的乱码对应之前dump出来的dll函数名乱码,写这个def文件相当于把乱码重新定义名字,让它更好识别,这里我定义的规则是
返回类型_函数名_参数列表类型
,当然你可以定义自己的规则,这样使用者一看就知道这个函数干啥的,有啥参数和返回值,再dump一下dll看看:
发现后面四个函数输出了我们想要的结果,但是前面仍然有四个乱码函数(其实是同样四个函数),可以将头文件中的*#define FUNCONLYDLL_API __declspec(dllexport)改成#define FUNCONLYDLL_API*这样就不会输出前面的乱码(但是这样会使得dll使用隐式链接出错):
至此,dll创建完毕。
-
新建一个项目使用创建的dll
显式链接是不用配置项目属性的,直接将dll文件放在项目目录下,或是其他能查找到的目录比如系统path路径之类的,代码如下:
#include <iostream> //为了使用LoadLibrary和FreeLibrary等函数以及LPCWSTR和LPCSTR类型加入的头文件 #include <Windows.h> using namespace std; //定义要加载的各种函数指针,通过dumpbin查看dll函数中函数签名从而得知,或者查看API typedef double(*pMin)(double, double); typedef double(*pMax)(double, double); typedef double(*pAdd)(double, double); typedef double(*pSub)(double, double); int main() { LPCWSTR dllName = TEXT("FuncOnlyDll.dll"); LPCSTR funName1 = "double_minValue_double_double"; LPCSTR funName2 = "double_maxValue_double_double"; LPCSTR funName3 = "double_add_double_double"; LPCSTR funName4 = "double_subtract_double_double"; HMODULE hDll = LoadLibrary(dllName);//加载dll if (hDll != NULL) { pMin fp1 = (pMin)(GetProcAddress(hDll, funName1));//加载函数 if (fp1 != NULL) { cout << "min value of 5 and 6:" << fp1(5, 6) << endl; } else { cout << "函数min加载失败" << endl; } pMax fp2 = (pMax)(GetProcAddress(hDll, funName2)); if (fp2 != NULL) { cout << "max value of 5 and 6:" << fp2(5, 6) << endl; } else { cout << "函数max加载失败" << endl; } pAdd fp3 = (pAdd)(GetProcAddress(hDll, funName3)); if (fp3 != NULL) { cout << "sum value of 5 and 6:" << fp3(5, 6) << endl; } else { cout << "函数add加载失败" << endl; } pSub fp4 = (pSub)(GetProcAddress(hDll, funName4)); if (fp2 != NULL) { cout << "difference of 5 and 6:" << fp4(5, 6) << endl; } else { cout << "函数sub加载失败" << endl; } FreeLibrary(hDll);//卸载dll,一般用完就卸载,避免占用内存 } else { cout << "加载dll文件失败" << endl; } system("pause"); return 0; }
从上述使用方法可以看出,因为我们之前创建dll文件的时候贴心地把导出的函数名设置了下,才可以在dumpbin中查看到比较有意义的函数名信息,所以如果第三方给的dll没有这么做,那么你就根据dump出来的函数名乱码猜吧,祝你好运。
-
显式链接的不足
DLLが唯一のインタフェース(APIヘッダー・ファイルまたは対応する文書)に与え、文字化けされた関数名をダンプない場合は明らかに、それはDLLを再利用されていません。推奨されていない1、少なくとも明示的なリンクのdllまた、輸出クラスと変数をサポートしていません。
4. A少しアドバイス
様々なオンラインチュートリアルを読んだ後、高度のdll再利用は、その後、我々は.hの使用する必要がある場合は、.libを、スリーピースの.dllをすることが推奨され、それは暗黙のリンク方式であります
それほど機能dllファイル構造が隠されているので、他のソリューションという、構造関数が使用されていないかわかりません
でも唯一確認するために場合によってdumbin.exeちんぷんかんぷん関数名のように見えますが、やっての特定の機能を理解することができないことを何か
すでにインターフェイスを知っている限り、このような暗黙のリンクとして、最初の文書に対応するDLLのソースコード、インターフェイスを公開するために、明らかな方法を使用します