在介紹Dll之前先了解下常見三種函數調用約定。
參考:https://www.cnblogs.com/yejianyong/p/7506465.html
我們使用的VS默認使用的函數調用約定是__cdel,而Windows API默認的調用約定是__stdcall。我們在使用一個dll的接口時,一定要確保你使用接口時的調用約定和接口定義時的調用約定一致。因為不同的調用約定,函數的棧內存釋放的方式不同。
然后我們再了解下extern C的作用,參考https://www.cnblogs.com/carsonzhu/p/5272271.html。
如果我們使用C++進行程序開發,開發過程中使用到了C語言寫的庫函數,則我們就需要使用extern C 來修飾,來告訴編譯器,這部分代碼使用C語言語法進行編譯鏈接。
例如:
#ifdef __cplusplus
extern "C" {
#endif
#include "legacy_C_header.h"
#ifdef __cplusplus
}
#endif
這個就是它允許你在你的C ++代碼中使用這個C頭文件,因為宏“__cplusplus”將被定義。
下面我們開始學習C++Dll的創建和使用
C++創建的dll既可以給C++工程使用也可以給C#工程使用。
C++導出函數,在DLL中有一張導出表,記錄着需要導出的函數,這些函數可供外部程序調用,即這些函數都是該DLL的入口點(類似main函數)。不在導出表中的函數,為該DLL私有的函數,外部程序不能調用它們。
C++工程調用C++導出函數或者導出類
導出函數的幾個方法參考https://www.cnblogs.com/findumars/p/8660427.html
在函數聲明時,直接使用__declspec(dllexport)聲明函數
或者是直接使用def文件指定導出的函數
使用導出函數庫時,我們可以直接在VS上配置,指定庫目錄和動態庫對應的lib文件名,以及C/C++常規中的包含目錄,該目錄指定頭文件。
也可以直接在代碼中使用#pragma comment,具體語法可以參考https://blog.csdn.net/wfq_1985/article/details/7456591
使用如下:
#pragma comment(lib, "..\\CplusplusDll\\Debug\\CplusplusDll.lib")
當你不知道頭文件只知道你使用的函數類型時,則可以使用如下函數:
typedef int(*func)(int, int);
HINSTANCE hInstance = LoadLibrary(L"..\\CplusplusDll\\Debug\\CplusplusDll.dll");
LPCSTR pc = "?GetMax@@YAHHH@Z";
func getmax = (func)GetProcAddress(hInstance, pc);
int max = getmax(a, b);
使用微軟VS提供的dumpbin –exports xxx.dll 可以查看你的函數名,同時你一定要確保你的調用約定和GetMax函數定義的一致。這里使用的是func的約定使用默認值一般是__cdel,函數GetMax定義的地方也是__cdel。如果是__stdcall則需要顯示聲明{typedef int(__stdcall*func)(int, int);}
注意,不建議直接使用這種方法對類的成員函數進行調用。
對於C++導出類,C++工程在調用時和導出函數一致,除了不能使用LoadLibrary函數進行動態加載外,VS配置和#progma預編譯指令都可以使用。
#include "../CplusplusDll/CMath.h"
#pragma comment(lib, "..\\CplusplusDll\\Debug\\CplusplusDll.lib")
CMath m;
int sum = m.add(5, 6, 7);
對於C#工程,如何調用C++導出函數呢?使用DllImport屬性,在System.Runtime.InteropServices命名空間下定義。參考https://www.cnblogs.com/xingboy/p/11158487.html,使用如下
[DllImport(@"CplusplusDll.dll",CallingConvention = CallingConvention.Cdecl,EntryPoint = "?GetMax@@YAHHH@Z")]
public extern static int getMax(int a, int b);
int a = getMax(2, 3);
對於非托管的C++類,C#是無法直接使用,但是C#支持托管的C++代碼的使用。所以非托管的C++類,可以通過托管類包裝,進行導出,C++托管類使用的數據類型必須都是托管的,詳情可以以下鏈接:https://blog.csdn.net/weixin_34167819/article/details/91974250