Unity 之 C#与C++/C交互指针函数指针结构体交互
1、打开Visual Studio ,新建一个工程,选择 Visual C++ 下的 Windows 桌面 下的 动态链接库(DLL),新建成工程项目,具体如下图

2、在生成的 NativeCode.h 文件中,添加要供 C# 调用的接口声明定义,具体如下图

3、NativeCode.h 的具体内容如下:
#ifndef __NativeCode_H__
#define __NativeCode_H__
#ifndef EXPORT_DLL
#define EXPORT_DLL __declspec(dllexport) //导出dll声明
#endif
struct Vector3
{
float x, y, z;
};
struct Vector8
{
int counter;
float x, y, z;
float a, b, c, d;
};
//定义一个函数指针
typedef void(__stdcall *CPPCallback)(Vector8 v8);
extern "C" {
EXPORT_DLL void MyAddFunc(int* _a, int* _b);
EXPORT_DLL void MySubFunc(int* _a);
EXPORT_DLL Vector3 MyVectorFunc(Vector3 vector3);
EXPORT_DLL Vector8 MyVector8Func();
//定义一个用于设置函数指针的方法,在该函数中调用C#中传递过来的委托
EXPORT_DLL void __stdcall SetCallback(CPPCallback callback);
EXPORT_DLL void MyTestCallbackFunc();
}
#endif
4、新建一个脚本 NativaCode.cpp ,实现之前定义的接口,包括 C++与C#之间的指针交互,函数指针交互,结构体交互的接口函数,具体如下图

5、NativaCode.cpp 的具体内容如下:
// NaviteCode.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "NaviteCode.h"
int* tmp;
CPPCallback callbackFunc;
extern "C" {
void MyAddFunc(int* _a, int* _b)
{
*_a = *_a + *_b;
tmp = _b;
}
void MySubFunc(int* _a) {
*_a = *_a - *tmp;
}
Vector3 MyVectorFunc(Vector3 vector3) {
Vector3 v = vector3;
v.x += 1;
v.y += 2;
v.z += 3;
return v;
}
Vector8 MyVector8Func() {
Vector8 v8 ={7,1,2,3,4,5,6,7};
return v8;
}
void __stdcall SetCallback(CPPCallback callback)
{
Vector8 v8 = { 7,1.1,2.2,3.3,4.4,5.5,6.6,7.7 };
//下面的代码是对C#中委托进行调用
callback(v8);
callbackFunc = callback;
}
void MyTestCallbackFunc() {
Vector8 v8 = { 7,11.1,22.2,33.3,44.4,55.5,66.6,77.7 };
callbackFunc(v8);
}
}
6、脚本没有错误,选中工程,右键-生成,把应用编译打包出 dll,没有失败的话,就会在目标路径生成出 dll,具体如下图


7、打开Unity,然后新建一个工程,然后在工程中,新建一个 Plugins,把之前生成的 dll 拖入进去,具体如下图


8、然后在工程中新建一个脚本 TestDLL ,引进DLL的接口函数,并与之对应构建需要的结构体(如果Unity与之对应的结构体,可使用Unity自带的),设置委托回调函数,接着对应的尝试调用的接口,并打印,便于后期查看结果,具体如下图



9、 TestDLL 脚本的具体内容如下:
using System.Runtime.InteropServices;
using UnityEngine;
[StructLayout(LayoutKind.Sequential)]
public struct Vector8
{
public int count;
public float x, y, z;
public float a, b, c, d;
}
public class TestDLL : MonoBehaviour
{
public delegate void CSCallback(Vector8 v8);
static void CSCallbackFunction(Vector8 v8)
{
Debug.Log("Vector8 v8: " + v8.count + " " + v8.x + " " + v8.y + " "
+ v8.z + " " + v8.a + " " + v8.b + " " + v8.c + " " + v8.d);
}
[DllImport("NaviteCode")]
public static extern void MyAddFunc(ref int a, ref int b);
[DllImport("NaviteCode")]
public static extern void MySubFunc(ref int a);
[DllImport("NaviteCode")]
public static extern Vector3 MyVectorFunc(Vector3 v);
[DllImport("NaviteCode")]
public static extern Vector8 MyVector8Func();
[DllImport("NaviteCode")]
public static extern void MyTestCallbackFunc();
[DllImport("NaviteCode")]
public static extern void SetCallback(CSCallback cSCallback);
// Start is called before the first frame update
void Start()
{
int a =10;
int b = 5;
MyAddFunc(ref a, ref b);
Debug.Log("a :"+a);
int c = 20;
MySubFunc(ref c);
Debug.Log("c :" + c);
Vector3 v = MyVectorFunc(new Vector3(1,2,3));
Debug.Log("Vector3 v :" + v);
Vector8 v8 = new Vector8();
v8 = MyVector8Func();
Debug.Log("Vector8 v8: " + v8.count + " " + v8.a);
SetCallback(CSCallbackFunction);
MyTestCallbackFunc();
}
}
10、脚本没有问题,回到Unity,场景中添加一个GameObject,并把脚本挂载上去,具体如下图

11、运行场景,即可看到,正常调用 C++封装的 DLL的接口,并且打印也符合预期,具体如下图
