如何創建一個動態鏈接庫DLL

在本演練中,您將創建一個動態鏈接庫 (DLL),其中包含可供其他應用程序使用的有用例程。使用 DLL 是一種重用代碼的絕佳方式。您不必在自己創建的每個程序中重新實現這些例程,而只需對這些例程編寫一次,然後從需要該功能的應用程序引用它們即可。

本演練使用本機 C++。有關使用本機 C++ 創建靜態庫的演練,請參見 演練:創建和使用靜態庫。有關使用面向公共語言運行庫的 Visual C++ 的演練,請參見演練:創建和使用託管程序集

本演練涵蓋以下內容:

  • 創建新的動態鏈接庫 (DLL) 項目

  • 向動態鏈接庫添加類

  • 創建引用動態鏈接庫的應用程序

  • 在控制檯應用程序中使用類庫的功能

  • 運行應用程序

本主題假定您具備 C++ 語言的基礎知識。

創建新的動態鏈接庫 (DLL) 項目

  1. 從“文件”菜單中,選擇“新建”,然後選擇“項目…”。

  2. 從“項目類型”窗格中選擇“Visual C++”下的“Win32”。

  3. 從“模板”窗格中,選擇“Win32 控制檯應用程序”。

  4. 爲項目選擇一個名稱,如MathFuncsDll,並將其輸入“名稱”字段。爲解決方案選擇一個名稱,如“DynamicLibrary”,並將其輸入“解決方案名稱”字段。

  5. 按“確定”啓動 Win32 應用程序嚮導。在“Win32 應用程序嚮導”對話框的“概述”頁中,按“下一步”。

  6. 從“Win32 應用程序嚮導”中的“應用程序設置”頁中,選擇“應用程序類型”下的“DLL”(如果可用),或者選擇“控制檯應用程序”(如果“DLL”不可用)。某些版本的 Visual Studio 不支持使用嚮導創建 DLL 項目。您可以稍後對此進行更改,以將項目編譯爲 DLL。

  7. 從“Win32 應用程序嚮導”的“應用程序設置”頁中,選擇“附加選項”下的“空項目”。

  8. 按“完成”創建項目。

向動態鏈接庫添加類

  1. 若要爲新類創建頭文件,請從“項目“右鍵菜單中選擇“添加新項…”。將顯示“添加新項”對話框。從“類別”窗格中,選擇“Visual C++”下的“代碼”。從“模板”窗格中,選擇“頭文件(.h)”。爲頭文件選擇一個名稱,如MathFuncsDll.h,並按“添加”。將顯示一個空白文件。

  2. 添加一個名爲“MyMathFuncs”的簡單類,以執行常見的算術運算,如加、減、乘和除。代碼應與以下內容類似:

    // MathFuncsDll.h

    namespace MathFuncs
    {
        class MyMathFuncs
        {
        public:
            // Returns a + b
            static __declspec(dllexport) double Add(double a, double b);

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

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

            // Returns a / b
            // Throws DivideByZeroException if b is 0
            static __declspec(dllexport) double Divide(double a, double b);
        };
    }
  3. 請注意上面的方法聲明中的 __declspec(dllexport) 修飾符。這些修飾符使 DLL 能夠導出該方法以供其他應用程序使用。有關更多信息,請參見 dllexport, dllimport

  4. 若要爲新類創建源文件,請從“項目”菜單中選擇“添加新項…”。將顯示“添加新項”對話框。從“類別”窗格中,選擇“Visual C++”下的“代碼”。從“模板”窗格中,選擇“C++ 文件(.cpp)”。爲源文件選擇一個名稱,如MathFuncsDll.cpp,並按“添加”。將顯示一個空白文件。

  5. 在源文件中實現“MyMathFuncs”的功能。代碼應與以下內容類似:

    // MathFuncsDll.cpp
    // compile with: /EHsc /LD

    #include "MathFuncsDll.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 new invalid_argument("b cannot be zero!");
            }

            return a / b;
        }
    }
  6. 若要將項目生成爲 DLL,請從“項目”菜單中選擇“MathFuncsDll,再選擇“屬性…”。從左窗格中,選擇“配置屬性”下的“常規”。從右窗格中,將“配置類型”更改爲“動態庫(.dll)”。按“確定”保存更改。默認的就是DLL類型

    Note注意

    如果是從命令行生成,請使用 /LD 編譯器選項指定輸出文件應爲 DLL。有關更多信息,請參見 /MD、/MT、/LD(使用運行時庫)

  7. 編譯該動態鏈接庫,方法是選擇“生成”菜單中的“生成解決方案”。會在解決方案的文件/Debug目錄下生成.dll文件,我的是C:\Users\Administrator\Desktop\MathFuncsDll\Debug這樣就創建了一個可供其他程序使用的 DLL。有關 DLL 的更多信息,請參見 DLL

創建引用動態鏈接庫的應用程序

  1. 若要創建引用並使用剛剛創建的動態鏈接庫的應用程序,請從“文件”菜單中選擇“新建”,然後選擇“項目…”。

  2. 從“項目類型”窗格中,選擇“Visual C++”下的“Win32”。

  3. 從“模板”窗格中,選擇“Win32 控制檯應用程序”。

  4. 爲項目選擇一個名稱,如“MyExecRefsDll”並將其輸入“名稱”字段。從“解決方案”旁邊的下拉列表中選擇“添入解決方案”。這會將新項目添加到該動態鏈接庫所屬的同一個解決方案中。

  5. 按“確定”啓動“Win32 應用程序嚮導”。在“Win32 應用程序嚮導”對話框的“概述”頁中,按“下一步”。

  6. 從“Win32 應用程序嚮導”的“應用程序設置”頁中,選擇“應用程序類型”下的“控制檯應用程序”。

  7. 從“Win32 應用程序嚮導”的“應用程序設置”頁中,取消選擇“附加選項”下的“預編譯頭”。

  8. 按“完成”創建項目。

在控制檯應用程序中使用類庫的功能

  1. 創建新的控制檯應用程序後,將爲您創建一個空程序。源文件的名稱與您在前面爲項目選擇的名稱相同。在本示例中,名爲“MyExecRefsDll.cpp”

  2. 若要使用在動態鏈接庫中創建的算術例程,必須引用該動態鏈接庫。爲此,請選擇“項目”右鍵菜單中的“引用…”。在“屬性頁”對話框中,展開“通用屬性”節點,並選擇“引用”。然後選擇“添加新引用…”按鈕。有關“引用…”對話框的更多信息,請參見 “<Projectname> 屬性頁”對話框 ->“通用屬性”->“引用”

  3. 將顯示“添加引用”對話框。此對話框列出了所有可以引用的庫。“項目”選項卡列出了當前解決方案中的所有項目,以及它們包含的所有庫。從“項目”選項卡中,選擇“MathFuncsDll”然後選擇“確定”。有關“添加引用”對話框的更多信息,請參見 “添加引用”對話框

  4. 若要引用動態鏈接庫的頭文件,必須修改包含目錄路徑。爲此,請在“屬性頁”對話框中,展開“配置屬性”節點,然後展開“C/C++”節點,並選擇“常規”。在“附加包含目錄”旁邊,鍵入“MathFuncsDll.h”頭文件所在的位置的路徑。我的是C:\Users\Administrator\Desktop\MathFuncsDll\MathFuncsDll

  5. 動態鏈接庫僅在運行時由可執行文件加載。必須告訴系統在哪裏查找“MathFuncsDll.dll”。這是使用 PATH 環境變量實現的。爲此,請在“屬性頁”對話框中,展開“配置屬性”節點,並選擇“調試”。“環境”旁邊,鍵入以下內容:PATH=<path to MathFuncsDll.dll file>,其中 <path to MathFuncsDll.dll file> 應替換爲“MathFuncsDll.dll”的實際位置。我的是C:\Users\Administrator\Desktop\MathFuncsDll\Debug  按“確定”保存進行的所有更改。

    Note注意

    如果要從命令行而不是從 Visual Studio 內運行可執行文件,必須從命令提示處手動更新 PATH 環境變量,如下所示:set PATH=%PATH%;<path to MathFuncsDll.dll file>,其中 <path to MathFuncsDll.dll file> 應替換爲“MathFuncsDll.dll”的實際位置。

  6. 現在,可以在應用程序中使用“MyMathFuncs”類了。使用以下代碼替換“MyExecRefsDll.cpp”的內容:

    // MyExecRefsDll.cpp
    // compile with: /EHsc /link MathFuncsDll.lib
    
    #include <iostream>
    
    #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;
    
        return 0;
    }
  7. 通過從“生成”菜單中選擇“生成解決方案”,生成可執行文件。

    8.解決MSVCP90D.dll無法找到問題 :

    VS 2005在生成可執行文件時使用了一種新的技術,該技術生成的可執行文件會伴隨生成一個清單文件(manifest file)(.manifest後綴文件)(其本質上是XML文檔,你可以用文本編輯器打開看看),並在鏈接完成後將該清單文件嵌入到exe文件中(默認情況下)。而在FAT32文件系統中,在處理清單文件階段,當增量鏈接時不能完成清單文件的更新(默認情況下),於是造成清單文件嵌入失敗,從而使該exe文件運行時沒有相應的清單文件而運行失敗並提示如上錯誤

    解決方案很多,列舉如下:
    1. 由於這是在鏈接動態運行庫出現的問題,所以你可以選擇代碼生成的連接方式爲/MTd而非/MDd,不用這些DLL文件從而避免問題的出現。該方法有一個很顯然的缺點:適用範圍有限,並且也不是我等提倡的解決問題的方式,不推薦該方法。

    2. 既然跟FAT32系統有關,那麼我們可以選擇在NTFS文件系統中開發從而避免該問題,此方法同上,也是採用的迴避問題的方式,不爲我等提倡。

    3. 該方法仍與FAT32有關:在項目的“屬性|配置屬性|清單工具|常規”中的“使用FAT32解決辦法”選擇“是”(默認爲“否”),重新生成項目即可解決問題。該方法是唯一真正針對問題所在而提出的解決方法,使清單工具可以正確更新。(此方法是官方解決方法,也比較方便,推薦)

    4. 既然問題是在更新嵌入的清單文件時發生的,由於FAT32的原因而未能更新嵌入的清單文件,於是我們有如下兩種解決方法:
    (1)不啓用增量鏈接。在項目的“屬性|配置屬性|鏈接器|常規”中的“啓用增量鏈接”選擇“否”。此方法阻斷了問題產生的源頭,其每次生成exe文件時都直接嵌入清單文件,而不是默認的根據時戳而決定是否更新清單文件。
    (2)不嵌入清單文件。在項目的“屬性|配置屬性|清單工具|輸入和輸出”中的“嵌入清單”選擇“否”,從而在生成exe文件時附隨生成一個清單文件(默認情況下,其文件名爲exe文件的全名加上“.manifest”),避免了嵌入清單文件可能失敗的問題。在程序運行時,會用到該清單文件。顯然,這種方式使可執行程序產生了更多的外部依賴,不推薦。

    另外,還有一個不能稱爲方法的土辦法:每次Build前手動刪除*.ilk文件(增量鏈接文件)(當然可以在項目屬性中寫入刪除命令,使其自動執行),不推薦該土辦法。

    最後,總結一下:
    1. 此問題只在特定條件下才會出現:在FAT32文件系統中編譯、默認設置(增量模式、不啓用FAT32解決方案、嵌入清單文件)、非第一次生成可執行文件文件(即在增量連接、更新清單文件時)。
    2. 解決方案1和4.1方便實用,推薦使用。

    9.運行應用程序

  1. 確保選擇“MyExecRefsDll”作爲默認項目。從“解決方案資源管理器”中,選擇“MyExecRefsDll”,然後選擇“項目”菜單中的“設爲啓動項目”。

  2. 若要運行項目,請選擇“調試”菜單中的“開始執行(不調試)”。輸出應如下所示:

    a + b = 106.4
    a - b = -91.6
    a * b = 732.6
    a / b = 0.0747475
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章