一、生成dll
windows平台使用visual studio生成。
extern "C" _declspec(dllexport) int Add(int x,int y);
int Add(int x,int y)
{
return x+y;
}
extern:C++ 程序可能包含多个 编译单元。 若要声明在单独的编译单元中定义的实体,请使用 extern 关键字。 声明中的信息足以用于编译器。 但是,如果在链接步骤中找不到实体的定义,则链接器将引发错误。
C++动态链接库(DLL)的创建和调用
C++中的extern关键字
关键字 extern 可以应用于全局变量、函数或模板声明。 它指定符号具有 external 链接。
关键字 extern 具有四种含义,具体取决于上下文:
- 在非const 全局变量声明中, extern 指定变量或函数在另一个转换单元中定义。
- const在变量声明中,它指定变量具有 external 链接。
- extern “C” 指定函数在别处定义并使用 C 语言调用约定。 在 C++ 中,与字符串一起使用时, extern 指定将另一种语言的链接约定用于声明符 () 。 仅当 C 函数和数据以前声明为具有 C 链接时,才能访问它们。Microsoft C++ 支持字符串和“C++”字符串文本字段中的字符串“C”。 所有标准包含文件都使用 extern “C” 语法,以允许在 C++ 程序中使用运行时库函数。
-
在 C++ 类中使用 dllimport 和 dllexport
dllexport、dllimport存储类属性是特定于 C 和 C++ 语言的扩展。 可以使用它们从 DLL 中导出或向其中导入函数、数据和对象。
声明dllexport时,必须使用__declspec关键字。
- 使用 dllexport 意味着定义,而使用 dllimport 则意味着声明。 必须使用带 extern 的 dllexport 关键字来强制进行声明;否则,会进行隐式定义。
- 将函数声明为 dllexport 无需模块定义 (.def) 文件。
- 声明为 extern “C” 包含基于调用约定的平台特定修饰的 C 函数或函数 。 ```cpp // dllimport and dllexport class attributes的例子: declspec( dllimport ) int i; declspec( dllexport ) void func();
//若要提高代码的可读性,可以使用宏定义:
define DllExport __declspec( dllexport )
class DllExport C { int i; virtual int func( void ) { return 1; } };
其中的**__declspec**放在变量类型的前面,放在struct、class关键字的后面。
```cpp
__declspec(dllimport) class X {} varX;
class __declspec(dllimport) X {};
如果放在class后面,将导出其所有成员函数和静态数据,这种类也被称为“可导出类”。禁止对可导出类的成员显式使用 dllimport 和 dllexport 属性。
二、把dll放入unity
在unity中创建一个Plugins文件夹,所有的外部引用的dll组件必须要放在这个文件下,才能被using。
如果是C#封装的dll,就用 using的方式引用,如果是C++的dll,就DllImport[“”]的方式来添加对dll的引用。
如果是一般的C#程序,需要和exe文件放在同一目录下。
三、在unity中使用C#导入dll
//MyDll.cs
using System.Runtime.InteropServices;
public static class MyDll
{
[DllImport("MyDll")]
public static extern int MyAdd(int x, int y);
}
原理
P/Invoke是平台调用服务(Platform Invocation Services)的简称。在C#中,可以使用extern关键字和DllImport特性将上述函数声明为一个同名的静态方法,即可在程序中直接调用。CLR包含了一个封送器(marshaler),它可以将参数和返回值在.NET类型和非托管类型间进行转换。
在上述例子中,就通过DllImport属性、extern关键字,定义了C++的dll文件中的同名静态方法,已经能够在其他位置调用了。此函数的参数类型很简单,可以直接使用。
如果dll中的参数类型是结构体、回调函数,还需要在C#中进行相应的定义。
结构体举例
C++原型:
C#定义:
StructLayout特性可以定义封送器的数据映射(如何将结构字段映射到非托管类型的相应部分上)方式。其中Layout.Sequential会将每一个字段按照声明顺序对齐到包尺寸(pack-size)的边界上。
回调函数举例
P/Invoke层可以将非托管函数指针映射为C#的委托(C#中和函数指针最接近的结构)。
C++原型:
C#定义:
四、在unity中使用C#调用dll中符号
// MyTest.cs
void Start ()
{
var x = MyDll.MyAdd(1, 2);
Debug.Log(x);
}
这个就比较简单了