日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++动态链接库的制作

發(fā)布時間:2023/12/18 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++动态链接库的制作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

輸入函式__declspec(dllimport)?與輸出函式__declspec(dllexport)?有什么區(qū)別呢?我知道他們不同,但差別在哪呢?我用的全是__declspec(dllexport)?,?__declspec(dllimport)一般在什么時用呢?說說一般在什么時分別用到它們?

導出函式__declspec(dllexport)在dll中用

導入函式__declspec(dllimport)在要調(diào)用dll的程序中用?

這是指靜態(tài)連接
動態(tài)鏈接就不需要__declspec(dllimport)

很多書都有介紹

_declspec(dllexport) 與__declspec(dllimport) 的使用說明

__declspec(XXXXXX)是windows擴展C++的編譯宏頭

_declspec(dllexport)?

聲明一個導出函數(shù),是說這個函數(shù)要從本DLL導出。我要給別人用。一般用于dll中?。
省掉在DEF文件中手工定義導出哪些函數(shù)的一個方法。當然,如果你的DLL里全是C++的類的話,你無法在DEF里指定導出的函數(shù),只能用__declspec(dllexport)導出類。

__declspec(dllimport)

聲明一個導入函數(shù),是說這個函數(shù)是從別的DLL導入。我要用。一般用于使用某個dll的exe中?。
不使用 __declspec(dllimport) 也能正確編譯代碼,但使用 __declspec(dllimport) 使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因為它可以確定函數(shù)是否存在于 DLL 中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現(xiàn)在跨 DLL 邊界的函數(shù)調(diào)用中。但是,必須使用 __declspec(dllimport) 才能導入 DLL 中使用的變量。

??? 相信寫WIN32程序的人,做過DLL,都會很清楚__declspec(dllexport)的作用,它就是為了省掉在DEF文件中手工定義導出哪些函數(shù)的一個方法。當然,如果你的DLL里全是C++的類的話,你無法在DEF里指定導出的函數(shù),只能用__declspec(dllexport)導出類。但是,MSDN文檔里面,對于__declspec(dllimport)的說明讓人感覺有點奇怪,先來看看MSDN里面是怎么說的:

??? 不使用?__declspec(dllimport) 也能正確編譯代碼,但使用?__declspec(dllimport) 使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因為它可以確定函數(shù)是否存在于 DLL 中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現(xiàn)在跨 DLL 邊界的函數(shù)調(diào)用中。但是,必須使用?__declspec(dllimport) 才能導入 DLL 中使用的變量。

extern??? "C"???

指示編譯器用C語言方法給函數(shù)命名。

在制作DLL導出函數(shù)時由于C++存在函數(shù)重載,因此__declspec(dllexport)??? function(int,int)??? 在DLL會被decorate,例如被decorate成為??? function_int_int,而且不同的編譯器decorate的方法不同,造成了在用GetProcAddress取得function地址時的不便,使用extern??? "C"時,上述的decorate不會發(fā)生,因為C沒有函數(shù)重載,但如此一來被extern"C"修飾的函數(shù),就不具備重載能力,可以說extern??? 和?? extern??? "C"不是一回事。

C++編譯器在生成DLL時,會對導出的函數(shù)進行名字改編,并且不同的編譯器使用的改變規(guī)則不一樣,因此改編后的名字會不一樣。這樣,如果利用不同的編譯器分別生成DLL和訪問該DLL的客戶端代碼程序的話,后者在訪問該DLL的導出函數(shù)時會出現(xiàn)問題。為了實現(xiàn)通用性,需要加上限定符:extern “C”。

但是利用限定符extern “C”可以解決C++和C之間相互調(diào)用時函數(shù)命名的問題,但是這種方法有一個缺陷,就是不能用于導出一個類的成員函數(shù),只能用于導出全局函數(shù)。
? LoadLibrary導入的函數(shù)名,對于非改編的函數(shù),可以寫函數(shù)名;對于改編的函數(shù),就必須吧@和號碼都寫上,一樣可以加載成功,可以試試看。

解決警告? inconsistent dll linkage

????inconsistent dll linkage警告是寫dll時常遇到的一個問題,解決此警告的方法如下:

??? 一般PREDLL_API工程依賴于是否定義了MYDLL_EXPORTS來決定宏展開為__declspec(dllexport)還是__declspec(dllimport)。展開為__declspec(dllexport)是DLL編譯時的需要,通知編譯器該函數(shù)是需要導出供外部調(diào)用的。展開為__declspec(dllimport)是給調(diào)用者用的,通知編譯器,該函數(shù)是個外部導入函數(shù)。

對于工程設置里面的預定義宏,是最早被編譯器看到的。所以當編譯器編譯DLL工程中的MYDLL.cpp時,因為看到前面有工程設置有定義MYDLL_EXPORTS,所以就把PREDLL_API展開為__declspec(dllexport)了。

這樣做的目的是為了讓DLL和調(diào)用者共用同一個h文件,在DLL項目中,定義MYDLL_EXPORTS,PREDLL_API就是導出;在調(diào)用該DLL的項目中,不定義MYDLL_EXPORTS,PREDLL_API就是導入。

使用dll的兩種方式

方法一: load-time dynamic linking?(隱式調(diào)用)
  在要調(diào)用dll的應用程序鏈接時,將dll的輸入庫文件(import library,.lib文件)包含進去。具體的做法是在源文件開頭加一句#include ,然后就可以在源文件中調(diào)用dlldemo.dll中的輸出文件了。

方法二: run-time dynamic linking?(顯示調(diào)用)
  不必在鏈接時包含輸入庫文件,而是在源程序中使用LoadLibrary或LoadLibraryEx動態(tài)的載入dll。
  主要步驟為(以demodll.dll為例):?

1) typedef函數(shù)原型和定義函數(shù)指針。
 typedef void (CALLBACK* DllFooType)(void) ;
 DllFooType pfnDllFoo = NULL ;
2) 使用LoadLibrary載入dll,并保存dll實例句柄
 HINSTANCE dllHandle = NULL ;
 ...?
 dllHandle = LoadLibrary(TEXT("dlldemo.dll"));
3) 使用GetProcAddress得到dll中函數(shù)的指針
 pfnDllFoo = (DllFooType)GetProcAddress(dllHandle,TEXT("DllFoo")) ;
 注意從GetProcAddress返回的指針必須轉(zhuǎn)型為特定類型的函數(shù)指針。
4)檢驗函數(shù)指針,如果不為空則可調(diào)用該函數(shù)?
 if(pfnDllFoo!=NULL)
 DllFoo() ;
5)使用FreeLibrary卸載dll
 FreeLibrary(dllHandle) ;

??? 使用run-time dynamic linking 比較麻煩,但有它的好處(下面討論)。MSDN中有一篇文章DLLs the Dynamic Way討論使用c的宏創(chuàng)建一個基類pDll完成以上復雜的操作,使用時只需定義一個類繼承自類pDll并對類和函數(shù)使用宏。?
 以上兩種方法都要求應用程序能找到dll文件,Windows按以下順序?qū)ふ襠ll文件:

???如果系統(tǒng)不能找到dll文件,將結(jié)束調(diào)用dll的進程并彈出一個“啟動程序時出錯”對話框,告訴你“找不到所需的dll文件-XXX.dll”



一、DLL的創(chuàng)建?

創(chuàng)建項目: Win32->Win32項目,名稱:MyDLL


選擇DLL (D) ->完成.

1、新建頭文件testdll.h
testdll.h代碼如下:

#ifndef TestDll_H_
#define TestDll_H_
#ifdef MYLIBDLL
#define MYLIBDLL extern "C" _declspec(dllimport)?
#else
#define MYLIBDLL extern "C" _declspec(dllexport)?
#endif
MYLIBDLL int Add(int plus1, int plus2);
//You can also write like this:
//extern "C" {
//_declspec(dllexport) int Add(int plus1, int plus2);
//};
#endif



2、新建源文件testdll.cpp
testdll.cpp代碼如下:

#include "stdafx.h"
#include "testdll.h"
#include <iostream>
using namespace std;
int Add(int plus1, int plus2)
{
int add_result = plus1 + plus2;
return add_result;
}




3、新建模塊定義文件mydll.def
mydll.def代碼如下:

LIBRARY "MyDLL"
EXPORTS
Add @1



4、vs2010自動創(chuàng)建dllmain.cpp文件,它定義了DLL 應用程序的入口點。

dllmain.cpp代碼如下:
// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
? ?? ?? ?? ?? ?? ?? ???DWORD??ul_reason_for_call,
? ?? ?? ?? ?? ?? ?? ???LPVOID lpReserved
? ?? ?)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
??break;
}
return TRUE;
}

最后,編譯生成MyDLL.dll文件和MyDLL.lib文件。



1>------ 已啟動生成: 項目: MyDLL, 配置: Debug Win32 ------

1> ?dllmain.cpp

========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========

?

1>------ 已啟動生成: 項目: MyDLL, 配置: Debug Win32 ------

1> ?stdafx.cpp

1> ?testdll.cpp

1> ?MyDLL.cpp

1> ?正在生成代碼...

1> ? ? 正在創(chuàng)建庫 D:\Visual C++\工程\Libaray\MyDLL\Debug\MyDLL.lib 和對象 D:\Visual C++\工程\Libaray\MyDLL\Debug


標準C/C++的DLL編寫

DLL也就是動態(tài)鏈接庫,使用DLL編程的好處大家應當都知道了吧,可是怎么樣來作呢,今天我就來說說。

首先,你要確定你要導出那些個函數(shù),然后你就在你要導出的函數(shù)名前加上下面一句話:

????// 輸出函數(shù)的前綴
????#define? DLL_EXPORT???extern?"C"?__declspec(?dllexport?)

????DLL_EXPORT?VOID??ExportFun()
??? {
??????? ...
??? }

? 是不是很簡單啊。如果你要導出整個類或者全局變量,你需要這樣做:

// 輸出類的前綴
#define? DLL_CLASS_EXPORT???__declspec(?dllexport?)

// 輸出全局變量的前綴
#define? DLL_GLOBAL_EXPORT???extern __declspec(?dllexport?)

?完成了這些以后,我們就要在主程序中調(diào)用這些個函數(shù)了,用下面的方法:

????HINSTANCE?hInst = NULL;
??? hInst = LoadLibrary("*.dll");????????//?你的DLL文件名

??? if?(!hInst)
??? {
??????? MessageBox(hWnd,"無法加載 *.Dll ","Error",MB_OK);
??? }

??? 還記得上面我聲明的那個ExportFun()函數(shù)嗎?我不能直接得到那個函數(shù),但是可以把那個函數(shù)的地址取出來。其實函數(shù)地址使用起來和函數(shù)是一樣的。只不過,為了使用方便,需要定義一個函數(shù)指針的類型。如果要指向上面的那個ExportFun(),則它的函數(shù)指針的類型定義如下:

????typedef?void (CALLBACK* LPEXPORTFUN)(void)

??? 之后需要做的是聲明一個指針,然后得到DLL中ExportFun()的地址。GetProcAddress函數(shù)的第一個參數(shù)是之前得到的DLL的實例句柄,后面一個是DLL中那個函數(shù)的函數(shù)名。
???????
????LPEXPORTFUN?pFun = NULL;
????LPEXPORTFUN?pFun = (LPEXPORTFUN)GetProcAddress(hInst, "ExportFun");

好了,到這里已經(jīng)就要大功告成了,還差最后一步,調(diào)用那個函數(shù):

pFun();

大功告成!!


總結(jié)

以上是生活随笔為你收集整理的C++动态链接库的制作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。