啊,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.接库
[DllImport("test")]
static extern int Creat(IntPtr hMemMgr, ref IntPtr phEngine);
3.C++ 和 C#之间的数据类型对应以传输数据方式
C++和C#的类型对应,很多文章都有,这里就不赘述整理,只将比较困扰我自己的部分记录下来。
如,C++端定义了一个空指针
void* handle = null;
在C# 中使用IntPtr.Zero对应
IntPtr handle = IntPtr.Zero;
如,C++端有如下结构体A
struct A
{
unsigned int num;
float* points;
int* states;
}
这里主要用到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++中有结构体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();
主要的内容就是这样啦~记录完毕...