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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

天马行空W:在C++中调用DLL中的函数

發布時間:2025/5/22 c/c++ 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 天马行空W:在C++中调用DLL中的函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.dll的優點

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

說明:實現“黑盒復用”的途徑不只dll一種,靜態鏈接庫甚至更高級的COM組件都是。

2.dll的創建

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

新建“Win32項目”,選擇應用程序類型為"DLL”,其他默認。添加頭文件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);
????};??
}

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

添加cpp文件

?//?testdll.cpp?:?定義?DLL?應用程序的導出函數。

#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;??
????}??
}

編譯就會生成對應的dll文件,同時也會生成對應的lib文件。?

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

?3.dll的調用

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

隱式鏈接采用靜態加載的方式,比較簡單,需要.h.lib.dll三件套。
新建控制臺應用程序空項目配置如下:(非常關鍵)

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

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

項目->屬性->配置屬性->鏈接器->輸入-> 附加依賴項里添加“testdll.lib”(若有多個 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;??
}

現在可以編譯通過了,但是程序運行就報錯,還需要將testdll.dll復制到當前項目生成的可執行文件所在的目錄?
顯式鏈接是應用程序在執行過程中隨時可以加載DLL文件,也可以隨時卸載DLL文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對于解釋性語言更為合適。?
新建項目,不需要特殊配置,添加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中的第一個函數
????????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中標示為"?..."的函數,C++編譯器考慮了函數的參數
????????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;??
}

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

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

4.更一般的顯式調用

為了解決上部分最后的問題,可以使用 extern “C” 為dll工程中的函數建立C連接,簡單的示例工程如下。?
在DLL創建的工程中,添加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調用工程中,添加cpp文件
?
/*
?*作者:侯凱
?*說明:顯式調用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"));//直接使用原工程函數名?
????????if?(addfun?!=?NULL)
????????{
????????????cout<<addfun(5,?4)<<endl;
????????}
????????else
????????{
????????????cout<<"ERROR?on?GetProcAddress"<<endl;
????????}
????????FreeLibrary(hMod);
????}
????else
????????cout<<"ERROR?on?LoadLibrary"<<endl;
}

?運行,這樣便可以調用dll的函數了。再進一步,上述dll文件如果通過隱式調用,利用.dll.lib文件,調用函數應為

?//隱式鏈接

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

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

總結

以上是生活随笔為你收集整理的天马行空W:在C++中调用DLL中的函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 羞羞涩| 日韩高清不卡 | 国产av不卡一区 | 国产成人在线视频网站 | 天天射av| 黑人高潮一区二区三区在线看 | 免费成人毛片 | 人人澡人人看 | 性一交一乱一透一a级 | 国产精品呻吟久久 | 欧美少妇色图 | 欧美激情性生活 | 欧洲午夜视频 | 国产精品一区二区三区不卡 | 久久伊人影视 | 毛片一区二区三区 | 国产老熟女伦老熟妇露脸 | 日韩av在线免费播放 | 亚洲综合久久av | 伦理自拍 | 黄在线观看 | 欧美做爰爽爽爽爽爽爽 | 天堂网色 | 最近中文字幕mv免费高清在线 | 可以免费观看的av网站 | 悠悠色在线 | 天堂av官网 | 手机成人免费视频 | 欧美三级黄色 | 99国产视频| 爱情岛亚洲论坛入口 | 肉丝美足丝袜一区二区三区四 | 久久黄网 | 波多野结衣在线电影 | 欧美人日b | 国产日韩精品一区二区 | 朱竹清到爽高潮痉挛 | 国产成人在线精品 | 亚洲 欧美 综合 | 五月天婷婷综合 | 麻豆国产免费 | 成人免费午夜 | 亚洲第一综合网 | 538精品在线视频 | 宅男午夜在线 | 国产女人18毛片水真多18 | 免费黄色片网站 | 久久99热精品 | 啪视频在线观看 | 男人的天堂色偷偷 | 亚洲AV永久无码国产精品国产 | 久草视频免费播放 | 成人福利免费视频 | 精品一区二区三区蜜臀 | 手机av免费观看 | 日韩精品免费电影 | 在线亚洲自拍 | 天堂va蜜桃一区二区三区 | 91精品国产乱码久久久久久久久 | 欧美一区二区三区成人久久片 | 国产一级片免费在线观看 | 丰满人妻一区二区三区免费视频 | 国产在线天堂 | 老外一级黄色片 | 影音先锋中文字幕资源 | 看全色黄大色黄大片女一次牛 | 成年人福利网站 | 狠狠人妻久久久久久综合 | 中文字幕1 | 国产乱码精品一区二区三区五月婷 | 国产高清一区二区 | 国产又色又爽又黄又免费 | 久久久一二三 | 午夜精品视频在线观看 | 免费一级a毛片夜夜看 | 男女午夜视频在线观看 | 亚洲AV成人无码精电影在线 | www在线看片 | 99re6在线| 青青草99| 午夜爽视频 | 日韩高清在线一区二区 | 成人网在线观看 | 美女张开腿让男人操 | 亚洲AV无码成人精品区在线观 | 亚洲天堂色图 | 亚洲精品一二三 | 美日韩精品 | 爱情岛论坛自拍 | 国产女人爽到高潮a毛片 | 狠狠爱天天干 | 97影视 | 91精品国产综合久久久久 | 青青青国内视频在线观看软件 | 午夜大片 | 黄片毛片 | 少妇做爰免费理伦电影 | 亚洲精品中文无码AV在线播放 | 老熟妇仑乱一区二区av |