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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

调用C++dll

發(fā)布時(shí)間:2023/12/18 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 调用C++dll 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.dll的優(yōu)點(diǎn)

代碼復(fù)用是提高軟件開發(fā)效率的重要途徑。一般而言,只要某部分代碼具有通用性,就可將它構(gòu)造成相對(duì)獨(dú)立的功能模塊并在之后的項(xiàng)目中重復(fù)使用。比較常見的例子是各種應(yīng)用程序框架, ATL 、 MFC 等,它們都以源代碼的形式發(fā)布。由于這種復(fù)用是 源碼級(jí)別 的,源代碼完全暴露給了程序員,因而稱之為 白盒復(fù)用 。 白盒復(fù)用 的缺點(diǎn)比較多,總結(jié)起來有 4 點(diǎn)。 ?
暴露了源代碼;多份拷貝,造成存儲(chǔ)浪費(fèi); ?
容易與程序員的 普通 代碼發(fā)生命名沖突; ?
更新功能模塊比較困難,不利于問題的模塊化實(shí)現(xiàn); ?
實(shí)際上,以上 4 點(diǎn)概括起來就是 暴露的源代碼 造成 代碼嚴(yán)重耦合 。為了彌補(bǔ)這些不足,就提出了 二進(jìn)制級(jí)別 的代碼復(fù)用。使用二進(jìn)制級(jí)別的代碼復(fù)用一定程度上隱藏了源代碼,對(duì)于緩解代碼耦合現(xiàn)象起到了一定的作用。這樣的復(fù)用被稱為 黑盒復(fù)用 。 ?

說明:實(shí)現(xiàn)黑盒復(fù)用的途徑不只dll一種,靜態(tài)鏈接庫甚至更高級(jí)的COM組件都是。

2.dll的創(chuàng)建

參考程序原文: http://msdn.microsoft.com/zh-cn/library/ms235636.aspx?

新建“Win32項(xiàng)目,選擇應(yīng)用程序類型為"DLL”,其他默認(rèn)。添加頭文件testdll.h

?//testdll.h

#ifdef?TESTDLL_EXPORTS??
#define?TESTDLL_API?__declspec(dllexport)???
#else??
#define?TESTDLL_API?__declspec(dllimport)???
#endif??
namespace?MathFuncs??
{??
????//?This?class?is?exported?from?the?testdll.dll??
????class?MyMathFuncs??
????{??
????public:???
????????//?Returns?a?+?b??
????????static?TESTDLL_API?double?Add(double?a,?double?b);

????????//?Returns?a?-?b??
????????static?TESTDLL_API?double?Subtract(double?a,?double?b);

????????//?Returns?a?*?b??
????????static?TESTDLL_API?double?Multiply(double?a,?double?b);

????????//?Returns?a?/?b??
????????
//?Throws?const?std::invalid_argument&?if?b?is?0??
????????static?TESTDLL_API?double?Divide(double?a,?double?b);
????};??
}

?當(dāng)定義了符號(hào)TESTDLL_EXPORTSTESTDLL_API被設(shè)置為?__declspec(dllexport)?修飾符,?This modifier enables the function to be exported by the DLL so that it can be used by other applications。若未定義則TESTDLL_API被設(shè)置為__declspec(dllimport)This modifier enables the compiler to optimize the importing of the function from the DLL for use in other applications。當(dāng)DLL項(xiàng)目生成時(shí),TESTDLL_EXPORTS默認(rèn)是定義的,所以默認(rèn)設(shè)置的是__declspec(dllexport)?修飾符。

添加 cpp 文件

?//?testdll.cpp?:?定義?DLL?應(yīng)用程序的導(dǎo)出函數(shù)。

#include?"stdafx.h"
#include?"testdll.h"??
#include?<stdexcept>??
using?namespace?std;??

namespace?MathFuncs??
{??
????double?MyMathFuncs::Add(double?a,?double?b)??
????{??
????????return?a?+?b;??
????}??

????double?MyMathFuncs::Subtract(double?a,?double?b)??
????{??
????????return?a?-?b;??
????}??

????double?MyMathFuncs::Multiply(double?a,?double?b)??
????{??
????????return?a?*?b;??
????}??

????double?MyMathFuncs::Divide(double?a,?double?b)??
????{??
????????if?(b?==?0)??
????????{??
????????????throw?invalid_argument("b?cannot?be?zero!");??
????????}??
????????return?a?/?b;??
????}??
}

編譯就會(huì)生成對(duì)應(yīng)的dll文件,同時(shí)也會(huì)生成對(duì)應(yīng)的lib文件。?

注意a.DLL中導(dǎo)出函數(shù)的聲明有兩種方式:在函數(shù)聲明中加上__declspec(dllexport);采用模塊定義(.def)文件聲明。詳見:http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792099.html?
b.
對(duì)于C文件創(chuàng)建dll時(shí)或者想使用C編譯器創(chuàng)建dll時(shí),建議使用?extern “C”?標(biāo)志,參見extern "C"的簡(jiǎn)單解析在C++中調(diào)用DLL中的函數(shù)(1)

?3.dll的調(diào)用

?應(yīng)用程序使用DLL可以采用兩種方式:一種是隱式鏈接(調(diào)用),另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數(shù)的結(jié)構(gòu)信息。VSVC\bin目錄下提供了一個(gè)名為Dumpbin.exe的小程序,用它可以查看DLL文件中的函數(shù)結(jié)構(gòu)。兩種的對(duì)比詳見:http://blog.sina.com.cn/s/blog_53004b4901009h3b.html?

隱式鏈接采用靜態(tài)加載的方式,比較簡(jiǎn)單,需要.h、.lib.dll三件套。
新建控制臺(tái)應(yīng)用程序空項(xiàng)目配置如下:(非常關(guān)鍵)

項(xiàng)目->屬性->配置屬性->VC++?目錄->?包含目錄里添加頭文件testdll.h所在的目錄

項(xiàng)目->屬性->配置屬性->VC++?目錄->?庫目錄里添加頭文件testdll.lib所在的目錄

項(xiàng)目->屬性->配置屬性->鏈接器->輸入->?附加依賴項(xiàng)里添加“testdll.lib”(若有多個(gè)?lib?則以空格隔開)

添加cpp文件

?//mydll.cpp

#include?<iostream>??
#include?"testdll.h"??
using?namespace?std;??

int?main()??
{??
????double?a?=?7.4;??
????int?b?=?99;??

????cout?<<?"a?+?b?=?"?<<??
????????MathFuncs::MyMathFuncs::Add(a,?b)?<<?endl;??
????cout?<<?"a?-?b?=?"?<<??
????????MathFuncs::MyMathFuncs::Subtract(a,?b)?<<?endl;??
????cout?<<?"a?*?b?=?"?<<??
????????MathFuncs::MyMathFuncs::Multiply(a,?b)?<<?endl;??
????cout?<<?"a?/?b?=?"?<<??
????????MathFuncs::MyMathFuncs::Divide(a,?b)?<<?endl;??

????try??
????{??
????????cout?<<?"a?/?0?=?"?<<??
????????????MathFuncs::MyMathFuncs::Divide(a,?0)?<<?endl;???
????}??
????catch?(const?invalid_argument?&e)???
????{??
????????cout?<<?"Caught?exception:?"?<<?e.what()?<<?endl;???
????}??
????return?0;??
}

現(xiàn)在可以編譯通過了,但是程序運(yùn)行就報(bào)錯(cuò),還需要將testdll.dll復(fù)制到當(dāng)前項(xiàng)目生成的可執(zhí)行文件所在的目錄。?
顯式鏈接是應(yīng)用程序在執(zhí)行過程中隨時(shí)可以加載DLL文件,也可以隨時(shí)卸載DLL文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對(duì)于解釋性語言更為合適。?
新建項(xiàng)目,不需要特殊配置,添加cpp文件

?#include<Windows.h>?//加載的頭文件

#include<iostream>
using?namespace?std;

int?main()??
{??
????typedef?double?(*pAdd)(double?a,?double?b);
????typedef?double?(*pSubtract)(double?a,?double?b);
?
????HMODULE?hDLL?=?LoadLibrary("testdll.dll");?//加載dll文件?
????if(hDLL?!=?NULL)??
????{??
????????pAdd?fp1?=?pAdd(GetProcAddress(hDLL,?MAKEINTRESOURCE(1)));?//得到dll中的第一個(gè)函數(shù)
????????if(fp1?!=?NULL)??
????????{???
????????????cout<<fp1(2.5,?5.5)<<endl;?
????????}??
????????else??
????????{??
????????????cout<<"Cannot?Find?Function?"<<"add"<<endl;??
????????}??
????????pSubtract?fp2?=?pSubtract(GetProcAddress(hDLL,?"?Subtract@MyMathFuncs@MathFuncs@@SANNN@Z"));?//得到dll中標(biāo)示為"?..."的函數(shù),C++編譯器考慮了函數(shù)的參數(shù)
????????if(fp2?!=?NULL)??
????????{??
????????????cout<<fp2(5.5,?2.5)<<endl;??
????????}??
????????else??
????????{??
????????????cout<<"Cannot?Find?Function?"<<"Subtract"<<endl;??
????????}??
????????FreeLibrary(hDLL);??
????}??
????else??
????{??
????????std::cout<<"Cannot?Find?"<<"testdll"<<std::endl;??
????}??
????return?1;??
}

?顯式調(diào)用的問題:DLL文件中,dll工程中函數(shù)名稱在編譯生成DLL的過程中發(fā)生了變化(C++編譯器),在DLL文件中稱變化后的字符為“name標(biāo)示。GetProcAddress中第二個(gè)參數(shù)可以由DLL文件中函數(shù)的順序獲得,或者直接使用DLL文件中的”name標(biāo)示,這個(gè)標(biāo)示可以通過Dumpbin.exe小程序查看。如果C++編譯器下,想讓函數(shù)名更規(guī)范(和原來工程中一樣),具體方法詳見:http://blog.csdn.net/btwsmile/article/details/6676802。?

當(dāng)然,為了讓函數(shù)名更規(guī)范,最常用的方式是:創(chuàng)建dll過程中使用C編譯器來編譯函數(shù),這樣DLL文件中的函數(shù)名和原dll工程中的函數(shù)名就一致了。

4.更一般的顯式調(diào)用

為了解決上部分最后的問題,可以使用 ?extern “C”? dll 工程中的函數(shù)建立 C 連接,簡(jiǎn)單的示例工程如下。 ?
DLL 創(chuàng)建的工程中,添加 cpp 文件

?#include?"stdafx.h"


#ifdef?__cplusplus?????????//?if?used?by?C++?code
extern?"C"?{??????????????????//?we?need?to?export?the?C?interface
#endif

__declspec(dllexport)?int?addfun(int?a,?int?b)
{
????????return?a+b;
}

#ifdef?__cplusplus
}
#endif
?
編譯即可生成DLL文件。在dll調(diào)用工程中,添加cpp文件
?
/*
?*作者:侯凱
?*說明:顯式調(diào)用dll
?*日期:2013-6-5
*/
#include?<windows.h>
#include?<iostream>
using?namespace?std;

void?main()
{
????typedef?int(*FUNA)(int,int);
????HMODULE?hMod?=?LoadLibrary("cdll.dll");//dll路徑
????if?(hMod)
????{
????????FUNA?addfun?=?(FUNA)GetProcAddress(hMod,?TEXT("addfun"));//直接使用原工程函數(shù)名?
????????if?(addfun?!=?NULL)
????????{
????????????cout<<addfun(5,?4)<<endl;
????????}
????????else
????????{
????????????cout<<"ERROR?on?GetProcAddress"<<endl;
????????}
????????FreeLibrary(hMod);
????}
????else
????????cout<<"ERROR?on?LoadLibrary"<<endl;
}

?運(yùn)行,這樣便可以調(diào)用dll的函數(shù)了。再進(jìn)一步,上述dll文件如果通過隱式調(diào)用,利用.dll、.lib文件,調(diào)用函數(shù)應(yīng)為

?//隱式鏈接

#include?<iostream>
#pragma?comment(lib,"cdll.lib")
using?namespace?std;

extern?"C"?_declspec(dllimport)?int?addfun(int?a,int?b);
//載入addfun函數(shù),這里起到了.h文件的作用
//dll中使用C編譯器?故這里需要extern?"C"?如果dll中無extern?"C"
//此處為:_declspec(dllimport)?int?addfun(int?a,int?b);
void?main()
{
????cout<<addfun(5,4)<<endl;
}

總結(jié)

以上是生活随笔為你收集整理的调用C++dll的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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