動態鏈接庫DLL文件是c++學習中很重要的一點。DLL文件有很多的有點,可以被一個程序甚至多個程序調用,節省了內存,共享了資源。DLL庫不同於靜態庫,在靜態庫情況下,函數和數據被編譯進一個二進制文件(通常擴展名為*.LIB), Visual C++的編譯器在處理程序代碼時將從靜態庫中恢復這些函數和數據並把他們和應用程序中的其他模塊組合在一起生成可執行文件。這個過程稱為"靜態鏈接",此時因為應用程序所需的全部內容都是從庫中復制了出來,所以靜態庫本身並不需要與可執行文件一起發行。
在動態庫的情況下,有兩個文件,一個是引入庫(.LIB)文件,一個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數和數據並不復制到可執行文件中,因此在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當一個或多個應用程序運行是再把程序代碼和被調用的函數代碼鏈接起來,從而節省了內存資源。從上面的說明可以看出,DLL和.LIB文件必須隨應用程序一起發行,否則應用程序將會產生錯誤。
在菜單欄上,依次選擇“文件”、“新建”、“項目”。
在“新建項目”對話框的左窗格中,依次展開“已安裝”、“模板”、“Visual C++”,然後選擇“Win32”。
在中間窗格中,選擇“Win32 控制台應用程序”。
在“名稱”框中為項目指定名稱,例如 MathFuncsDll。在“解決方案名稱”框中為解決方案指定名稱,例如 DynamicLibrary。選擇“確定”按鈕。
在“Win32 應用程序向導”對話框的“概述”頁上,選擇“下一步”按鈕。
在“應用程序設置”頁面的“應用程序類型”下,選擇“DLL”。
選擇“完成”按鈕創建項目。
若要為新類創建頭文件,請在菜單欄上,依次選擇“項目”、“添加新項”。在“添加新項”對話框的左窗格中,在“Visual C++”下選擇“代碼”。在中間窗格中,選擇“頭文件(.h)”。為頭文件指定名稱(例如 MathFuncsLib.h),然後選擇“添加”按鈕。將顯示一個空白頭文件。
將以下代碼添加到頭文件的開頭:
C++ 復制// MathFuncsDll.h #ifdef MATHFUNCSDLL_EXPORTS #define MATHFUNCSDLL_API __declspec(dllexport) #else #define MATHFUNCSDLL_API __declspec(dllimport) #endif
添加一個名為 MyMathFuncs 的基類,以執行常見的算術運算(例如加、減、乘和除)。代碼應類似如下:
C++ 復制namespace MathFuncs { // This class is exported from the MathFuncsDll.dll class MyMathFuncs { public: // Returns a + b static MATHFUNCSDLL_API double Add(double a, double b); // Returns a - b static MATHFUNCSDLL_API double Subtract(double a, double b); // Returns a * b static MATHFUNCSDLL_API double Multiply(double a, double b); // Returns a / b // Throws const std::invalid_argument& if b is 0 static MATHFUNCSDLL_API double Divide(double a, double b); }; }
在此代碼中,當 MATHFUNCSDLL_EXPORTS 符號已經被定義時,成員函數聲明部分的 MATHFUNCSDLL_API 符號將被設置為 __declspec(dllexport) 修飾符。此修飾符使函數能作為 DLL 導出,以供其他應用程序調用。如果未定義 MATHFUNCSDLL_EXPORTS(例如,應用程序包含了頭文件),則 MATHFUNCSDLL_API 將定義成員函數聲明中的 __declspec(dllimport) 修飾符。此修飾符將優化在應用程序中導入該函數的操作。默認情況下,DLL 的“新建項目”模板會將 PROJECTNAME_EXPORTS 添加到 DLL 項目的已定義符號中。在本例中,生成 MathFuncsDll 項目後將定義 MATHFUNCSDLL_EXPORTS。有關詳細信息,請參閱aspx" target="_blank">dllexport、dllimport。
如果你要在命令行上生成 DLL 項目,請使用 /D 編譯器選項來定義 MATHFUNCSDLL_EXPORTS 符號。
在“解決方案資源管理器”的“MathFuncsDll”項目中,在“源文件”文件夾中打開 MathFuncsDll.cpp。
實現源文件中 MyMathFuncs 的功能。代碼應類似如下:
C++ 復制// MathFuncsDll.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "MathFuncsDll.h" #includeusing 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; } }
通過選擇菜單欄中的 生成>生成解決方案 編譯動態鏈接庫
如果使用的是不顯示“生成”菜單的 Express 版,請在菜單欄上,依次選擇“工具”、“設置”、“專家設置”來啟用它,然後依次選擇“生成”、“生成解決方案”。
如果在命令行中生成項目,請使用 /LD 編譯器選項指定輸出文件為 DLL。有關詳細信息,請參閱/MD、/MT、/LD(使用運行庫)。使用 /EHsc 編譯器選項啟用 C++ 異常處理。有關詳細信息,請參閱/EH(異常處理模型)。
為了創建一個項目引用你剛剛創建好的DLL,在菜單欄中選擇 文件>新建>項目。
在左窗格中的“Visual C++”下,選擇“Win32”。
在中間窗格中,選擇“Win32 控制台應用程序”。
在“名稱”框中為項目指定名稱,例如 MyExecRefsDll。在“解決方案”旁邊,從下拉列表中選擇“添加到解決方案”。這會將新項目添加到包含此 DLL 的同一解決方案中。選擇“確定”按鈕。
在“Win32 應用程序向導”對話框的“概述”頁上,選擇“下一步”按鈕。
在“應用程序設置”頁的“應用程序類型”下,選擇“控制台應用程序”。
在“應用程序設置”頁的“附加選項”下,清除“預編譯頭”復選框。
選擇“完成”按鈕創建項目。
在創建一個控制台應用程序後,一個空的程序已經為你創建好了。源文件的名稱與你之前選擇的名稱相同。在此示例中,其名稱為 MyExecRefsDll.cpp。
若要在應用中使用在 DLL 中創建的數學例程,必須對它進行引用。為此,請在 解決方案資源管理器 中選擇 MyExecRefsDll 項目,然後在菜單欄上,選擇 項目,引用。在“屬性頁”對話框中,展開“通用屬性”節點、選擇“框架和引用”,然後選擇“添加新引用”按鈕。有關“引用”對話框的更多信息,請參見在 Visual C++ 項目中添加引用。
“添加引用”對話框列出了可以引用的庫。“項目”選項卡列出了當前解決方案中的所有項目以及它們包含的所有庫。在“項目”選項卡上,選中“MathFuncsDll”旁邊的復選框,然後選擇“確定”按鈕。
若要引用 DLL 的頭文件,必須修改包含的目錄路徑。若要執行此操作,請在“屬性頁”對話框中,依次展開“配置屬性”節點和“C/C++”節點,然後選擇“常規”。在“附加包含目錄”旁邊,指定 MathFuncsDll.h 頭文件的位置路徑。你可以使用相對路徑(例如 ..\MathFuncsDll\),然後選擇“確定”按鈕。
現在即可在此應用程序中使用 MyMathFuncs 類。將 MyExecRefsDll.cpp 的內容替換為以下代碼:
C++ 復制// MyExecRefsDll.cpp // compile with: /EHsc /link MathFuncsDll.lib #include#include "MathFuncsDll.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; }
通過在菜單欄上依次選擇“生成”、“生成解決方案”來生成可執行文件。
請確保已將 MyExecRefsDll 選為默認項目。在“解決方案資源管理器”中,選擇 MyExecRefsDll,然後在菜單欄上,依次選擇“項目”、“設為啟動項目”。
若要運行項目,請在菜單欄上依次選擇“調試”、“開始執行(不調試)”。輸出應該與下面的內容類似:
a + b = 106.4 a - b = -91.6 a * b = 732.6 a / b = 0.0747475 捕獲到異常:b 不能為零!
同上,也可以在類名前添加 MATHFUNCSDLL_API 使類作為DLL導出。