当前位置: 首页>编程语言>正文

ios 频繁调用unity unity调用32位dll报错怎么办

很多时候我们都会用到第三方C++的DLL,但是我们并不知道其中的原理和过程,考虑到以后需要用C++封装一些通用的接口,就花时间学习一下在unity中调用C++的接口。

在VS中就可以编译DLL,只是要注意unity系统版本。

编译安卓的.so,可以参考:使用eclipse编译.so动态链接库

三种参数类型:

1.值类型

2.引用类型

3.指针类型

4.函数类型

关于4函数类型:

C++:
//定义函数指针;
typedef void(__stdcall *CPPCallback)(int x, int y, int len);
// 定义接口
extern “C” void _DLLExport SetCallback(CPPCallback callback);
c#:
public delegate void CSCallback(int x, int y, int len);
[DllImport(“TestDLL”)]
private static extern void SetCallback(CSCallback callback);
tips:
unity运行提示找不到DLL,可能是放的目录不对,也可能是DLL编译的平台不对。
细节都在代码中:
C++部分:
TestDll.h
#ifdef TESTDLL_EXPORTS
// 将带有_DLLExport的函数声明为C语言方式的DLL导出函数,忽略重载机制
#define TESTDLL_API extern "C" __declspec(dllexport)
#else
#define TESTDLL_API extern "C"
#endif
TESTDLL_API int FunTest();
typedef struct
{
char name[128];
}TestInfoChild;
typedef struct
{
public:
int x;
int y;
char name[128];
TestInfoChild child;
}TestInfo;
// 通过传递【结构体引用】传递
TESTDLL_API bool GetInfoRef(TestInfo &info);
// 通过传递【结构体指针】传递(在C#端有两种写法)
TESTDLL_API bool GetInfoPtr(TestInfo *info);
// 传递【结构体数组】(在C#只能通过指针传递)
TESTDLL_API bool GetInfoArray(TestInfo *info, int iLen);
TestDll.cpp
#include "stdafx.h"
#include "TestDll.h"
#include 
using namespace std;
int FunTest()
{
return 6666;
}
bool GetInfoPtr(TestInfo *info)
{
info->x = 6;
info->y = 8;
strcpy(info->name, "hello_ptr");
return true;
}
bool GetInfoRef(TestInfo &info)
{
info.x = 12;
info.y = 16;
strcpy(info.name, "hello_ref");
return true;
}
bool GetInfoArray(TestInfo *info, int iLen)
{
for (int i = 0; i < iLen; i ++)
{
info[i].x = 11 * (i + 1);
info[i].y = 11 * (i + 1);
// 索引转成字符
char strIndex[4];
itoa(i, strIndex, 16);
// 拼接name
sprintf(info[i].name, "%s%s%s","parent:", "name_", strIndex);
// 子结构体赋值
sprintf(info[i].child.name, "%s%s%s", "child:", "name_", strIndex);
}
return true;
}
c#部分:
using UnityEngine;
using System.Runtime.InteropServices;
using System;
public class TestDll : MonoBehaviour {
[DllImport("TestDll")]
static extern int FunTest();
// 通过【结构体引用】传递参数
[DllImport("TestDll")]
static extern bool GetInfoRef(ref TestInfo info);
// 通过【结构体指针】传递参数的两种写法
[DllImport("TestDll")]
//static extern bool GetInfoPtr(ref TestInfo info); // 写法1:结构体引用(和上面的一样)
static extern bool GetInfoPtr(IntPtr info);         // 写法2:通用指针
// 通过【结构体数组】传递参数
[DllImport("TestDll")]
static extern bool GetInfoArray(IntPtr p, int iLen);
[StructLayout(LayoutKind.Sequential)] // 在内存中按顺序排列,Explicit可通过FieldOffset指定位置
public struct TestInfoChild
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string name;
}
[StructLayout(LayoutKind.Sequential)] // 在内存中按顺序排列,Explicit可通过FieldOffset指定位置
public struct TestInfo
{
public int x;
public int y;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public TestInfoChild child;
}
void Start () {
int data = FunTest();
Debug.Log("普通方法测试:" + data);
TestStruct();
TestArray();
}
private void TestStruct()
{
Debug.Log("引用的方式获取值=====================================");
TestInfo info = new TestInfo();
GetInfoRef(ref info);
Debug.Log("x:" + info.x);
Debug.Log("y:" + info.y);
Debug.Log("name:" + info.name);
Debug.Log("指针的方式获取值=====================================");
// 指针参数写法1,结构体引用
//TestInfo info = new TestInfo();  // 初始化结构体
//GetInfoPtr(ref info);
//Debug.Log("ptr:x:" + info.x);
//Debug.Log("ptr:y:" + info.y);
//Debug.Log("ptr:name:" + info.name);
// 指针参数写法2,通过平台通用指针(使用类似C的malloc, free,分配堆内存)
int totalSize = Marshal.SizeOf(typeof(TestInfo));
IntPtr pt = Marshal.AllocHGlobal(totalSize);
if (GetInfoPtr(pt))
{
// 其实这里这么写就可以直接转化为结构体数据,但是会产生gc
//TestInfo info1 = (TestInfo)Marshal.PtrToStructure((IntPtr)pt.ToInt32(), typeof(TestInfo));
// 下面这么写,就不会产生gc
TestInfo info1;
//ReadInt32 从非托管内存中读取一个 32 位有符号整数
info1.x = Marshal.ReadInt32(pt, 0);
info1.y = Marshal.ReadInt32(pt, 4);
// PtrToStringAnsi 为托管字符串的副本从非托管ANSI第一个空字符开始的所有字符串,可以带长度
// pv.ToInt32() 将此实例的值转换为32位有符号的整数
// 转成整数后,加上前面2个参数所在的字节数8,就可以拿到后面的字符串啦
info1.name = Marshal.PtrToStringAnsi((IntPtr)(8 + pt.ToInt32()));
Debug.Log("x:" + info1.x);
Debug.Log("y:" + info1.y);
Debug.Log("name:" + info1.name);
}
Marshal.FreeHGlobal(pt); // 释放内存
}
private void TestArray()
{
Debug.Log("结构体数组的方式获取值=====================================");
TestInfo[] infos = GetArray(2);
for (int i = 0; i < infos.Length; i++)
{
Debug.Log("x:" + infos[i].x);
Debug.Log("y:" + infos[i].y);
Debug.Log("name:" + infos[i].name);
Debug.Log("child name:" + infos[i].child.name);
}
}
/// 
/// 可根据实际需求封装
/// 
private T[] GetArray(int iLen)
{
int structLen = iLen;
T[] infos = new T[structLen]; // 定义结构体数组数量
int totalSize = Marshal.SizeOf(typeof(TestInfo)) * structLen;
IntPtr pt = Marshal.AllocHGlobal(totalSize);   // 分配totalSize大小的内存,返回指针
if (GetInfoArray(pt, structLen))
{
for(int i = 0; i < structLen; i ++)
{
infos[i] = (T)Marshal.PtrToStructure((IntPtr)(pt.ToInt32() + i * Marshal.SizeOf(typeof(T))), typeof(T));
}
}
Marshal.FreeHGlobal(pt); // 释放内存
return infos;
}
}

输出:

ios 频繁调用unity unity调用32位dll报错怎么办,ios 频繁调用unity unity调用32位dll报错怎么办_API,第1张

作者:木木猫


https://www.xamrdz.com/lan/5wk1960386.html

相关文章: