本逐步解說說明如何使用 Visual Studio IDE 建立您自己的動態連結程式庫 (DLL) 以 Microsoft C++ (MSVC) 撰寫,以及如何從另一個 C++ 應用程式使用 DLL。 DLL 也稱為 UNIX 型作業系統中的 共用程式庫 ,是最有用的 Windows 元件類型之一。 您可以使用它們來共用程式碼和資源,以及縮小應用程式的大小。 DLL 甚至可以更輕鬆地維護和擴展您的應用程序。
在本步驟解說中,您會建立並實作一些數學函式的 DLL。 然後,您會建立使用 DLL 函式的主控台應用程式。 您也會瞭解 Windows DLL 中使用的一些程式設計技術和慣例。
本逐步解說涵蓋下列步驟:
- 在 Visual Studio 中建立 DLL 專案。
- 將匯出的函式和變數新增至 DLL。
- 在 Visual Studio 中建立主控台應用程式專案。
- 在主控台應用程式中使用從 DLL 匯入的函式和變數。
- 執行已完成的應用程式。
就像靜態連結的程式庫一樣,DLL 會依名稱匯 出 變數、函式和資源。 用戶端應用程式 會匯入 名稱以使用這些變數、函式和資源。 不同於靜態連結的程式庫,Windows 會在載入時或執行階段將應用程式中的匯入連線到 DLL 中的匯出,而不是在連結時連線它們。 Windows 需要不屬於標準 C++ 編譯模型的額外資訊,才能建立這些連線。 MSVC 編譯器會實作一些 Microsoft 特定的 C++ 延伸模組,以提供這項額外資訊。 我們會隨著進度解釋這些擴展。
本逐步解說會建立兩個 Visual Studio 解決方案:一個用於建置 DLL,另一個用於建置用戶端應用程式。 DLL 會使用 C 呼叫慣例。 它可以從其他程式語言編寫的應用程式呼叫,只要平台、呼叫約定和連結約定相符即可。 用戶端應用程式會使用 隱含連結,其中 Windows 會在載入時將應用程式連結至 DLL。 此連結可讓應用程式呼叫 DLL 提供的函式,就像靜態連結程式庫中的函式一樣。
本逐步解說未涵蓋一些常見情況。 程式碼不會顯示其他程式設計語言使用 C++ DLL。 它不顯示如何建立僅限資源的 DLL,或如何使用明確連結在執行階段加載 DLL,而不是在載入時。 請放心,您可以使用 MSVC 和 Visual Studio 來執行所有這些操作。
儘管 DLL 的代碼是用 C++ 編寫的,但我們對導出的函數使用 C 樣式的接口。 這主要有兩個原因:首先,許多其他語言都支援匯入C風格的函數。 用戶端應用程式不需要以 C++ 撰寫。 其次,它避免了一些與匯出類別和成員函數相關的常見陷阱。 匯出類別時很容易犯出難以診斷的錯誤,因為類別宣告中引用的所有內容都必須具有匯出的實例化。 此限制適用於 DLL,但不適用於靜態程式庫。 如果您的類別是純舊資料樣式,則不應遇到此問題。
如需 DLL 詳細資訊的連結,請參閱 在 Visual Studio 中建立 C/C++ DLL。 如需隱含連結和明確連結的詳細資訊,請參閱 判斷要使用的連結方法。 如需建立 C++ DLL 以搭配使用 C 語言連結慣例的程式設計語言的相關資訊,請參閱 匯出 C++ 函式以用於 C 語言可執行檔。 如需如何建立 DLL 以搭配 .NET 語言使用的相關資訊,請參閱 從 Visual Basic 應用程式呼叫 DLL 函式。
先決條件
- Microsoft Windows 7 或更高版本。 建議您使用最新版本的 Windows,以獲得最佳的開發體驗。
Visual Studio。 若要瞭解如何下載和安裝 Visual Studio,請參閱 安裝 Visual Studio。 當您執行安裝程式時,請確定已核取 [ 使用 C++ 進行桌面開發 ] 工作負載。 如果您在安裝 Visual Studio 時未安裝此工作負載,請不要擔心。 您可以再次運行安裝程序並立即安裝。
- Visual Studio。 如需如何下載和安裝 Visual Studio 2015 的資訊,請參閱 安裝 Visual Studio 2015。 使用 自訂 安裝來安裝 C++ 編譯器和工具,因為預設不會安裝它們。
瞭解使用 Visual Studio IDE 的基本概念。 如果您以前使用過 Windows 傳統型應用程序,您可能可以跟上。 如需簡介,請參閱 Visual Studio IDE 功能導覽。
對 C++ 語言有一定的熟悉程度。 別擔心,我們不會做任何太複雜的事情。
備註
本逐步解說假設您使用的是 Visual Studio 2017 15.9 版或更新版本。 某些舊版的 Visual Studio 2017 在程式碼範本中存在缺陷,或使用不同的使用者介面對話方塊。 若要避免問題,請使用 Visual Studio 安裝程式將 Visual Studio 2017 更新至 15.9 版或更新版本。
建立 DLL 專案
在下列一組工作中,您可以建立 DLL 的專案、新增程式碼,並建置它。 若要開始,請啟動 Visual Studio IDE,並視需要登入。 這些指示會因您使用的 Visual Studio 版本而略有不同。 若要查看您慣用的 Visual Studio 版本的步驟,請使用位於此頁面目錄頂端的 [版本 ] 選取器。
在 Visual Studio 中建立 DLL 專案
在功能表列上,選擇 [檔案]>[新增]>[專案],以開啟 [建立新專案] 對話方塊。
在對話方塊頂端,將 [語言] 設定為 C++,將 [平臺] 設定為 Windows,並將 [專案類型] 設定為 [程式庫]。
從篩選的專案類型清單中,選取 [動態連結程式庫 (DLL)],然後選擇 [ 下一步]。
在「設定您的新專案」頁面中,在「專案名稱」方塊中輸入 MathLibrary,以指定專案的名稱。 保留預設的 [位置] 和 [解決方案名稱] 值。 將 解決方案 設定為 建立新解決方案。 如果已勾選 [將解決方案和專案放在相同的目錄中] ,請取消勾選。
選擇 [建立] 按鈕以建立專案。
建立解決方案時,您可以在 Visual Studio 的 [方案總管 ] 視窗中看到產生的專案和來源檔案。
在 Visual Studio 2017 中建立 DLL 專案
在功能表列上,選擇 [檔案]> [新增]> [專案],以開啟 [新增專案] 對話方塊。
在 [ 新增專案 ] 對話方塊的左窗格中,選取 [已安裝的>Visual C++>Windows 桌面]。 在中央窗格中,選取 [ Dynamic-Link 程式庫 (DLL)]。 在「名稱」方塊中輸入 MathLibrary,以指定專案的名稱。 保留預設的 [位置] 和 [解決方案名稱] 值。 將 解決方案 設為 建立新解決方案。 如果未核取,請勾選 [建立目錄以取得解決方案 ]。
選擇 [確定 ] 按鈕以建立專案。
建立解決方案時,您可以在 Visual Studio 的 [方案總管 ] 視窗中看到產生的專案和來源檔案。
在 Visual Studio 2015 和舊版中建立 DLL 專案
在功能表列上,選擇 [檔案]>[新增]>[專案]。
在 [ 新增專案 ] 對話方塊的左窗格中,展開 [已安裝>的範本],然後選取 [Visual C++],然後在中央窗格中選取 [Win32 主控台應用程式]。 在「名稱」編輯方塊中輸入 MathLibrary,以指定專案的名稱。 保留預設的 [位置] 和 [解決方案名稱] 值。 設置 解決方案 為 新建解決方案。 如果未勾選,請勾選[建立解決方案的目錄]。
選擇 [確定 ] 按鈕以關閉 [ 新增專案 ] 對話方塊,並啟動 Win32 應用程式精靈。
選擇 [下一步] 按鈕。 在 [ 應用程式設定 ] 頁面的 [ 應用程式類型] 底下,選取 [DLL]。
選擇 Finish 按鈕 以建立專案。
精靈完成解決方案時,您可以在 Visual Studio 的 [方案總管 ] 視窗中看到產生的專案和來源檔案。
目前,這個 DLL 並沒有做太多事情。 接下來,您將建立標頭檔來宣告 DLL 匯出的函式,然後將函式定義新增至 DLL 以使其更有用。
將標頭檔新增至 DLL
若要建立函式的標頭檔,請在功能表列上選擇 [專案>新增項目]。
在 [新增專案] 對話方塊的左窗格中,選取 [Visual C++]。 在中央窗格中,選取 [標頭檔 (.h)]。 指定
MathLibrary.h為標頭檔的名稱。
選擇 [新增 ] 按鈕以產生空白標頭檔,該檔會顯示在新的編輯器視窗中。
將標頭檔的內容替換為以下程式碼:
// MathLibrary.h - Contains declarations of math functions #pragma once #ifdef MATHLIBRARY_EXPORTS #define MATHLIBRARY_API __declspec(dllexport) #else #define MATHLIBRARY_API __declspec(dllimport) #endif // The Fibonacci recurrence relation describes a sequence F // where F(n) is { n = 0, a // { n = 1, b // { n > 1, F(n-2) + F(n-1) // for some initial integral values a and b. // If the sequence is initialized F(0) = 1, F(1) = 1, // then this relation produces the well-known Fibonacci // sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. extern "C" MATHLIBRARY_API void fibonacci_init( const unsigned long long a, const unsigned long long b); // Produce the next value in the sequence. // Returns true on success and updates current value and index; // false on overflow, leaves current value and index unchanged. extern "C" MATHLIBRARY_API bool fibonacci_next(); // Get the current value in the sequence. extern "C" MATHLIBRARY_API unsigned long long fibonacci_current(); // Get the position of the current value in the sequence. extern "C" MATHLIBRARY_API unsigned fibonacci_index();
此標頭檔宣告一些函式,以產生廣義斐波那契數列,給定兩個起始值。 使用 fibonacci_init(1, 1) 的呼叫會生成大家熟悉的斐波那契數列。
請注意檔案頂端的預處理器陳述式。 DLL 專案的新專案範本會將 <PROJECTNAME>_EXPORTS 新增到已定義的前置處理器宏中。 在此範例中,Visual Studio 會 MATHLIBRARY_EXPORTS 定義建置 MathLibrary DLL 專案的時間。
MATHLIBRARY_EXPORTS 巨集定義後,MATHLIBRARY_API 巨集會在函數宣告上設定 __declspec(dllexport) 修飾符。 此修飾符會告知編譯器和連結器從 DLL 匯出函式或變數,以供其他應用程式使用。 當 MATHLIBRARY_EXPORTS 未定義時,例如,當用戶端應用程式包含標頭檔案時,MATHLIBRARY_API 會將 __declspec(dllimport) 修飾元套用到宣告中。 此修飾元可最佳化應用程式中函式或變數的匯入。 如需詳細資訊,請參閱 dllexport、dllimport。
將一個實作新增至 DLL
在 [方案總管] 中,以滑鼠右鍵按一下 [來源檔案 ] 節點,然後選擇 [ 新增>專案]。 建立名為
.cpp的新檔案MathLibrary.cpp,其方式與您在上一個步驟中新增標頭檔的方式相同。在編輯器視窗中,選取索引
MathLibrary.cpp標籤(如果已開啟)。 如果沒有,請在 [方案總管] 中,按兩下MathLibrary.cppMathLibrary 專案的 [來源檔案] 資料夾以開啟它。在編輯器中,將檔案的內容
MathLibrary.cpp取代為下列程式碼:// MathLibrary.cpp : Defines the exported functions for the DLL. #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier #include <utility> #include <limits.h> #include "MathLibrary.h" // DLL internal state variables: static unsigned long long previous_; // Previous value, if any static unsigned long long current_; // Current sequence value static unsigned index_; // Current seq. position // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. void fibonacci_init( const unsigned long long a, const unsigned long long b) { index_ = 0; current_ = a; previous_ = b; // see special case when initialized } // Produce the next value in the sequence. // Returns true on success, false on overflow. bool fibonacci_next() { // check to see if we'd overflow result or position if ((ULLONG_MAX - previous_ < current_) || (UINT_MAX == index_)) { return false; } // Special case when index == 0, just return b value if (index_ > 0) { // otherwise, calculate next sequence value previous_ += current_; } std::swap(current_, previous_); ++index_; return true; } // Get the current value in the sequence. unsigned long long fibonacci_current() { return current_; } // Get the current index position in the sequence. unsigned fibonacci_index() { return index_; }
在編輯器視窗中,如果已開啟MathLibrary.cpp,請選取該索引標籤。 如果沒有,請在 [方案總管] 中,按兩下 MathLibrary 專案的 [來源檔案] 資料夾中的 MathLibrary.cpp以開啟它。
在編輯器中,將檔案的內容
MathLibrary.cpp取代為下列程式碼:// MathLibrary.cpp : Defines the exported functions for the DLL. #include "stdafx.h" // use pch.h in Visual Studio 2019 and later #include <utility> #include <limits.h> #include "MathLibrary.h" // DLL internal state variables: static unsigned long long previous_; // Previous value, if any static unsigned long long current_; // Current sequence value static unsigned index_; // Current seq. position // Initialize a Fibonacci relation sequence // such that F(0) = a, F(1) = b. // This function must be called before any other function. void fibonacci_init( const unsigned long long a, const unsigned long long b) { index_ = 0; current_ = a; previous_ = b; // see special case when initialized } // Produce the next value in the sequence. // Returns true on success, false on overflow. bool fibonacci_next() { // check to see if we'd overflow result or position if ((ULLONG_MAX - previous_ < current_) || (UINT_MAX == index_)) { return false; } // Special case when index == 0, just return b value if (index_ > 0) { // otherwise, calculate next sequence value previous_ += current_; } std::swap(current_, previous_); ++index_; return true; } // Get the current value in the sequence. unsigned long long fibonacci_current() { return current_; } // Get the current index position in the sequence. unsigned fibonacci_index() { return index_; }
若要確認到目前為止一切正常,請編譯 DLL。 若要編譯,請選擇功能表列上的 建置>建置解決方案 。 DLL 和相關編譯器輸出會放在解決方案資料夾正下方呼叫的 Debug 資料夾中。 如果您建立發行組建,輸出會放在名為 Release的資料夾中。 輸出應如下所示:
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>stdafx.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>MathLibrary.cpp
1>dllmain.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.pdb (Partial PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
恭喜,您已使用 Visual Studio 建立 DLL! 接下來,您將建立使用 DLL 匯出函式的用戶端應用程式。
建立使用 DLL 的用戶端應用程式
當您建立 DLL 時,請考慮用戶端應用程式如何使用它。 若要呼叫函式或存取 DLL 匯出的資料,用戶端原始程式碼必須在編譯階段具有可用的宣告。 在連結時,連結器需要資訊來解析函式呼叫或資料存取。 DLL 會在 匯入程式庫中提供這項資訊,此檔案包含如何尋找函式和資料的相關資訊,而不是實際程式碼。 在執行階段,DLL 必須可供用戶端使用,位於作業系統可以找到的位置。
無論是您自己的還是來自協力廠商的,您的用戶端應用程式專案都需要數個資訊才能使用 DLL。 它必須尋找宣告 DLL 匯出的標頭、連結器的匯入程式庫,以及 DLL 本身。 其中一個解決方案是將所有這些檔案複製到您的用戶端專案中。 對於用戶端在開發期間不太可能變更的第三方 DLL,這個方法可能是使用它們的最佳方式。 不過,當您也建置 DLL 時,最好避免重複。 如果您建立開發中 DLL 檔案的本機複本,您可能會不小心變更一個複本中的標頭檔,但不會變更另一個複本中的標頭檔,或使用過期的程式庫。
若要避免不同步的程式碼,建議您在用戶端專案中設定包含路徑,以直接從 DLL 專案包含 DLL 標頭檔。 此外,在用戶端專案中設定程式庫路徑,以包含來自 DLL 專案的 DLL 匯入程式庫。 最後,將建置的 DLL 從 DLL 專案複製到用戶端建置輸出目錄中。 此步驟可讓您的用戶端應用程式使用您建置的相同 DLL 程式碼。
在 Visual Studio 中建立用戶端應用程式
在功能表列上,選擇 [ 檔案>新>專案 ] 以開啟 [ 建立新專案 ] 對話方塊。
在對話方塊頂端,將 [語言] 設定為 C++,將 [平台] 設定為 Windows,並將 [專案類型] 設定為主控台。
從專案類型的篩選清單中,選擇 [主控台應用程式],然後選擇 [下一步]。
在 [設定您的新專案] 頁面中,在 [專案名稱] 方塊中輸入 MathClient 以指定專案的名稱。 保留預設的 [位置] 和 [解決方案名稱] 值。 設置 解決方案 為 新建解決方案。 如果已勾選 [將解決方案和專案放在相同的目錄中] ,請取消勾選。
選擇 [建立] 按鈕以建立用戶端專案。
系統會為您建立最小的主控台應用程式專案。 主要來源檔案的名稱與您先前輸入的專案名稱相同。 在此範例中,它名為 MathClient.cpp。 您可以構建它,但它還沒有使用您的 DLL。
在 Visual Studio 2017 中建立用戶端應用程式
若要建立使用您建立之 DLL 的 C++ 應用程式,請在功能表列上選擇 [ 檔案>新增>專案]。
在 [新增專案] 對話方塊的左窗格中,選取 [已安裝的Visual C++] > 底下的 [Windows 桌面]。 在中央窗格中,選取 [Windows 主控台應用程式]。 在 [名稱] 編輯方塊中指定專案的名稱 MathClient。 保留預設的 [位置] 和 [解決方案名稱] 值。 設置 解決方案 為 新建解決方案。 如果未勾選,請勾選[建立解決方案的目錄]。
選擇 [確定 ] 以建立用戶端應用程式專案。
系統會為您建立最小的主控台應用程式專案。 主要來源檔案的名稱與您先前輸入的專案名稱相同。 在此範例中,它名為 MathClient.cpp。 您可以構建它,但它還沒有使用您的 DLL。
在 Visual Studio 2015 中建立用戶端應用程式
若要建立使用您建立之 DLL 的 C++ 應用程式,請在功能表列上選擇 [ 檔案>新增>專案]。
在 [新增專案] 對話方塊的左窗格中,選取 [已安裝>>] 底下的 [Win32]。 在中央窗格中,選取 [Win32 主控台應用程式]。 在 [名稱] 編輯方塊中指定專案的名稱 MathClient。 保留預設的 [位置] 和 [解決方案名稱] 值。 設置 解決方案 為 新建解決方案。 如果未勾選,請勾選[建立解決方案的目錄]。
選擇 [確定 ] 按鈕以關閉 [ 新增專案 ] 對話方塊,並啟動 Win32 應用程式精靈。 在 Win32 應用程式精靈對話方塊的 [概觀] 頁面上,選擇 [下一步] 按鈕。
在 [ 應用程式設定 ] 頁面的 [ 應用程式類型] 底下,選取 [主控台應用程式] (如果尚未選取)。
選擇 Finish 按鈕 以建立專案。
精靈完成時,會為您建立最小的主控台應用程式專案。 主要來源檔案的名稱與您先前輸入的專案名稱相同。 在此範例中,它名為 MathClient.cpp。 您可以構建它,但它還沒有使用您的 DLL。
接下來,若要在原始程式碼中呼叫 MathLibrary 函數,您的專案必須包含該 MathLibrary.h 檔案。 您可以將此標頭檔複製到用戶端應用程式專案中,然後將它以現有項目的方式新增到專案中。 這種方法對於第三方函式庫來說可能是一個不錯的選擇。 不過,如果您同時處理 DLL 和用戶端的程式碼,標頭檔可能會不同步。若要避免此問題,請在專案中設定 其他包含目錄 路徑,以包含原始標頭的路徑。
若要將 DLL 標頭檔新增至您的包含路徑中
以滑鼠右鍵按兩下 [方案總管] 中的 MathClient 節點,以開啟 [屬性頁] 對話方塊。
在 設定 下拉選單中,如果尚未選取,請選擇 全部設定。
在左窗格中,選取 [組態屬性] [>C/C++>General]。
在屬性窗格中,選取 [其他包含目錄 ] 編輯方塊旁的下拉式控制項,然後選擇 [編輯]。
按兩下 [ 其他包含目錄 ] 對話方塊的頂端窗格,以啟用編輯控制項。 或者,選擇資料夾圖示以建立新項目。
在編輯控制項中,指定指向
MathLibrary.h標頭檔案位置的路徑。 您可以選擇省略符號 (...) 控制項,以瀏覽至正確的資料夾。您也可以輸入從用戶端來源檔案到包含 DLL 標頭檔的資料夾的相對路徑。 如果您遵循指示將用戶端專案放在與 DLL 不同的解決方案中,相對路徑應該如下所示:
..\..\MathLibrary\MathLibrary如果您的 DLL 和用戶端專案位於相同的解決方案中,相對路徑可能如下所示:
..\MathLibrary當 DLL 和用戶端專案位於其他資料夾中時,請調整相對路徑以相符。 或者,使用省略符號控制項來瀏覽資料夾。
在 [其他包含目錄 ] 對話方塊中輸入標頭檔的路徑之後,請選擇 [ 確定 ] 按鈕。 在 [屬性頁面 ] 對話方塊中,選擇 [ 確定 ] 按鈕以儲存變更。
您現在可以包含檔案 MathLibrary.h ,並在用戶端應用程式中使用其宣告的函式。 使用以下程式碼替換MathClient.cpp的內容:
// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"
int main()
{
// Initialize a Fibonacci relation sequence.
fibonacci_init(1, 1);
// Write out the sequence values until overflow.
do {
std::cout << fibonacci_index() << ": "
<< fibonacci_current() << std::endl;
} while (fibonacci_next());
// Report count of values written before overflow.
std::cout << fibonacci_index() + 1 <<
" Fibonacci sequence values fit in an " <<
"unsigned 64-bit integer." << std::endl;
}
此程式碼可以編譯,但不能連結。 如果您現在建置用戶端應用程式,錯誤清單會顯示數個LNK2019錯誤。 這是因為您的專案缺少一些資訊:您尚未指定您的專案對程式庫具有 MathLibrary.lib 相依性。 而且,您尚未告訴連結器如何尋找 MathLibrary.lib 檔案。
若要修正此問題,您可以將程式庫檔案直接複製到用戶端應用程式專案中。 連結器會自動尋找並使用它。 不過,如果程式庫和用戶端應用程式都在開發中,則可能會導致一個複本的變更未顯示在另一個複本中。 若要避免此問題,您可以設定 [其他相依性 ] 屬性,以告知專案相依 MathLibrary.lib的建置系統。 此外,您可以在專案中設定「 其他資料庫目錄」 路徑,以便在連結時包含原始資料庫的路徑。
將 DLL 匯入程式庫新增至您的專案
以滑鼠右鍵按一下 [方案總管] 中的 MathClient 節點,然後選擇 [屬性] 以開啟 [屬性頁] 對話方塊。
在 設定 下拉選單中,如果尚未選取,請選擇 全部設定。 它可確保任何屬性變更都會套用至偵錯和發行組建。
在左窗格中,選取 [組態屬性] [>連結器>輸入]。 在屬性窗格中,選取 [其他相依性 ] 編輯方塊旁的下拉式控制項,然後選擇 [編輯]。
在 「其他相依性」 對話方塊中,將
MathLibrary.lib新增到頂端編輯控制項中的清單。
選擇 [ 確定 ] 以返回 [屬性頁 ] 對話方塊。
在左窗格中,選取 [組態屬性] [>連結器>] [一般]。 在屬性窗格中,選取 [其他程式庫目錄 ] 編輯方塊旁的下拉式控制項,然後選擇 [編輯]。
按兩下 [其他文件庫目錄 ] 對話方塊的頂端窗格,以啟用編輯控制項。 在編輯控制項中,指定檔案位置
MathLibrary.lib的路徑。 根據預設,它位於 DLL 解決方案資料夾正下方名為 Debug 的資料夾中。 如果您建立發行組建,則檔案會放置在名為 Release 的資料夾中。 您可以使用$(IntDir)巨集,使連結器可以找到您的 DLL,無論您建立何種建置類型。 如果您遵循指示將用戶端專案放在與 DLL 專案不同的解決方案中,相對路徑應該如下所示:..\..\MathLibrary\$(IntDir)如果您的 DLL 和用戶端專案位於其他位置,請調整相對路徑以相符。
在 [其他文件庫目錄 ] 對話方塊中輸入文件庫文件的路徑後,選擇 [ 確定 ] 按鈕以返回 [屬性頁 ] 對話框。 選擇 [確定 ] 以儲存屬性變更。
您的用戶端應用程式現在可以成功編譯和連結,但它仍然沒有執行所需的一切。 當作業系統載入您的應用程式時,它會尋找 MathLibrary DLL。 如果在某些系統目錄、環境路徑或本機應用程式目錄中找不到 DLL,則載入會失敗。 視作業系統而定,您會看到如下錯誤訊息:
避免此問題的其中一種方法是將 DLL 複製到包含用戶端可執行檔的目錄,作為建置程式的一部分。 您可以將 建置後事件 新增至專案,以新增將 DLL 複製到建置輸出目錄的命令。 此處指定的命令只有在遺失或已變更時才會複製 DLL。 它會使用巨集,根據您的建置配置,複製到調試或發布位置。
在建置後事件中複製 DLL
以滑鼠右鍵按一下 [方案總管] 中的 MathClient 節點,然後選擇 [屬性] 以開啟 [屬性頁] 對話方塊。
在 配置 下拉式方塊中,如果尚未選取,請選取 所有配置。
在左窗格中,選取 [組態屬性]>[建置事件]> [建置後事件]。
在屬性窗格中,選取 [命令列] 欄位中的編輯控制項。 如果您遵循指示將用戶端專案放入與 DLL 專案不同的解決方案中,請輸入下列命令:
xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"如果您的 DLL 和用戶端專案位於其他目錄中,請變更 DLL 的相對路徑以相符。
選擇 [確定 ] 按鈕以儲存對專案屬性的變更。
現在,您的用戶端應用程式擁有建置和執行所需的一切。 選擇功能表列上的 建置>建置解決方案 ,以建置應用程式。 Visual Studio 中的 [輸出] 視窗應該具有類似下列範例的內容,視您的 Visual Studio 版本而定:
1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
恭喜,您已建立一個可呼叫您 DLL 中函式的應用程式。 現在運行您的應用程序以查看它的作用。 在功能表列上,選擇 Debug>Start Without Debugging (不偵錯啟動)。 Visual Studio 會開啟要執行程式的命令視窗。 輸出的最後一部分應該如下所示:
按任意鍵關閉命令視窗。
現在您已經建立了 DLL 和用戶端應用程式,您可以進行實驗。 嘗試在用戶端應用程式的程式碼中設定中斷點,並在偵錯工具中執行應用程式。 看看當您進入圖書館通話時會發生什麼。 將其他函式新增至程式庫,或撰寫其他使用 DLL 的用戶端應用程式。
當您部署應用程式時,您也必須部署其使用的 DLL。 若要讓您建置的 DLL 或從第三方包含的 DLL 可供使用,最簡單的方式是將它們放在與應用程式相同的目錄中。 這稱為 應用程式本機部署。 如需部署的詳細資訊,請參閱 Microsoft C++ 中的部署。