关于在Unity3D中使用C++ DLL库的记录

 

啊,long time no see...大概又是很久没有更新博客了。好消息是我今天正式收到了转正邮件了。

最近get到了一个新技能,就是在U3D中调我们自己写的C++的库。之前也有用到过,但都是导师来接好了,没有自己研究过。现将内容记录如下。

1. 关于Unity中导入外部库,在PC端和安卓端

pc端使用的是C++  test.dll, 安卓端使用的是 libtest.so. 其中安卓端的库是以lib开头,在Unity脚本中不需要单独处理。

文件组织:

—Plugins

——Android

————libtest.so

——test.dll

2.接库

  • 需要在脚本中包含 using System.Runtime.InteropServices
  • 使用如下命令来指定下面的函数是来自外部库的

 [DllImport("test")]
 static extern int Creat(IntPtr hMemMgr, ref IntPtr phEngine);

3.C++ 和 C#之间的数据类型对应以传输数据方式

C++和C#的类型对应,很多文章都有,这里就不赘述整理,只将比较困扰我自己的部分记录下来。

  • C++ 中的void* 类型(一般咱们用来作handle,engine),在C#中是用IntPtr

如,C++端定义了一个空指针

void* handle = null; 

在C# 中使用IntPtr.Zero对应

IntPtr handle = IntPtr.Zero;
  • C++中的包含指针的结构体,在C#中的定义

如,C++端有如下结构体A

struct A
{
    unsigned int num;
    float* points;
    int* states;
}
  • 在C#端要如何定义并且传输到C++端呢?

这里主要用到Marshal.AllocHGlobal为指针分配内存,和Marshal.FreeHGlobal()释放

DANGDANGDANG...

struct A
{
    public UInt32 num;
    public IntPtr points;
    public IntPtr states;

//对IntPtr指针分配内存,即初始化A结构体
    public  Init(int num)
    {
        points = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(float)) * num);
        states = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)) * num); 
    }
//分配了内存,需要释放
    public void Release()
    {
        Marshal.FreeHGlobal(points);
        Marshal.FreeHGlobal(states);
    }
}

 定义好了C#端的结构体后,就可以为这个指针所指向的内存赋值,并将这个A结构体对象传到C++的函数中。

主要是对给指针分配的这块内存进行划分,另起一个指针,不断的对这块内存赋值,并移动一定的位置,主要用到的是

Marshal.StructureToPtr()函数

A a;
a.Init();

long longptr = a.points.ToInt64();
long longptr1 = a.states.ToInt64();

for(int i = 0; i < num; ++i)
{
   IntPtr temp1 = new IntPtr(longptr);
   IntPtr temp2 = new IntPtr(longptr1);

   Marshal.StructureToPtr(1.0f, temp1, false);
   longptr += Marshal.SizeOf(typeof(float));
   Marshal.StructureToPtr(1, temp2, false);
   longptr1 += Marshal.SizeOf(typeof(int));
}

//传入外部函数
SetPoints(ref a);

a.Release();
  • 获取从C++端的数据到C#的结构体中

其实整体和上面差不多,不过这里分享一下对于比较复杂的结构体,比如一个结构体内还包含了另一个结构体

C++中有结构体A,A的定义如上

struct B
{
    unsigned int num;
    A* points;
}

C#中的定义:

public struct B
{
    public UInt32 num;
    public IntPtr pointslist;

    public void Init(int num)
    {
        pointslist = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(A)) * num);
        num = (UInt32)num;
    }

    public void Release()
    {
        Marshal.FreeHGlobal(pointslist);
    }
}

在C#中获取C++传来的B, 主要用到的就是下面这个方法去将unmanaged数据,转换成C#中的结构体,下面这个方法亲测有效。

核心是Marshal.PtrToStructure()

public static void MarshalUnmananagedArray2Struct(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{
    var size = Marshal.SizeOf(typeof(T));
    mangagedArray = new T[length];

    for (int i = 0; i < length; i++)
    {
       IntPtr ins = new IntPtr(unmanagedArray.ToInt64() + i * size);
       mangagedArray[i] = (T)Marshal.PtrToStructure(ins,typeof(T));
    }
}

使用方法如下: 

A[] alist;
B b;
b.Init(num);

//C++中的方法
GetB(ref b);
        
MarshalUnmananagedArray2Struct(b.pointslist, (int)b.num, out alist);

b.Release();

主要的内容就是这样啦~记录完毕...

你可能感兴趣的:(Unity3D开启新世界的大门)