一、生成dll

windows平台使用visual studio生成。

  1. extern "C" _declspec(dllexport) int Add(int x,int y);
  2. int Add(int x,int y)
  3. {
  4. return x+y;
  5. }

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++ 程序中使用运行时库函数。
  • 在模板声明中, extern 指定模板已在其他位置实例化。

    在 C++ 类中使用 dllimport 和 dllexport

    dllexport、dllimport存储类属性是特定于 C 和 C++ 语言的扩展。 可以使用它们从 DLL 中导出或向其中导入函数、数据和对象。

  • 声明dllexport时,必须使用__declspec关键字。

  • 使用 dllexport 意味着定义,而使用 dllimport 则意味着声明。 必须使用带 externdllexport 关键字来强制进行声明;否则,会进行隐式定义。
  • 将函数声明为 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; } };

  1. 其中的**__declspec**放在变量类型的前面,放在structclass关键字的后面。
  2. ```cpp
  3. __declspec(dllimport) class X {} varX;
  4. class __declspec(dllimport) X {};

如果放在class后面,将导出其所有成员函数和静态数据,这种类也被称为“可导出类”。禁止对可导出类的成员显式使用 dllimportdllexport 属性。

二、把dll放入unity

在unity中创建一个Plugins文件夹,所有的外部引用的dll组件必须要放在这个文件下,才能被using。
如果是C#封装的dll,就用 using的方式引用,如果是C++的dll,就DllImport[“”]的方式来添加对dll的引用。
如果是一般的C#程序,需要和exe文件放在同一目录下。

三、在unity中使用C#导入dll

  1. //MyDll.cs
  2. using System.Runtime.InteropServices;
  3. public static class MyDll
  4. {
  5. [DllImport("MyDll")]
  6. public static extern int MyAdd(int x, int y);
  7. }

原理

P/Invoke是平台调用服务(Platform Invocation Services)的简称。在C#中,可以使用extern关键字和DllImport特性将上述函数声明为一个同名的静态方法,即可在程序中直接调用。CLR包含了一个封送器(marshaler),它可以将参数和返回值在.NET类型和非托管类型间进行转换。
在上述例子中,就通过DllImport属性、extern关键字,定义了C++的dll文件中的同名静态方法,已经能够在其他位置调用了。此函数的参数类型很简单,可以直接使用。
如果dll中的参数类型是结构体、回调函数,还需要在C#中进行相应的定义。
结构体举例
C++原型:
image.png
image.png
C#定义:
image.png
image.png
StructLayout特性可以定义封送器的数据映射(如何将结构字段映射到非托管类型的相应部分上)方式。其中Layout.Sequential会将每一个字段按照声明顺序对齐到包尺寸(pack-size)的边界上。
回调函数举例
P/Invoke层可以将非托管函数指针映射为C#的委托(C#中和函数指针最接近的结构)。
C++原型:
image.png
image.png
C#定义:
image.png

四、在unity中使用C#调用dll中符号

  1. // MyTest.cs
  2. void Start ()
  3. {
  4. var x = MyDll.MyAdd(1, 2);
  5. Debug.Log(x);
  6. }

这个就比较简单了