轉載:https://blog.csdn.net/w_x_myself/article/details/82252646
1.dll的特點
代碼復用是提高軟件開發效率的重要途徑。一般而言,只要某部分代碼具有通用性,就可將它構造成相對獨立的功能模塊並在之后的項目中重復使用。比較常見的例子是各種應用程序框架,ATL、MFC等,它們都以源代碼的形式發布。由於這種復用是“源碼級別”的,源代碼完全暴露給了程序員,因而稱之為“白盒復用”。“白盒復用”的缺點比較多,總結起來有4點。
暴露了源代碼;
多份拷貝,造成存儲浪費;
容易與程序員的“普通”代碼發生命名沖突;
更新功能模塊比較困難,不利於問題的模塊化實現;
實際上,以上4點概括起來就是“暴露的源代碼”造成“代碼嚴重耦合”。為了彌補這些不足,就提出了“二進制級別”的代碼復用。使用二進制級別的代碼復用一定程度上隱藏了源代碼,對於緩解代碼耦合現象起到了一定的作用。這樣的復用被稱為“黑盒復用”。
說明:實現“黑盒復用”的途徑不只dll一種,靜態鏈接庫甚至更高級的COM組件都是。
2.VS創建新一個空的解決方案(一個解決方案下可以有很多project)
2.創建dll
文件------>新建------>項目------>Win32控制台應用程序------>
選擇dll -- 勾選導出符號 -- 不勾選預編譯頭文件
刪除stdafx.h 、stdafx.cpp、targetver.h、dllmain.cpp,把MyDll.h修改成dllexport.dll。修改MyDll.cpp中#include "stdafx.h" #include "MyDll.h"改為 "dllexport.h"
如果生產dll和使用dll的工程在一個解決方案中,我們可以指定dll輸出目錄
$(SolutionDir) --- 解決方案目錄
$(Platform) ---- 平台目錄(x86/x64)
$(Configuration) --- 編譯模式(Debug/Release)
因為dll庫是函數的實現,lib里面是函數的聲明,我們也指定他的輸出路徑
這是我們編譯工程:
這時在解決方案目錄下生成bin和lib目錄
3.創建useDll工程
使用dll
導入頭文件 指定導入
在運行之前我們要指定UseDll工程的exe的輸出目錄
運行結果:
通過配置工程屬性來使用dll庫
工程—屬性—配置屬性—鏈接器—常規—附加庫目錄:加上lib文件存放目錄。
然后添加工程引用的lib文件名:工程—屬性—配置屬性—鏈接器—輸入—附加依賴項:加上lib文件名。
顯式調用dll:獲取dll庫的路徑,無需配置環境,無法進行隱式鏈接
調用:
#include "stdafx.h" #include <iostream> #include <Windows.h> #include <Shlwapi.h>// 使用PathRemoveFileSpec函數 using namespace std; #pragma comment(lib, "shlwapi.lib") //這個庫也要有,不然會報鏈接錯誤 typedef int(*MyAdd)(int a,int b); typedef int(*MySub)(int i,int j); int main() { TCHAR ModulePath[MAX_PATH] = { 0 }; GetModuleFileName(NULL,ModulePath,MAX_PATH); ::PathRemoveFileSpec(ModulePath);//C:\\TestDemo\\Debug wstring dllpath = ModulePath; dllpath += L"\\FunDll.dll"; HMODULE hModule = LoadLibrary(dllpath.c_str()); if (hModule) { MyAdd func = (MyAdd)GetProcAddress(hModule, "Add");//顯式調用dll中的Add cout << func(1, 5) << endl; MySub funs = (MySub)GetProcAddress(hModule,"Sub');//顯式調用dll中的Sub cout << funs(5,3) <<endl; } cout << fnMyDll() << endl;//調用dll中的函數 FreeLibrary(hModule); return 0; }