標頭檔案中為什麼要有下面的**呢?
#ifdef yakedll_exports
#define yakedll_api __declspec(dllexport)
#else
#define yakedll_api __declspec(dllimport)
#endif
__declspec(dllexport)意思是匯出符號到dll.
__declspec(dllimport)意思是從dll匯入符號.
我們生成的時候,在專案屬性中系統幫我們定義了yakedll_exports巨集,所以生成時是將符號匯出到dll中.
而我們在使用dll的時候,沒有定義到yakedll_exports巨集,所以使用的時候從dll中匯入符號到.exe檔案,以供.exe檔案使用.
接下來再標頭檔案和cpp檔案中新增想匯出為dll的函式宣告及實現。
yakedll.h標頭檔案
// 下列 ifdef 塊是建立使從 dll 匯出更簡單的
// 巨集的標準方法。此 dll 中的所有檔案都是用命令列上定義的 yakedll_exports
// 符號編譯的。在使用此 dll 的
// 任何專案上不應定義此符號。這樣,原始檔中包含此檔案的任何其他專案都會將
// yakedll_api 函式視為是從 dll 匯入的,而此 dll 則將用此巨集定義的
// 符號視為是被匯出的。
#ifdef yakedll_exports
#define yakedll_api __declspec(dllexport)
#else
#define yakedll_api __declspec(dllimport)
#endif
#include using namespace std;
// 此類是從 dll 匯出的
class yakedll_api cyakedll ;
// 匯出變數符號到dll中
extern yakedll_api int nyakedll;
// 匯出函式符號到dll中
yakedll_api int fnyakedll(void);
//匯出函式(使用export)
yakedll_api void fnmydllwithdllexport(ostream& os);
yakedll_api int add(int a, int b);
// 匯出函式(c語言方式)
extern "c"
yakedll.cpp檔案
// yakedll.cpp : 定義 dll 的匯出函式。
//#include "pch.h"
#include "framework.h"
#include "yakedll.h"
// 這是匯出變數的乙個示例
yakedll_api int nyakedll=0;
// 這是匯出函式的乙個示例。
yakedll_api int fnyakedll(void)
yakedll_api int add(int a, int b)
yakedll_api void fnmydllwithdllexport(ostream& os)
yakedll_api void fnmydllwithexternc(ostream& os)
// 這是已匯出類的建構函式。
cyakedll::cyakedll()
void cyakedll::output(void)
然後編譯,可以看到輸出已經生成了想要的dll和lib檔案。
.lib檔案有兩種,一種是靜態庫,是靜態編譯出來的,索引和實現都在其中。
另一種是與動態編譯出來的dll檔案對應的lib檔案,一般是一些索引資訊,具體的實現在dll檔案中。(本例子的情況)
從開始選單的visual studio 2017的開發人員命令提示符
處啟動dumpbin工具,執行dumpbin -exports path\to\dll
命令分析生成的dll,檢視編譯器產生的函式名:
vc++編譯器會針對c++函式使用名稱修飾,而不會修飾以c方式宣告的函式(其實也修飾了,在函式名前面加了乙個下劃線字首(fnmydllwithexternc = @ilt+305(_fnmydllwithexternc)),這是c語言的函式呼叫約定預設為__cdecl
所導致);
呼叫dll有兩種鏈結方式:隱式鏈結和顯式鏈結,無論哪種方式都要求將dll和exe放在同一目錄下,或者設定環境變數,讓系統搜尋到。比較常用的是隱式鏈結。
所謂顯式鏈結,就是直接呼叫win32 api函式loadlibrary
、getprocaddress
和freelibrary
顯式地裝載、解除安裝dll。
#include // 必要標頭檔案
#include using namespace std;
hinstance hdll; // handle to dll
void (*mydllexport)(ostream& os);
void (*mydllexportexternc)(ostream& os);
int(*myadd)(int , int );
int main()
mydllexport(std::cout);
mydllexportexternc(std::cout);
int c = myadd(1, 2);
cout << c << endl;
system("pause");
freelibrary(hdll);
return 0;
}
2.2 c# 顯式呼叫dll
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using system.io;
using system.runtime.interopservices; // dll import
namespace dlltest_csharpconsole}}
[dllimport("yakedll.dll", entrypoint = "add", exactspelling = false, callingconvention = callingconvention.cdecl)]
動態鏈結庫DLL
函式和資料被編譯進乙個二進位制檔案 通常擴充套件名為.lib 靜態庫 在使用靜態庫的情況下,在編譯鏈結可執行檔案時,鏈結器從庫中複製這些函式和資料並把它們和應用程式的其它模組組合起來建立最終的可執行檔案 exe檔案 在多個同樣的程式執行時,系統保留了許多重複的 副本,造成記憶體資源浪費。動態庫 使用...
VS2017建立動態庫DLL,並實現呼叫
1 開啟vs2017,新建乙個 動態鏈結庫 dll 專案,這裡命名為 myfirstdll 2 建好後的專案中,在標頭檔案中會自動生成framework.h和pch.h兩個檔案,在原始檔中會自動生成dllmain.cpp和pch.cpp兩個檔案 3 在標頭檔案中新建乙個mathlibrary.件,用...
DLL(動態鏈結庫)程式設計
dll是現在常見的檔案,它整合了程式的很多功能在裡面。一般情況下,它不能直接被執行,常見的使用方法是用其他的 exe呼叫其執行,以使其內部功能表現出來。還有 ocx檔案也與之類似,也就是人們常說的com 1.簡要 windows api中所有的函式都包含在dll中,其中有3個最重要的dll。1 ke...