1. 程式人生 > >VS下動態庫dll的顯式呼叫(動態呼叫)

VS下動態庫dll的顯式呼叫(動態呼叫)

VS下動態庫dll的顯式呼叫

動態庫的載入分兩種形式:分為靜態載入和動態載入。靜態載入時,對應的標頭檔案、DLL,和LIB缺一不可,並且生產的EXE沒有找到DLL檔案就會導致“應用程式初始化失敗”。動態載入只需要dll,通過LoadLibrary()函式進行載入,但該方式對生成的dll的規範有一定的要求否則容易出錯。

Dll的動態呼叫常規程式碼如下:

//#include <Windows.h>
#include <afxwin.h>
#include <string>
#include <vector>
//#define  _AFxDLL

typedef int (*DLLfun)(int, int);

int main(){
	DLLfun fun1;
	HINSTANCE hdll;
	hdll=LoadLibrary("Image Enhance.dll"); //載入dll
	printf("hdll:%p\n",hdll);//列印dll地址
	if(hdll==NULL){
		FreeLibrary(hdll);//釋放dll
	}
	fun1 = (DLLfun)GetProcAddress(hdll, "sharpen");//獲取函式地址
	printf("fun1:%p\n",fun1);
	if(fun1==NULL){
		FreeLibrary(hdll);
	}
	int r;
	r = fun1(4,5);//函式地址
	return 0;
}

從上面的程式可以看出,dll動態呼叫主要用到三個函式LoadLibrary,GetProcAddress以及FreeLibrary。

1. LoadLibrary是用來載入dll的,格式為

HINSTANCE hdll;
	hdll=LoadLibrary("Image Enhance.dll");

呼叫成功則返回函式地址,否則返回0或NULL。

(1)當其調用出錯時,用GetLastError()得到返回值一般為126。使用LoadLibrary()動態載入dll失敗的原因一般分兩種:

1)路徑不對(程式與dll要放在同一資料夾)

2) dll本身錯誤(依賴其他dll)

解決方法:

a. 將DLL與exe放於同一目錄

b. Loadlibrary()與LoadlibraryEx()

c. DLL本身依賴使用depends.exe/Dependency Walker(depends)檢視該DLL依賴哪些DLL

“depends.exe 使用說明”:http://blog.csdn.net/scythe666/article/details/47165533

2. GetProcAddress()是用來獲取函式地址的,呼叫格式

 fun1 =(DLLfun)GetProcAddress(hdll, "sharpen");


具體看上面程式或者百度。通常若dll生成規範,可以直接執行成功。失敗則返回0或NULL。

(1)當其調用出錯時,用GetLastError()得到返回值一般為127,表示函式地址獲取失敗。原因基本上是因為函式名(如“sharpen”)在dll中不存在。當函式名沒有拼寫出錯的時候,則是因為dll在生成過程中把函式按不同標準進行修改,如改成了“?? 0sharpen @@

[email protected]”(通過depends.exe工具可以檢視具體函式名),這時候呼叫引數改成下面的形式就可以呼叫成功。


fun1 = (DLLfun)GetProcAddress(hdll, "?? 0sharpen @@[email protected] ");

這種方式呼叫起來很不方便,每次都要去檢視dll,所以我們最好在生成dll的時候就讓函式名變得規範,下文會對dll生成中的注意點進行介紹。

3. FreeLibrary()是用來釋放載入dll時佔用的空間的,由於Loadlibrary()為對dll的顯式載入(又叫動態載入),這種方式不會在用完dll後自動清理dll所佔用的空間,所以我們要手動清除dll所佔用的空間。否則會導致記憶體洩漏。呼叫格式如下:

FreeLibrary(hdll);

以上三個函式的具體使用還可以參考:

“動態載入DLL所需要的三個函式詳解(LoadLibrary,GetProcAddress,FreeLibrary)”

http://www.cnblogs.com/westsoft/p/5936092.html

4.規範化生成dll的注意點

(1)標頭檔案中定義__declspec(dllexport)  時,要加上extern "C",從而規範dll的輸出符合C標準,否則容易生成帶@之類的字串。extern"C"使得在C++中使用C編譯方式成為可能。在“C++”下定義“C”函式,需要加extern“C”關鍵詞。用extern "C"來指明該函式使用C編譯方式。加上extern C後,輸出函式的形式為"sharpen"符合預期標準。格式如下:(其中IMG_EXPORTS為自己定義輸出巨集

#define IMG_EXPORTS extern "C" __declspec(dllexport)  
//或者
extern "C" _declspec(dllimport) int calculateLineNum(CString filePath); 

但是該過程需要注意一點避免出錯,例如下面生成dll的標頭檔案程式碼中,函式輸出應該寫在AAA出現的位置,而不是BBB位置,在需要輸出到dll的函式前加上IMG_EXPORTS,如下:


#ifdef IMG_API_EXPORTS  
#define IMG_EXPORTS extern "C" __declspec(dllexport)  
AAAAAAAAAAAAAAAAA
IMG_EXPORTS int fun1(int a,int b);
#else  
#define IMG_EXPORTS __declspec(dllimport)  
#endif  
BBBBBBBBBBBBBBBBBB

注:使用微軟專用的_declspec (dllexport) 

cpp檔案在編譯為OBJ檔案時要對函式進行重新命名,C語言會把函式name重新命名為_name,而C++會重新命名為[email protected]@decoration,extern "C"表示用C語言的格式將函式重新命名,要輸出整個的類,對類使用_declspec(_dllexpot);要輸出類的成員函式,則對該函式使用_declspec(_dllexport)。

注:extern C的作用詳解參考部落格:http://blog.csdn.net/jiqiren007/article/details/5933599

(2)不加extern "C"的情況下,輸出函式名容易變形,靜態呼叫dll完全沒問題,但是顯式呼叫dll容易出錯。除了extern "C",我們還可以新增的標準約定,如_stdcall等。

1)__stdcall呼叫約定

在輸出函式名前加上一個下劃線字首,後面加上一個“@”符號和其引數的位元組數,格式為[email protected]

2__cdecl

呼叫約定僅在輸出函式名前加上一個下劃線字首,格式為_functionname

3__fastcall呼叫約定在輸出函式名前加上一個“@”符號,後面也是一個“@”符號和其引數的位元組數,格式為@[email protected]

它們均不改變輸出函式名中的字元大小寫,這和PASCAL呼叫約定不同,PASCAL約定輸出的函式名無任何修飾且全部大寫。

注:關於dll匯出函式名的方式還可以參考以下部落格:

dll匯出函式名的那些事:http://blog.csdn.net/qq_16209077/article/details/51989114







相關推薦

ROS CAN匯流排裝置接入(一)Linux動態呼叫

前提: (1),如果在libpcan安裝正常的話,那麼可以用以下命令查詢到libpcan.so ls /usr/lib/libpcan* 查詢到方可進行api載入。 (2),確保CMakeList.txt 當前目標檔案已加入add_executable...;target_

VS動態dll呼叫(動態呼叫)

VS下動態庫dll的顯式呼叫 動態庫的載入分兩種形式:分為靜態載入和動態載入。靜態載入時,對應的標頭檔案、DLL,和LIB缺一不可,並且生產的EXE沒有找到DLL檔案就會導致“應用程式初始化失敗”。動態載入只需要dll,通過LoadLibrary()函式進行載入,但該方式對

Linux靜態、動態(隱呼叫)的建立和使用及區別

顯式呼叫的動態庫的建立與隱式呼叫相同。(隱式呼叫與靜態庫的使用方法一樣,不需要包含匯出函式的標頭檔案(顯式呼叫也不用包含標頭檔案),只需要在編譯可執行程式時指定庫檔案的路徑)顯式呼叫和隱式呼叫的區別在於:編譯可執行程式時需要指定庫檔案的搜尋路徑,而顯式呼叫編譯可執行程式時不用加上動態庫的搜尋路徑(因為已經在主

動態(.dll)的建立與使用———VS編譯器實現

一、動態庫的概念 ①概念:動態庫連結時不復制,程式執行時由系統動態載入到記憶體,供程式呼叫。而且系統只加載一次,可以被多個程式共用。 ②特點: 動態函式庫在編譯的時候並沒有被編譯進目的碼中,需要用到相應的功能,程式碼才會被呼叫到程式中,節約記憶體 動態庫的改變,程式

windows動態dll和靜態編譯和使用問題

window下動態庫dll和靜態庫lib問題 windows下動態庫dll和靜態庫lib的聯絡和區別,以及示例匯出個動態庫 https://blog.csdn.net/lifei092/article/details/79630273 問題: 1,生成dll時,同時生成lib是做

PB呼叫.NET/C#開發的動態DLL的問題

之前用C#做了一個Dll提供給第三方呼叫(主要為PB使用者)。 pb一直無法呼叫我寫的dll,導致問題排查了3天。 最後找出原因是因為,對方環境沒有安裝.net framework。沒有將dll註冊導致的。

JNA呼叫C動態dll、so

1.介紹jna           JNA(Java Native Access )提供一組Java工具類用於在執行期動態訪問系統本地庫(native library:如Window的dll)而不需要編寫任何Native/JNI程式碼。開發人員只要在一個java介面中描述目

unity-呼叫動態dll-windows篇

1、生成64位的dll 用vs新建個工程,隨便寫個函式 NaviteCode.h #ifndef __NativeCode_H__ #define __NativeCod

利用c#實現dll動態,並在c++中呼叫的方法

           近期,在進行一個大專案開發。其中涉及多語言協同開發。主要是c#dll和c++dll的開發和應用,其中,需要在c++中呼叫c#dll的內容。現在把開發中的經驗、教訓和注意事項總結整理如下,希望對其他人能有所幫助。           1.建立c#dll,

【HelloCUDA】win10 首個 cuda9 應用程式 及 靜態(.lib) 動態(.dll)的引用

環境描述: win10 cuda 9.0 vs2017 vc++2015 redistributable update 3 and Build tools 目標及實現步驟 #1 將 CUDA 核心計算函式以靜態庫的方式為應用程式所用 1.1 新建靜態庫專案 1

vb.net 呼叫動態dll

'宣告部分 Public Declare Function Encode Lib ".\LDPC_DEC_DLL.dll" _ (ByRef s As Byte, ByRef c As Byte) As Byte Public Declar

【PE】Windows平臺為可執行檔案或動態dll新增版本資訊

###Date: 2017/9/22 ###Author : SoaringLee   平常我們可以看到在Windows可執行檔案中,右鍵屬性中含有檔案版本,檔名稱和版本等資訊,本文講述怎麼新增這些

【深度學習之Caffe】將模型測試Classification過程生成動態連結dll以方便其他專案呼叫

#include "caffe_classify.h"   #include "head.h"   Classifier::Classifier(const string& model_file,const string& trained_file,const string& mean

C# 調用 C++/CLI (托管模式c++) 的動態(DLL)

C++/CLI C# Dll調用 1.創建C++/CLI的動態庫 添加類 右鍵生成後即可生成 CLI_Dll.dll2.創建C#窗口應用程序,引用CLI_Dll.dll,然後就可以像是調用C#生成的的dll調用CLI_Dll.dll。C# 調用 C++/CLI (托管模式c++) 的動態庫(D

Unity3d 載入 C++/CLI (託管模式c++) 的動態(DLL)

由於最近開發遊戲尋路A*使用非常頻繁.所以是邏輯上的瓶頸. c#又比c++慢一倍.所以決定上c++.這樣算一種優化吧.哈哈. 關於vs上的vc++.分託管和非託管模式.  託管模式就是 C++/CLI 也就說可以c++使用.net庫. 和 CLR是一起的.  還有就是 非託

使用動態DLL匯出類

首先建立一個DLL工程,名稱為ServMgrDll,新建一個類,包含標頭檔案ServConfig.h和cpp檔案ServConfig.cpp。類的程式碼如下:.h:#pragma once /* 如果沒有定義:ServConfigAPI,則ServConfigAPI

動態DLL中類的使用

一、DLL中類的匯出 在類名稱前增加 _declspec(dllexport)定義,例如: class _declspec(dllexport) CMath{ .... }; 通常使用預編譯開關切換

Unity Windows&Mac 編譯和除錯外部C#動態(DLL)

目標實現 Windows 平臺 工具 Visual Studio 2015 Unity 5.6 Visual Studio 2015 Tools for Unity  Python 2.7.9 步驟 建立 C# 類庫工程 引用UnityEngine.dl

qt使用動態(DLL)

本文主要講解在QT開發環境中如何使用VC生成的DLL及QT自身生成的DLL。至於其它情況本文不作討論。 連線庫分為2種 (1)動態連線庫,通常有.h .lib .dll三個檔案,功能實現在dll中 (2)靜態連線庫,通常有.h .lib二個檔案,功能實現在lib中 由上可以看

Visual Studio2017動態DLL製作與使用

DLL(Dynamic Link Library)檔案為動態連結庫檔案,又稱“應用程式拓展”,是軟體檔案型別。在Windows中,許多應用程式並不是一個完整的可執行檔案,它們被分割成一些相對獨立的動態連結庫,即DLL檔案,放置於系統中。當我們執行某一個程式時,相