P/Invode Unity调用C++库
Unity开发中,我们不免要调用C++库,P/Invode(Platform Invocation Services)则为我们提供这个桥梁。
🧠 什么是 P/Invoke?
P/Invoke 全称是:
Platform Invocation Services
它是 .NET/Mono 平台用于从托管代码(如 C#)中调用非托管代码(如 C/C++ DLL)的机制。
🔧 你可以用它做什么?
✅ 从 C# 调用 C/C++ 函数
✅ 调用 Windows API 或 自己写的 .dll
✅ Unity 中调用 OpenCV、CUDA、点云算法等 C++ 模块
✅ 典型 P/Invoke 示例(Unity 或普通 C#)
🎯 假设你有一个 C++ 函数:
native.cpp
xxxxxxxxxx
extern "C" {
__declspec(dllexport) int Add(int a, int b) {
return a + b;
}
}
🔁 C# 侧调用:
xxxxxxxxxx
using System.Runtime.InteropServices;
public class NativeLib
{
[DllImport("YourLibraryName", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
}
注意:
YourLibraryName不要带.dll后缀,Unity 会自动找YourLibraryName.dll
📦 常用属性解释
| 属性 | 示例 | 含义 |
|---|---|---|
DllImport("xxx") |
指定调用的 DLL 名称 | |
CallingConvention |
Cdecl / StdCall / FastCall |
必须匹配 C++ 函数 |
extern |
表示函数定义来自外部 | |
__declspec(dllexport) |
在 C++ 里导出函数 |
🧠 重要规则
| C++ 类型 | C# 类型对应 |
|---|---|
int |
int |
float |
float |
double |
double |
char* |
string 或 IntPtr |
void* |
IntPtr |
struct |
需要用 [StructLayout] 显式映射 |
| C++ 类型 | C# 类型 | 说明 |
|---|---|---|
const char* |
string |
默认 ANSI 字符串 |
const wchar_t* |
string + CharSet.Unicode |
Unicode 字符串 |
char*(可写) |
StringBuilder |
可写缓冲区,用于输出字符串 |
char[] |
byte[] |
传入字节数组(手动处理) |
| C++ 类型 | C# 类型 | 说明 |
|---|---|---|
int* |
IntPtr / ref int |
原始指针 |
float* |
float[] / IntPtr |
数组 |
void* |
IntPtr |
通用指针 |
T*(结构体) |
ref struct / IntPtr |
通常用 ref 或 out |
⚛常用MarshalAs标记
| 用法 | 说明 |
|---|---|
LPStr |
C 的 char* |
LPWStr |
宽字符 wchar_t* |
I1 |
bool 映射为 1 字节 |
ByValArray |
结构体中数组固定大小 |
| ⚠️std::string 没有对应的C#, 因此C++ 端需要将其先选换成如char* 类型 |
✅ 总结推荐使用
| 场景 | 推荐写法 |
|---|---|
| 数值、float、int | 直接用 C# 对应类型 |
| 字符串传入 | string + MarshalAs |
| 可写字符串 | StringBuilder |
| 结构体传值 | [StructLayout] + ref |
| 指针 | IntPtr / unsafe 指针 |
| C 数组传入 | T[] / IntPtr + Marshal.Copy |
⚠️ 注意事项
| 问题 | 原因 | 解决方式 |
|---|---|---|
| 找不到 DLL | 路径或平台不一致 | 放到 Assets/Plugins/x86_64/ 下 |
| 类型不匹配 | 参数/返回值定义不一致 | 确保函数签名匹配 |
| 字符串乱码 | 编码不同 | 用 Encoding.UTF8 编解码或 IntPtr 传值 |
🧪 实战例子(带字符串)
C++ 侧:
xxxxxxxxxx
extern "C" {
__declspec(dllexport) void Hello(const char* name)
{
printf("Hello %s\\n", name);
}
}
C# 侧:
xxxxxxxxxx
[DllImport("NativeLib", CallingConvention = CallingConvention.Cdecl)]
public static extern void Hello([MarshalAs(UnmanagedType.LPStr)] string name);
🧪 实战例子(结构体)
C++侧:
xxxxxxxxxx
extern "C" MYDLL_API float pixelToLength(const myPointf topPoint, const myPointf lowerPoint);
C#侧
xxxxxxxxxx
[StructLayout(LayoutKind.Sequential)]
public struct myPointf
{
public float x;
public float y;
}
[DllImport("YourDllName", CallingConvention = CallingConvention.Cdecl)]
public static extern float pixelToLength(myPointf topPoint, myPointf lowerPoint);
myPointf top = new myPointf { x = 100.5f, y = 200.0f };
myPointf bottom = new myPointf { x = 100.5f, y = 500.0f };
float length = pixelToLength(top, bottom);
Debug.Log($"像素点距离 = {length}");
方便的工具
Dependencies GUI
确认依赖项是否缺失(依赖链未加载)
举例:你的 mydll.dll 引用了 opencv_world.dll,但你没把它一并放进去 → 也会报找不到 mydll
✅ 用工具查看依赖链:
- 👉 推荐工具:Dependencies GUI(查看 DLL 依赖)
- ✅ 确保所有依赖都在同目录或系统 PATH 可访问
ClangSharp P/Invoke Generator(微软官方)
支持从
.h头文件自动生成 C# P/Invoke 绑定,精度高、现代、安全
- ✅ 微软官方维护,基于 LLVM Clang
- ✅ 支持复杂结构体、指针、函数导出
- ✅ 可配置输出为 C# 代码、生成整套接口
- 支持 Windows、Linux、macOS
- 推荐用于企业级封装
SWIG(Simplified Wrapper and Interface Generator)**
支持将 C/C++ 接口导出为多种语言绑定,包括 C#
- ✅ 支持类、指针、继承、模板
- ✅ 自动生成
.cs和.dll封装 - ❗生成代码有学习曲线,适合复杂接口工程
📌 总结一句话:
P/Invoke 是 C# / Unity 调用本地 C/C++ 函数的桥梁,掌握它可以让你把 C++ 算法库“无缝”接入到 C# 项目中。
作者:世纪末的魔术师
出处:https://www.cnblogs.com/Firepad-magic/
Unity最受欢迎插件推荐:点击查看
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号