Unity 之 使用HybridCLR热更新 中 MonoPInvokeCallback 使用 string 参数导致的问题及解决方案
ExecutionEngineException: GetReversePInvokeWrapper fail. not find wrapper of method:System.IntPtr VideoScreen::CallBackTest(System.IntPtr)
HybridCLR 中 [MonoPInvokeCallback] 使用 string 参数导致的问题及解决方案
问题描述
运行报错:ExecutionEngineException: GetReversePInvokeWrapper fail. not find wrapper of method:System.IntPtr VideoScreen::CallBackTest(System.IntPtr)
在 Unity 项目中使用 HybridCLR 进行热更新时,若定义如下委托和回调方法:
public delegate string UnityCallBack(string s);
[MonoPInvokeCallback(typeof(UnityCallBack))]
public static string CallBackTest(string s)
{
Debug.Log("debug:" + s);
s += " Csharp";
return s;
}
可能会遇到以下两类错误:
-
编辑器构建时错误
MonoPInvokeCallback method System.String VideoScreen::CallBackTest(System.String) has unsupported parameter or return type. -
运行时错误(若构建绕过编辑器检查)
ExecutionEngineException: GetReversePInvokeWrapper fail. not find wrapper of method:System.String VideoScreen::CallBackTest(System.String)
即使按照建议将签名改为 IntPtr 后,仍可能遇到:
ExecutionEngineException: GetReversePInvokeWrapper fail. not find wrapper of method:System.IntPtr VideoScreen::CallBackTest(System.IntPtr)
根本原因
- HybridCLR 的限制:对于标记了
[MonoPInvokeCallback]的方法(反向 P/Invoke),不支持需要封送(marshaling)的托管类型,如string、数组、类等。这些类型在 native 代码调用时,无法自动生成正确的包装器(wrapper)。 - 包装器缺失:即使改为
IntPtr,若 HybridCLR 未正确为该方法生成反向 P/Invoke 包装器,运行时仍会找不到对应入口。
解决方案
1. 修改委托和方法签名
将委托和所有标记 [MonoPInvokeCallback] 的方法的参数和返回值改为 IntPtr。
修改前:
public delegate string UnityCallBack(string s);
[MonoPInvokeCallback(typeof(UnityCallBack))]
public static string CallBackTest(string s) { ... }
修改后:
using System;
using System.Runtime.InteropServices;
using AOT;
public delegate IntPtr UnityCallBack(IntPtr s);
[MonoPInvokeCallback(typeof(UnityCallBack))]
public static IntPtr CallBackTest(IntPtr s)
{
// 1. 将 native 字符串转为 C# string(假设 UTF-8 编码)
string input = Marshal.PtrToStringUTF8(s);
Debug.Log("debug:" + input);
// 2. 业务处理
string output = input + " Csharp";
// 3. 将结果 string 转为 IntPtr(分配非托管内存)
IntPtr result = Marshal.StringToCoTaskMemUTF8(output);
return result;
}
2. 重要注意事项
- 内存管理:C# 侧通过
Marshal.StringToCoTaskMemUTF8分配的内存,必须由 native 调用方负责释放(例如调用CoTaskMemFree)。若 native 端无法修改,需约定其他内存管理方式(如使用Marshal.AllocHGlobal配合FreeHGlobal)。 - 委托类型匹配:
[MonoPInvokeCallback]中指定的委托类型必须与方法签名完全一致。
3. 重新生成反向 P/Invoke 包装器
修改签名后,必须手动触发 HybridCLR 的包装器生成:
- 菜单栏:HybridCLR → Generate → ReversePInvokeWrapper(或 Generate All)。
生成成功后,检查输出目录(通常为 HybridCLRData/ReversePInvokeWrapper/)是否包含你的方法。
4. 清理旧构建缓存
旧的缓存可能导致新包装器未被使用,建议执行一次 Clean Build:
- Build Settings → 点击 Build 旁的下拉箭头 → 选择 Clean Build。
- 或手动删除
Library/Bee、Library/PlayerDataCache、Library/il2cpp_cache目录后重新构建。
5. 验证热更新程序集配置
确保你的热更新程序集已被 HybridCLR 的包装器生成器扫描到:
- 打开 HybridCLR → Settings → ReversePInvokeWrapper 选项卡,确认你的程序集已勾选。
- 若未出现,可尝试重新导入程序集或检查程序集定义文件(Assembly Definition)的设置。
常见后续问题排查
问题:修改为 IntPtr 后仍然报 GetReversePInvokeWrapper fail
可能原因及解决步骤:
-
委托定义与签名不一致
检查委托是否更新为IntPtr,且[MonoPInvokeCallback(typeof(YourDelegate))]正确引用。 -
包装器未生成
重复执行步骤 3,并查看生成日志是否包含你的方法名。 -
热更新程序集未被扫描
确认程序集在 HybridCLR 设置中启用,或临时将方法移到 AOT 主工程测试(若移动后正常,则问题在热更新侧配置)。 -
缓存干扰
执行步骤 4 的 Clean Build,或删除整个Library目录后重新导入项目(谨慎操作)。
总结
- HybridCLR 的
[MonoPInvokeCallback]不支持string等托管类型,必须使用IntPtr并手动转换字符串。 - 修改签名后,务必重新生成反向 P/Invoke 包装器并清理缓存。
- 注意内存管理约定,避免泄漏。
更多推荐

所有评论(0)