在介绍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