網(wǎng)站首頁 編程語言 正文
工具集
借助工具可以獲得Dll庫函數(shù)的訪問地址,以下推薦兩款工具以供使用:
Dependency Walker官網(wǎng)
Depends22_x64.zip
Dllexp-x64.zip
如何生成
__declspec(dllexport)
將一個函數(shù)聲名為導(dǎo)出函數(shù),就是說這個函數(shù)要被其他程序調(diào)用,即作為DLL的一個對外函數(shù)接口。
__declspec(dllexport) RETURN_TYPE FUNCTION()
extern “C”
由于在制作DLL導(dǎo)出函數(shù)時由于C++存在函數(shù)重載
- 因此
__declspec(dllexport) FUNCTION(int,int)
在DLL會被decorate,例如: 被decorate成為function_int_int, - 而且不同的編譯器decorate的方法不同,造成了在用
GetProcAddress
取得FUNCTION地址
時的不便 - 使用
extern "C"
時,上述的decorate不會發(fā)生,因?yàn)镃沒有函數(shù)重載,如此一來被extern"C"修飾的函數(shù),就不具備重載能力
。
extern "C" { __declspec(dllexport) RETURN_TYPE FUNCTION(){ ; } }
如何使用
- 動態(tài)載入方式是指在編譯之前并不知道將會調(diào)用哪些 DLL 函數(shù), 完全是在運(yùn)行過程中根據(jù)需要決定應(yīng)調(diào)用哪些函數(shù)。
- 方法是:用 LoadLibrary 函數(shù)加載動態(tài)鏈接庫到內(nèi)存,用 GetProcAddress函數(shù)動態(tài)獲得 DLL 函數(shù)的入口地址。
- 當(dāng)一個 DLL 文件用 LoadLibrary 顯式加載后,在任何時刻均可以通過調(diào)用 FreeLibrary 函數(shù)顯式地從內(nèi)存中把它給卸載。
- 動態(tài)調(diào)用使用的 Windows API 函數(shù)主要有 3 個, 分別是
LoadLibrary
、GetProcAddress
和FreeLibrary
聲明調(diào)用
注意DLL函數(shù)調(diào)用約定,必須一致
-
__stdcall
Windows API默認(rèn)的函數(shù)調(diào)用協(xié)議 -
__cdecl
C/C++默認(rèn)的函數(shù)調(diào)用協(xié)議 -
__fastcall
適用于對性能要求較高的場合
Example
假如我有一個函數(shù)接口如下:
//@ GETCOMCHECKSUM_API是一個宏定義 //@ #define GETCOMCHECKSUM_API __declspec(dllexport) GETCOMCHECKSUM_API int fnGetComCheckSum( const unsigned char* iCsArray, //[In]數(shù)組 const unsigned int iCsSize, //[In]數(shù)值 unsigned char& ioCsValue) //[In/Out]數(shù)值
那么我的調(diào)用應(yīng)該這么寫:
//@ __cdecl * 后面函數(shù)名可以自定義 typedef int(__cdecl *GetComCheckSum)( unsigned char const *, unsigned int, unsigned char&);
LoadLibrary
- [格式]
function LoadLibrary(LibFileName : PChar): Thandle
; - [功能] 加載由參數(shù) LibFileName 指定的 DLL 文件
- [說明] 參數(shù) LibFileName 指定了要裝載的 DLL 文件名
如果 LibFileName 沒有包含一個路徑,系統(tǒng)將按照:當(dāng)前目錄、Windows 目錄、Windows 系統(tǒng)目錄、包含當(dāng)前任務(wù)可執(zhí)行文件的目錄、列在 PATH 環(huán)境變量中的目錄等順序查找文件。
如果函數(shù)操作成功,將返回裝載 DLL 庫模塊的實(shí)例句柄,否則,將返回一個錯誤代碼,錯誤代碼的定義如下表所示
錯誤代碼 ? ? ? ? ? ? 含義
? ? ? 0 ? ? ? ? ? ? 系統(tǒng)內(nèi)存不夠,可執(zhí)行文件被破壞或調(diào)用非法
? ? ? 2 ? ? ? ? ? ? 文件沒有被發(fā)現(xiàn)
? ? ? 3 ? ? ? ? ? ? 路徑?jīng)]有被發(fā)現(xiàn)
? ? ? 5 ? ? ? ? ? ? 企圖動態(tài)鏈接一個任務(wù)錯誤或者有一個共享或網(wǎng)絡(luò)保護(hù)錯誤
? ? ? 6 ? ? ? ? ? ? 庫需要為每個任務(wù)建立分離的數(shù)據(jù)段 ?
? ? ? 8 ? ? ? ? ? ? 沒有足夠的內(nèi)存啟動應(yīng)用程序 ?
? ? ? 10 ? ? ? ? ? ?Windows ?版本不正確 ?
? ? ? 11 ? ? ? ? ? ?可執(zhí)行文件非法或不是Windows ?應(yīng)用程序,或在. ?EXE映像中有錯誤 ?
? ? ? 12 ? ? ? ? ? ?應(yīng)用程序?yàn)橐粋€不同的操作系統(tǒng)設(shè)計(jì)(如 ?OS/2) ?
? ? ? 13 ? ? ? ? ? ?應(yīng)用程序?yàn)??MS ?DOS ? 4. 0 ?設(shè)計(jì) ?
? ? ? 14 ? ? ? ? ? ?可執(zhí)行文件的類型不知道 ?
? ? ? 15 ? ? ? ? ? ?試圖裝載一個實(shí)模式應(yīng)用程序(為早期Windows ?版本設(shè)計(jì))
? ? ? 16 ? ? ? ? ? ?試圖裝載包含可寫的多個數(shù)據(jù)段的可執(zhí)行文件的第二個實(shí)例 ?
? ? ? 19 ? ? ? ? ? ?試圖裝載一個壓縮的可執(zhí)行文件(文件必須被解壓后才能被裝載) ?
? ? ? 20 ? ? ? ? ? ?DLL ?文件非法
? ? ? 21 ? ? ? ? ? ?應(yīng)用程序需要 ?32 ?位擴(kuò)展
Example
//@ 定義句柄 HINSTANCE hSnKLib; //@ 獲取鏈接庫句柄 Getchecksum為dll的文件名 即 Getchecksum.dll //@ 系統(tǒng)將會在當(dāng)前目錄下尋找名為Getchecksum.dll的文件 //@ 至于為什么使用_T("") ,_T是一個宏,作用是讓你的程序支持Unicode編碼,Windows使用兩種字符集ANSI和UNICODE hSnKLib = LoadLibrary(_T("Getchecksum")) //@ 如果未能成功獲取,拋出錯誤 if (hSnKLib == NULL) { FreeLibrary(hSnKLib); printf("LoadLibrary err\n"); getchar(); return 1; }
GetProcAddress
- 格式:
function GetProcAddress(Module:Thandle; ProcName:PChar): TfarProc;
- 功能: 返回參數(shù) Module 指定的模塊中,由參數(shù) ProcName 指定的過程或函數(shù)的入口地址
- 說明: 參數(shù)
Module
包含被調(diào)用函數(shù)的 DLL 句柄,這個值由 LoadLibrary 返回,procName
是指向含有函數(shù)名的以 nil 結(jié)尾的字符串指針,或者可以是函數(shù)的次序值.
大多數(shù)情況下,用函數(shù)名
是一種更穩(wěn)妥的選擇。
如果該函數(shù)執(zhí)行成功,則返回 DLL 中由參數(shù) ProcName 指定的過程或函數(shù)的入口地址
,否則返回 nil 。
Example
//前面我們在頭文件中聲明了下述函數(shù) typedef int(__cdecl *GetComCheckSum)( unsigned char const *, unsigned int, unsigned char&); //實(shí)例化并且獲取函數(shù)地址 //fnGetComCheckSum為dll export出來的函數(shù)名,GetComCheckSum為我們引用時候聲明的函數(shù)名 //這里做的工作就是將dll中函數(shù)與我們聲明的聯(lián)系到一塊。 GetComCheckSum getcom = (GetComCheckSum)GetProcAddress(hSnKLib, "fnGetComCheckSum") if (!getcom) { FreeLibrary(hSnKLib); //釋放dll文件 //Add your code here }
FreeLibrary
- 格式:
procedure FreeLibrary(Module: Thandle);
- 說明:將由參數(shù) Module 指定的 DLL 文件從內(nèi)存中卸載 1 次。
- 說明:Module 為 DLL 庫的句柄。這個值由 LoadLibrary 返回。由于 DLL 在內(nèi)存中只裝載一次,因此調(diào)用 FreeLibrary 首先使 DLL 的引用計(jì)數(shù)減 1,如果計(jì)數(shù)減為 0 則卸載該 DLL
- 注意:每調(diào)用一次 LoadLibrary 函數(shù)就應(yīng)調(diào)用一次 FreeLibrary 函數(shù),以保證不會有多余的庫模塊在應(yīng)用程序結(jié)束后仍留在內(nèi)存中,否則導(dǎo)致內(nèi)存泄漏。
Example
FreeLibrary(hSnKLib);
FAQS
Question 1: GetLastError獲取錯誤代碼127
問題描述:
- 采用"運(yùn)行期間動態(tài)鏈接"自己的dll文件
- LoadLibrary成功獲取dll模塊句柄
- 但是GetProcAddress(hModule, “ExportFunc”)卻返回NULL,GetLastError獲取錯誤代碼127,意思是“找不到指定程序”
問題定位:
- 用Depends工具(VS2010默認(rèn)沒有,需另行下載:http://www.dependencywalker.com/),查看dll的導(dǎo)出函數(shù)名稱。
- 發(fā)現(xiàn)導(dǎo)出函數(shù)名不再是“ExportFunc”,而根據(jù)函數(shù)的返回類型和參數(shù)進(jìn)行了“decorate”,變?yōu)榱恕?ExportFunc@@YAXPB_W@Z”。
解決方法兩種:
- 修改GetProcAddress的第二個參數(shù)為真正的導(dǎo)出函數(shù)名稱即可
- 在dll工程中添加DEF文件,寫入如下內(nèi)容:
EXPORTS ExportFunc
- 重新編譯dll工程。再次用Depends工具查看導(dǎo)出函數(shù)名稱,即為“ExportFunc”。
- 工程–鏈接器–輸入 的模塊定義文件中,將自己的DEF文件加上
參考案例
GetProcAddress 使用注意事項(xiàng)
原文鏈接:https://blog.csdn.net/qq_33704787/article/details/126090055
相關(guān)推薦
- 2022-05-09 Docker?Overlay2磁盤空間占用過大清理的方法實(shí)現(xiàn)_docker
- 2022-10-05 matplotlib之Pyplot模塊繪制三維散點(diǎn)圖使用顏色表示數(shù)值大小_python
- 2022-05-26 Pytorch中使用ImageFolder讀取數(shù)據(jù)集時忽略特定文件_python
- 2022-09-29 kotlin源碼結(jié)構(gòu)層次詳解_Android
- 2023-07-13 react中useState的基本用法
- 2022-05-10 @requestmapping獲取請求參數(shù)
- 2022-03-19 關(guān)于docker中?WSL?配置與修改問題_docker
- 2022-10-30 Matlab利用遺傳算法GA求解非連續(xù)函數(shù)問題詳解_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支